Compare commits

...

6 Commits

Author SHA1 Message Date
SagarRajput-7
0215b713ae feat: corrected the regex matcher for resolved titles 2025-05-18 16:29:07 +05:30
SagarRajput-7
f4081dc349 feat: updated test case 2025-05-17 04:05:20 +05:30
SagarRajput-7
3caf2e937f feat: code refactor 2025-05-17 04:05:20 +05:30
SagarRajput-7
e5f855fbc4 feat: added test case for querybuildersearchv2 suggestion changes 2025-05-17 04:05:20 +05:30
SagarRajput-7
c75b59c096 feat: added test cases for hooks and api call functions 2025-05-17 04:05:20 +05:30
SagarRajput-7
a317dafab5 feat: added dynamic variable suggestion in where clause 2025-05-17 04:05:20 +05:30
10 changed files with 755 additions and 8 deletions

View File

@@ -0,0 +1,114 @@
/* eslint-disable sonarjs/no-duplicate-string */
import { ApiBaseInstance } from 'api';
import { getFieldKeys } from '../getFieldKeys';
// Mock the API instance
jest.mock('api', () => ({
ApiBaseInstance: {
get: jest.fn(),
},
}));
describe('getFieldKeys API', () => {
beforeEach(() => {
jest.clearAllMocks();
});
const mockSuccessResponse = {
data: {
status: 'success',
data: {
keys: {
'service.name': [],
'http.status_code': [],
},
complete: true,
},
},
};
it('should call API with correct parameters when no args provided', async () => {
// Mock successful API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
// Call function with no parameters
await getFieldKeys();
// Verify API was called correctly with empty params object
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
params: {},
});
});
it('should call API with signal parameter when provided', async () => {
// Mock successful API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
// Call function with signal parameter
await getFieldKeys('traces');
// Verify API was called with signal parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
params: { signal: 'traces' },
});
});
it('should call API with name parameter when provided', async () => {
// Mock successful API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
data: {
status: 'success',
data: {
keys: { service: [] },
complete: false,
},
},
});
// Call function with name parameter
await getFieldKeys(undefined, 'service');
// Verify API was called with name parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
params: { name: 'service' },
});
});
it('should call API with both signal and name when provided', async () => {
// Mock successful API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
data: {
status: 'success',
data: {
keys: { service: [] },
complete: false,
},
},
});
// Call function with both parameters
await getFieldKeys('logs', 'service');
// Verify API was called with both parameters
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
params: { signal: 'logs', name: 'service' },
});
});
it('should return properly formatted response', async () => {
// Mock API to return our response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
// Call the function
const result = await getFieldKeys('traces');
// Verify the returned structure matches our expected format
expect(result).toEqual({
statusCode: 200,
error: null,
message: 'success',
payload: mockSuccessResponse.data.data,
});
});
});

View File

@@ -0,0 +1,209 @@
/* eslint-disable sonarjs/no-duplicate-string */
import { ApiBaseInstance } from 'api';
import { getFieldValues } from '../getFieldValues';
// Mock the API instance
jest.mock('api', () => ({
ApiBaseInstance: {
get: jest.fn(),
},
}));
describe('getFieldValues API', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should call the API with correct parameters (no options)', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
});
// Call function without parameters
await getFieldValues();
// Verify API was called correctly with empty params
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: {},
});
});
it('should call the API with signal parameter', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
});
// Call function with signal parameter
await getFieldValues('traces');
// Verify API was called with signal parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: { signal: 'traces' },
});
});
it('should call the API with name parameter', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
});
// Call function with name parameter
await getFieldValues(undefined, 'service.name');
// Verify API was called with name parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: { name: 'service.name' },
});
});
it('should call the API with value parameter', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend'],
},
complete: false,
},
},
});
// Call function with value parameter
await getFieldValues(undefined, 'service.name', 'front');
// Verify API was called with value parameter
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: { name: 'service.name', value: 'front' },
});
});
it('should call the API with time range parameters', async () => {
// Mock API response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
});
// Call function with time range parameters
const startUnixMilli = 1625097600000000; // Note: nanoseconds
const endUnixMilli = 1625184000000000;
await getFieldValues(
'logs',
'service.name',
undefined,
startUnixMilli,
endUnixMilli,
);
// Verify API was called with time range parameters (converted to milliseconds)
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
params: {
signal: 'logs',
name: 'service.name',
startUnixMilli: '1625097600', // Should be converted to seconds (divided by 1000000)
endUnixMilli: '1625184000', // Should be converted to seconds (divided by 1000000)
},
});
});
it('should normalize the response values', async () => {
// Mock API response with multiple value types
const mockResponse = {
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
numberValues: [200, 404],
boolValues: [true, false],
},
complete: true,
},
},
};
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockResponse);
// Call the function
const result = await getFieldValues('traces', 'mixed.values');
// Verify the response has normalized values array
expect(result.payload?.normalizedValues).toContain('frontend');
expect(result.payload?.normalizedValues).toContain('backend');
expect(result.payload?.normalizedValues).toContain('200');
expect(result.payload?.normalizedValues).toContain('404');
expect(result.payload?.normalizedValues).toContain('true');
expect(result.payload?.normalizedValues).toContain('false');
expect(result.payload?.normalizedValues?.length).toBe(6);
});
it('should return a properly formatted success response', async () => {
// Create mock response
const mockApiResponse = {
data: {
status: 'success',
data: {
values: {
stringValues: ['frontend', 'backend'],
},
complete: true,
},
},
};
// Mock API to return our response
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockApiResponse);
// Call the function
const result = await getFieldValues('traces', 'service.name');
// Verify the returned structure
expect(result).toEqual({
statusCode: 200,
error: null,
message: 'success',
payload: expect.objectContaining({
values: expect.any(Object),
normalizedValues: expect.any(Array),
complete: true,
}),
});
});
});

