diff --git a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearchV2/QueryBuilderSearchV2.tsx b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearchV2/QueryBuilderSearchV2.tsx index 2505e70eb7ab..d78ca566a438 100644 --- a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearchV2/QueryBuilderSearchV2.tsx +++ b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearchV2/QueryBuilderSearchV2.tsx @@ -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'; @@ -246,6 +247,8 @@ function QueryBuilderSearchV2( return false; }, [currentState, query.aggregateAttribute?.dataType, query.dataSource]); + const { dynamicVariables } = useGetDynamicVariables(); + const { data, isFetching } = useGetAggregateKeys( { searchText: searchValue?.split(' ')[0], @@ -800,6 +803,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( @@ -819,6 +835,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 diff --git a/frontend/src/hooks/dashboard/useGetDynamicVariables.tsx b/frontend/src/hooks/dashboard/useGetDynamicVariables.tsx new file mode 100644 index 000000000000..596e6aa35147 --- /dev/null +++ b/frontend/src/hooks/dashboard/useGetDynamicVariables.tsx @@ -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 }; +}; diff --git a/frontend/src/hooks/queryBuilder/useOptions.ts b/frontend/src/hooks/queryBuilder/useOptions.ts index e990f789dee7..11022a32ba7d 100644 --- a/frontend/src/hooks/queryBuilder/useOptions.ts +++ b/frontend/src/hooks/queryBuilder/useOptions.ts @@ -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([]); 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,6 +73,11 @@ export const useOptions = ( const getOptionsWithValidOperator = useCallback( (key: string, results: string[], searchValue: string) => { const hasAllResults = results.every((value) => result.includes(value)); + + if (!isEmpty(variableAsValue)) { + results.unshift(variableAsValue); + } + const values = getKeyOpValue(results); return hasAllResults @@ -80,7 +95,7 @@ export const useOptions = ( ...values, ]; }, - [getKeyOpValue, result], + [getKeyOpValue, result, variableAsValue], ); const getKeyOperatorOptions = useCallback( @@ -128,7 +143,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 +179,7 @@ export const useOptions = ( getKeyOperatorOptions, getOptionsWithValidOperator, isFetching, + variableAsValue, ]); return useMemo( diff --git a/frontend/src/lib/dashbaordVariables/getDashboardVariables.ts b/frontend/src/lib/dashbaordVariables/getDashboardVariables.ts index cba2e597e101..972a20063c71 100644 --- a/frontend/src/lib/dashbaordVariables/getDashboardVariables.ts +++ b/frontend/src/lib/dashbaordVariables/getDashboardVariables.ts @@ -26,6 +26,8 @@ export const getDashboardVariables = ( variablesTuple[value.name] = value?.type === 'DYNAMIC' && value?.allSelected && + value?.showALLOption && + value?.multiSelect && !value?.haveCustomValuesSelected ? '__all__' : value?.selectedValue;