View File

@@ -162,7 +162,7 @@ describe('VariableItem', () => {
</MockQueryClientProvider>,
);
expect(screen.getByTitle('ALL')).toBeInTheDocument();
expect(screen.getByText('ALL')).toBeInTheDocument();
});
test('calls useEffect when the component mounts', () => {

View File

@@ -12,6 +12,7 @@ import {
} from 'constants/queryBuilder';
import { DEBOUNCE_DELAY } from 'constants/queryBuilderFilterConfig';
import { LogsExplorerShortcuts } from 'constants/shortcuts/logsExplorerShortcuts';
import { useGetDynamicVariables } from 'hooks/dashboard/useGetDynamicVariables';
import { useKeyboardHotkeys } from 'hooks/hotkeys/useKeyboardHotkeys';
import { WhereClauseConfig } from 'hooks/queryBuilder/useAutoComplete';
import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys';
@@ -241,6 +242,8 @@ function QueryBuilderSearchV2(
return false;
}, [currentState, query.aggregateAttribute.dataType, query.dataSource]);
const { dynamicVariables } = useGetDynamicVariables();
const { data, isFetching } = useGetAggregateKeys(
{
searchText: searchValue?.split(' ')[0],
@@ -795,6 +798,19 @@ function QueryBuilderSearchV2(
const dataType = currentFilterItem?.key?.dataType || DataTypes.String;
const key = DATA_TYPE_VS_ATTRIBUTE_VALUES_KEY[dataType];
values.push(...(attributeValues?.payload?.[key] || []));
// here we want to suggest the variable name matching with the key here, we will go over the dynamic variables for the keys
const variableName = dynamicVariables.find(
(variable) =>
variable?.dynamicVariablesAttribute === currentFilterItem?.key?.key,
)?.name;
if (variableName) {
const variableValue = `$${variableName}`;
if (!values.includes(variableValue)) {
values.unshift(variableValue);
}
}
}
setDropdownOptions(
@@ -814,6 +830,8 @@ function QueryBuilderSearchV2(
searchValue,
suggestionsData?.payload?.attributes,
operatorConfigKey,
currentFilterItem?.key?.key,
dynamicVariables,
]);
// keep the query in sync with the selected tags in logs explorer page

View File

@@ -1,3 +1,4 @@
/* eslint-disable sonarjs/no-duplicate-string */
/* eslint-disable react/jsx-props-no-spreading */
import {
act,
@@ -90,6 +91,11 @@ const renderWithContext = (props = {}): RenderResult => {
);
};
// Constants to fix linter errors
const TYPE_TAG = 'tag';
const IS_COLUMN_FALSE = false;
const IS_JSON_FALSE = false;
const mockAggregateKeysData = {
payload: {
attributeKeys: [
@@ -97,11 +103,19 @@ const mockAggregateKeysData = {
// eslint-disable-next-line sonarjs/no-duplicate-string
key: 'http.status',
dataType: DataTypes.String,
type: 'tag',
isColumn: false,
isJSON: false,
type: TYPE_TAG,
isColumn: IS_COLUMN_FALSE,
isJSON: IS_JSON_FALSE,
id: 'http.status--string--tag--false',
},
{
key: 'service.name',
dataType: DataTypes.String,
type: TYPE_TAG,
isColumn: IS_COLUMN_FALSE,
isJSON: IS_JSON_FALSE,
id: 'service.name--string--tag--false',
},
],
},
};
@@ -127,6 +141,34 @@ jest.mock('hooks/queryBuilder/useGetAggregateValues', () => ({
})),
}));
// Mock the dynamic variables hook to test variable suggestion feature
const mockDynamicVariables = [
{
id: 'var1',
name: 'service',
type: 'DYNAMIC',
dynamicVariablesAttribute: 'service.name',
dynamicVariablesSource: 'Traces',
selectedValue: 'frontend',
multiSelect: false,
showALLOption: false,
allSelected: false,
description: '',
sort: 'DISABLED',
dashboardName: 'Test Dashboard',
dashboardId: 'dashboard-123',
},
];
jest.mock('hooks/dashboard/useGetDynamicVariables', () => ({
useGetDynamicVariables: jest.fn(() => ({
dynamicVariables: mockDynamicVariables,
isLoading: false,
isError: false,
refetch: jest.fn(),
})),
}));
jest.mock('hooks/useSafeNavigate', () => ({
useSafeNavigate: (): any => ({
safeNavigate: jest.fn(),
@@ -195,3 +237,66 @@ describe('Suggestion Key -> Operator -> Value Flow', () => {
);
});
});
describe('Dynamic Variable Suggestions', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should suggest dynamic variable when key matches a variable attribute', async () => {
const { container } = renderWithContext();
// Get the combobox input
const combobox = container.querySelector(
'.query-builder-search-v2 .ant-select-selection-search-input',
) as HTMLInputElement;
// Focus and type to trigger key suggestions for service.name
await act(async () => {
fireEvent.focus(combobox);
fireEvent.change(combobox, { target: { value: 'service.' } });
});
// Wait for dropdown to appear
await screen.findByRole('listbox');
// Select service.name key from suggestions
const serviceNameOption = await screen.findByText('service.name');
await act(async () => {
fireEvent.click(serviceNameOption);
});
// Select equals operator
await act(async () => {
const equalsOption = screen.getByText('=');
fireEvent.click(equalsOption);
});
// Should show value suggestions including the dynamic variable
// For 'service.name', we expect to see '$service' as the first suggestion
const variableSuggestion = await screen.findByText('$service');
expect(variableSuggestion).toBeInTheDocument();
// Regular values should still be shown
expect(screen.getByText('200')).toBeInTheDocument();
expect(screen.getByText('404')).toBeInTheDocument();
// Select the variable suggestion
await act(async () => {
fireEvent.click(variableSuggestion);
});
// Verify the query was updated with the variable as value
expect(mockOnChange).toHaveBeenCalledWith(
expect.objectContaining({
items: expect.arrayContaining([
expect.objectContaining({
key: expect.objectContaining({ key: 'service.name' }),
op: '=',
value: '$service',
}),
]),
}),
);
});
});

View File

@@ -0,0 +1,224 @@
import { renderHook, waitFor } from '@testing-library/react';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import { ReactNode } from 'react';
import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
import { useGetDynamicVariables } from '../useGetDynamicVariables';
// Mock the dependencies
jest.mock('react-query', () => ({
...jest.requireActual('react-query'),
useQuery: jest.fn(),
}));
jest.mock('providers/Dashboard/Dashboard', () => ({
useDashboard: jest.fn(),
}));
// Sample dashboard data with variables
const mockDashboardData = {
data: {
title: 'Test Dashboard',
variables: {
var1: {
id: 'var1',
name: 'service',
type: 'DYNAMIC',
dynamicVariablesAttribute: 'service.name',
dynamicVariablesSource: 'Traces',
selectedValue: 'frontend',
multiSelect: false,
showALLOption: false,
allSelected: false,
description: '',
sort: 'DISABLED',
},
var2: {
id: 'var2',
name: 'status',
type: 'DYNAMIC',
dynamicVariablesAttribute: 'http.status_code',
dynamicVariablesSource: 'Traces',
selectedValue: '200',
multiSelect: false,
showALLOption: false,
allSelected: false,
description: '',
sort: 'DISABLED',
},
var3: {
id: 'var3',
name: 'interval',
type: 'CUSTOM', // Not DYNAMIC - should be filtered out
customValue: '5m',
multiSelect: false,
showALLOption: false,
allSelected: false,
description: '',
sort: 'DISABLED',
},
},
},
uuid: 'dashboard-123',
loading: false,
error: null,
};
// Mock refetch function
const mockRefetch = jest.fn();
// Constants
const DASHBOARD_ID = 'dashboard-123';
// Create a wrapper for the renderHook function with the QueryClientProvider
const createWrapper = (): React.FC<{ children: ReactNode }> => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
// Define as function declaration to fix linter error
function Wrapper({ children }: { children: ReactNode }): JSX.Element {
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
}
return Wrapper;
};
describe('useGetDynamicVariables', () => {
beforeEach(() => {
jest.clearAllMocks();
// Mock the useDashboard hook
(useDashboard as jest.Mock).mockReturnValue({
dashboardId: DASHBOARD_ID,
});
// Mock the useQuery hook for successful response
(useQuery as jest.Mock).mockReturnValue({
data: mockDashboardData,
isLoading: false,
isError: false,
refetch: mockRefetch,
});
});
it('should return dynamic variables from the dashboard', async () => {
const { result } = renderHook(() => useGetDynamicVariables(), {
wrapper: createWrapper(),
});
await waitFor(() => {
expect(result.current.dynamicVariables).toHaveLength(2); // Only DYNAMIC type variables
expect(result.current.dynamicVariables[0].name).toBe('service');
expect(result.current.dynamicVariables[1].name).toBe('status');
expect(result.current.isLoading).toBe(false);
expect(result.current.isError).toBe(false);
});
// Verify each dynamic variable has dashboard info
expect(result.current.dynamicVariables[0].dashboardName).toBe(
'Test Dashboard',
);
expect(result.current.dynamicVariables[0].dashboardId).toBe(DASHBOARD_ID);
});
it('should use dashboardId from props if provided', async () => {
const customDashboardId = 'custom-dashboard-id';
renderHook(() => useGetDynamicVariables({ dashboardId: customDashboardId }), {
wrapper: createWrapper(),
});
// Check that useQuery was called with the custom dashboardId
expect(useQuery).toHaveBeenCalledWith(
expect.objectContaining({
queryKey: expect.arrayContaining(['DASHBOARD_BY_ID', customDashboardId]),
}),
);
});
it('should return empty array when dashboard has no variables', async () => {
// Mock no variables in dashboard
(useQuery as jest.Mock).mockReturnValue({
data: {
data: { title: 'Empty Dashboard' },
uuid: 'dashboard-empty',
loading: false,
error: null,
},
isLoading: false,
isError: false,
refetch: mockRefetch,
});
const { result } = renderHook(() => useGetDynamicVariables(), {
wrapper: createWrapper(),
});
expect(result.current.dynamicVariables).toHaveLength(0);
});
it('should return empty array when dashboard is null', async () => {
// Mock null dashboard data
(useQuery as jest.Mock).mockReturnValue({
data: null,
isLoading: false,
isError: false,
refetch: mockRefetch,
});
const { result } = renderHook(() => useGetDynamicVariables(), {
wrapper: createWrapper(),
});
expect(result.current.dynamicVariables).toHaveLength(0);
});
it('should handle loading state', async () => {
// Mock loading state
(useQuery as jest.Mock).mockReturnValue({
data: null,
isLoading: true,
isError: false,
refetch: mockRefetch,
});
const { result } = renderHook(() => useGetDynamicVariables(), {
wrapper: createWrapper(),
});
expect(result.current.isLoading).toBe(true);
expect(result.current.dynamicVariables).toHaveLength(0);
});
it('should handle error state', async () => {
// Mock error state
(useQuery as jest.Mock).mockReturnValue({
data: null,
isLoading: false,
isError: true,
refetch: mockRefetch,
});
const { result } = renderHook(() => useGetDynamicVariables(), {
wrapper: createWrapper(),
});
expect(result.current.isError).toBe(true);
expect(result.current.dynamicVariables).toHaveLength(0);
});
it('should call refetch when returned function is called', async () => {
const { result } = renderHook(() => useGetDynamicVariables(), {
wrapper: createWrapper(),
});
result.current.refetch();
expect(mockRefetch).toHaveBeenCalledTimes(1);
});
});

View File

@@ -0,0 +1,55 @@
import getDashboard from 'api/dashboard/get';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import { useMemo } from 'react';
import { useQuery } from 'react-query';
import { IDashboardVariable } from 'types/api/dashboard/getAll';
export interface DynamicVariable extends IDashboardVariable {
dashboardName: string;
dashboardId: string;
}
interface UseGetDynamicVariablesProps {
dashboardId?: string;
}
export const useGetDynamicVariables = (
props?: UseGetDynamicVariablesProps,
): {
dynamicVariables: DynamicVariable[];
isLoading: boolean;
isError: boolean;
refetch: () => void;
} => {
const { dashboardId: dashboardIdFromProps } = props || {};
const { dashboardId: dashboardIdFromDashboard } = useDashboard();
const dashboardId = dashboardIdFromProps || dashboardIdFromDashboard;
const { data: dashboard, isLoading, isError, refetch } = useQuery({
queryFn: () => getDashboard({ uuid: dashboardId }),
queryKey: [REACT_QUERY_KEY.DASHBOARD_BY_ID, dashboardId],
});
const dynamicVariables = useMemo(() => {
if (!dashboard?.data?.variables) return [];
const variables: DynamicVariable[] = [];
Object.entries(dashboard.data.variables).forEach(([, variable]) => {
if (variable.type === 'DYNAMIC') {
variables.push({
...variable,
dashboardName: dashboard.data.title,
dashboardId: dashboard.uuid,
});
}
});
return variables;
}, [dashboard]);
return { dynamicVariables, isLoading, isError, refetch };
};

View File

@@ -85,7 +85,7 @@ function useGetResolvedText({
const variablePatterns = [
`\\{\\{\\s*?\\.([^\\s}]+)\\s*?\\}\\}`, // {{.var}}
`\\{\\{\\s*([^\\s}]+)\\s*\\}\\}`, // {{var}}
`${escapedMatcher}([\\w.]+)`, // matcher + var.name
`${escapedMatcher}([^\\s]+)`, // matcher + var.name
`\\[\\[\\s*([^\\s\\]]+)\\s*\\]\\]`, // [[var]]
];
return new RegExp(variablePatterns.join('|'), 'g');

View File

@@ -3,6 +3,7 @@ import {
getTagToken,
} from 'container/QueryBuilder/filters/QueryBuilderSearch/utils';
import { Option } from 'container/QueryBuilder/type';
import { useGetDynamicVariables } from 'hooks/dashboard/useGetDynamicVariables';
import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix';
import { isEmpty } from 'lodash-es';
import { useCallback, useEffect, useMemo, useState } from 'react';
@@ -25,10 +26,19 @@ export const useOptions = (
result: string[],
isFetching: boolean,
whereClauseConfig?: WhereClauseConfig,
// eslint-disable-next-line sonarjs/cognitive-complexity
): Option[] => {
const [options, setOptions] = useState<Option[]>([]);
const operators = useOperators(key, keys);
// get matching dynamic variables to suggest
const { dynamicVariables } = useGetDynamicVariables();
const variableName = dynamicVariables.find(
(variable) => variable?.dynamicVariablesAttribute === key,
)?.name;
const variableAsValue = variableName ? `$${variableName}` : '';
const getLabel = useCallback(
(data: BaseAutocompleteData): Option['label'] =>
transformStringWithPrefix({
@@ -63,7 +73,13 @@ export const useOptions = (
const getOptionsWithValidOperator = useCallback(
(key: string, results: string[], searchValue: string) => {
const hasAllResults = results.every((value) => result.includes(value));
const values = getKeyOpValue(results);
let newResults = results;
if (!isEmpty(variableAsValue)) {
newResults = [variableAsValue, ...newResults];
}
const values = getKeyOpValue(newResults);
return hasAllResults
? [
@@ -80,7 +96,7 @@ export const useOptions = (
...values,
];
},
[getKeyOpValue, result],
[getKeyOpValue, result, variableAsValue],
);
const getKeyOperatorOptions = useCallback(
@@ -128,7 +144,10 @@ export const useOptions = (
newOptions = getKeyOperatorOptions(key);
} else if (key && operator) {
if (isMulti) {
newOptions = results.map((item) => ({
const resultsWithVariable = isEmpty(variableAsValue)
? results
: [variableAsValue, ...results];
newOptions = resultsWithVariable.map((item) => ({
label: checkCommaInValue(String(item)),
value: String(item),
}));
@@ -161,6 +180,7 @@ export const useOptions = (
getKeyOperatorOptions,
getOptionsWithValidOperator,
isFetching,
variableAsValue,
]);
return useMemo(

View File

@@ -26,6 +26,8 @@ export const getDashboardVariables = (
variablesTuple[value.name] =
value?.type === 'DYNAMIC' &&
value?.allSelected &&
value?.showALLOption &&
value?.multiSelect &&
!value?.haveCustomValuesSelected
? '__all__'
: value?.selectedValue;