fix: query builder edit mode doesn't send correct payload (#2804)

* fix: where clause getting values

* fix: group by filter custom option

* fix: id for group by and aggregate filters

* fix: repeating values

* refactor: group by uniq items

* fix: removing source key

* fix: keep where clause filter on operator change

* chore: clean up for console log and additional variables

---------

Co-authored-by: Chintan Sudani <46838508+techchintan@users.noreply.github.com>
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
Yevhen Shevchenko 2023-06-06 22:28:18 +03:00 committed by GitHub
parent 6614cd31c1
commit 342e94d093
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 167 additions and 110 deletions

View File

@ -1,6 +1,8 @@
import { ApiV3Instance } from 'api'; import { ApiV3Instance } from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import { baseAutoCompleteIdKeysOrder } from 'constants/queryBuilder';
import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
import createQueryParams from 'lib/createQueryParams'; import createQueryParams from 'lib/createQueryParams';
// ** Helpers // ** Helpers
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorResponse, SuccessResponse } from 'types/api';
@ -10,7 +12,6 @@ import {
BaseAutocompleteData, BaseAutocompleteData,
IQueryAutocompleteResponse, IQueryAutocompleteResponse,
} from 'types/api/queryBuilder/queryAutocompleteResponse'; } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { v4 as uuid } from 'uuid';
export const getAggregateAttribute = async ({ export const getAggregateAttribute = async ({
aggregateOperator, aggregateOperator,
@ -31,8 +32,10 @@ export const getAggregateAttribute = async ({
); );
const payload: BaseAutocompleteData[] = const payload: BaseAutocompleteData[] =
response.data.data.attributeKeys?.map((item) => ({ ...item, id: uuid() })) || response.data.data.attributeKeys?.map(({ id: _, ...item }) => ({
[]; ...item,
id: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder),
})) || [];
return { return {
statusCode: 200, statusCode: 200,

View File

@ -1,6 +1,8 @@
import { ApiV3Instance } from 'api'; import { ApiV3Instance } from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import { baseAutoCompleteIdKeysOrder } from 'constants/queryBuilder';
import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
import createQueryParams from 'lib/createQueryParams'; import createQueryParams from 'lib/createQueryParams';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorResponse, SuccessResponse } from 'types/api';
// ** Types // ** Types
@ -9,7 +11,6 @@ import {
BaseAutocompleteData, BaseAutocompleteData,
IQueryAutocompleteResponse, IQueryAutocompleteResponse,
} from 'types/api/queryBuilder/queryAutocompleteResponse'; } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { v4 as uuid } from 'uuid';
export const getAggregateKeys = async ({ export const getAggregateKeys = async ({
aggregateOperator, aggregateOperator,
@ -33,8 +34,10 @@ export const getAggregateKeys = async ({
); );
const payload: BaseAutocompleteData[] = const payload: BaseAutocompleteData[] =
response.data.data.attributeKeys?.map((item) => ({ ...item, id: uuid() })) || response.data.data.attributeKeys?.map(({ id: _, ...item }) => ({
[]; ...item,
id: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder),
})) || [];
return { return {
statusCode: 200, statusCode: 200,

View File

@ -1,7 +1,10 @@
// ** Helpers // ** Helpers
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName'; import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName';
import { LocalDataType } from 'types/api/queryBuilder/queryAutocompleteResponse'; import {
BaseAutocompleteData,
LocalDataType,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { import {
HavingForm, HavingForm,
IBuilderFormula, IBuilderFormula,
@ -35,7 +38,13 @@ import {
export const MAX_FORMULAS = 20; export const MAX_FORMULAS = 20;
export const MAX_QUERIES = 26; export const MAX_QUERIES = 26;
export const selectValueDivider = '--'; export const idDivider = '--';
export const selectValueDivider = '__';
export const baseAutoCompleteIdKeysOrder: (keyof Omit<
BaseAutocompleteData,
'id'
>)[] = ['key', 'dataType', 'type', 'isColumn'];
export const formulasNames: string[] = Array.from( export const formulasNames: string[] = Array.from(
Array(MAX_FORMULAS), Array(MAX_FORMULAS),
@ -90,7 +99,7 @@ export const initialHavingValues: HavingForm = {
value: [], value: [],
}; };
export const initialAggregateAttribute: IBuilderQuery['aggregateAttribute'] = { export const initialAutocompleteData: BaseAutocompleteData = {
id: uuid(), id: uuid(),
dataType: null, dataType: null,
key: '', key: '',
@ -102,7 +111,7 @@ export const initialQueryBuilderFormValues: IBuilderQuery = {
dataSource: DataSource.METRICS, dataSource: DataSource.METRICS,
queryName: createNewBuilderItemName({ existNames: [], sourceNames: alphabet }), queryName: createNewBuilderItemName({ existNames: [], sourceNames: alphabet }),
aggregateOperator: MetricAggregateOperator.NOOP, aggregateOperator: MetricAggregateOperator.NOOP,
aggregateAttribute: initialAggregateAttribute, aggregateAttribute: initialAutocompleteData,
filters: { items: [], op: 'AND' }, filters: { items: [], op: 'AND' },
expression: createNewBuilderItemName({ expression: createNewBuilderItemName({
existNames: [], existNames: [],

View File

@ -3,19 +3,25 @@ import { AutoComplete, Spin } from 'antd';
// ** Api // ** Api
import { getAggregateAttribute } from 'api/queryBuilder/getAggregateAttribute'; import { getAggregateAttribute } from 'api/queryBuilder/getAggregateAttribute';
import { import {
initialAggregateAttribute, baseAutoCompleteIdKeysOrder,
idDivider,
initialAutocompleteData,
QueryBuilderKeys, QueryBuilderKeys,
selectValueDivider, selectValueDivider,
} from 'constants/queryBuilder'; } from 'constants/queryBuilder';
import useDebounce from 'hooks/useDebounce'; import useDebounce from 'hooks/useDebounce';
import { getFilterObjectValue } from 'lib/newQueryBuilder/getFilterObjectValue'; import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix'; import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
import {
AutocompleteType,
BaseAutocompleteData,
DataType,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataSource } from 'types/common/queryBuilder'; import { DataSource } from 'types/common/queryBuilder';
import { ExtendedSelectOption } from 'types/common/select'; import { ExtendedSelectOption } from 'types/common/select';
import { transformToUpperCase } from 'utils/transformToUpperCase'; import { transformToUpperCase } from 'utils/transformToUpperCase';
import { v4 as uuid } from 'uuid';
import { selectStyle } from '../QueryBuilderSearch/config'; import { selectStyle } from '../QueryBuilderSearch/config';
// ** Types // ** Types
@ -27,7 +33,7 @@ export const AggregatorFilter = memo(function AggregatorFilter({
}: AgregatorFilterProps): JSX.Element { }: AgregatorFilterProps): JSX.Element {
const [optionsData, setOptionsData] = useState<ExtendedSelectOption[]>([]); const [optionsData, setOptionsData] = useState<ExtendedSelectOption[]>([]);
const debouncedValue = useDebounce(query.aggregateAttribute.key, 300); const debouncedValue = useDebounce(query.aggregateAttribute.key, 300);
const { data, isFetching } = useQuery( const { isFetching } = useQuery(
[ [
QueryBuilderKeys.GET_AGGREGATE_ATTRIBUTE, QueryBuilderKeys.GET_AGGREGATE_ATTRIBUTE,
debouncedValue, debouncedValue,
@ -44,18 +50,17 @@ export const AggregatorFilter = memo(function AggregatorFilter({
enabled: !!query.aggregateOperator && !!query.dataSource, enabled: !!query.aggregateOperator && !!query.dataSource,
onSuccess: (data) => { onSuccess: (data) => {
const options: ExtendedSelectOption[] = const options: ExtendedSelectOption[] =
data?.payload?.attributeKeys?.map((item) => ({ data?.payload?.attributeKeys?.map(({ id: _, ...item }) => ({
label: transformStringWithPrefix({ label: transformStringWithPrefix({
str: item.key, str: item.key,
prefix: item.type || '', prefix: item.type || '',
condition: !item.isColumn, condition: !item.isColumn,
}), }),
value: `${transformStringWithPrefix({ value: `${item.key}${selectValueDivider}${createIdFromObjectFields(
str: item.key, item,
prefix: item.type || '', baseAutoCompleteIdKeysOrder,
condition: !item.isColumn, )}`,
})}${selectValueDivider}${item.id || uuid()}`, key: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder),
key: item.id || uuid(),
})) || []; })) || [];
setOptionsData(options); setOptionsData(options);
@ -70,15 +75,23 @@ export const AggregatorFilter = memo(function AggregatorFilter({
): void => { ): void => {
const currentOption = option as ExtendedSelectOption; const currentOption = option as ExtendedSelectOption;
const { key } = getFilterObjectValue(value); if (currentOption.key) {
const [key, dataType, type, isColumn] = currentOption.key.split(idDivider);
const attribute: BaseAutocompleteData = {
key,
dataType: dataType as DataType,
type: type as AutocompleteType,
isColumn: isColumn === 'true',
};
const currentAttributeObj = data?.payload?.attributeKeys?.find( onChange(attribute);
(item) => currentOption.key === item.id, } else {
) || { ...initialAggregateAttribute, key }; const attribute = { ...initialAutocompleteData, key: value };
onChange(currentAttributeObj); onChange(attribute);
}
}, },
[data, onChange], [onChange],
); );
const value = useMemo( const value = useMemo(

View File

@ -1,17 +1,25 @@
import { Select, Spin } from 'antd'; import { Select, Spin } from 'antd';
import { getAggregateKeys } from 'api/queryBuilder/getAttributeKeys'; import { getAggregateKeys } from 'api/queryBuilder/getAttributeKeys';
// ** Constants // ** Constants
import { QueryBuilderKeys, selectValueDivider } from 'constants/queryBuilder'; import {
idDivider,
initialAutocompleteData,
QueryBuilderKeys,
selectValueDivider,
} from 'constants/queryBuilder';
import useDebounce from 'hooks/useDebounce'; import useDebounce from 'hooks/useDebounce';
import { getFilterObjectValue } from 'lib/newQueryBuilder/getFilterObjectValue';
// ** Components // ** Components
// ** Helpers // ** Helpers
import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix'; import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix';
import { memo, useEffect, useState } from 'react'; import { isEqual, uniqWith } from 'lodash-es';
import { memo, useCallback, useEffect, useState } from 'react';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import {
AutocompleteType,
BaseAutocompleteData,
DataType,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { SelectOption } from 'types/common/select'; import { SelectOption } from 'types/common/select';
import { v4 as uuid } from 'uuid';
import { selectStyle } from '../QueryBuilderSearch/config'; import { selectStyle } from '../QueryBuilderSearch/config';
import { GroupByFilterProps } from './GroupByFilter.interfaces'; import { GroupByFilterProps } from './GroupByFilter.interfaces';
@ -32,7 +40,7 @@ export const GroupByFilter = memo(function GroupByFilter({
const debouncedValue = useDebounce(searchText, 300); const debouncedValue = useDebounce(searchText, 300);
const { data, isFetching } = useQuery( const { isFetching } = useQuery(
[QueryBuilderKeys.GET_AGGREGATE_KEYS, debouncedValue, isFocused], [QueryBuilderKeys.GET_AGGREGATE_KEYS, debouncedValue, isFocused],
async () => async () =>
getAggregateKeys({ getAggregateKeys({
@ -65,7 +73,7 @@ export const GroupByFilter = memo(function GroupByFilter({
str: item.key, str: item.key,
prefix: item.type || '', prefix: item.type || '',
condition: !item.isColumn, condition: !item.isColumn,
})}${selectValueDivider}${item.id || uuid()}`, })}${selectValueDivider}${item.id}`,
})) || []; })) || [];
setOptionsData(options); setOptionsData(options);
@ -87,36 +95,32 @@ export const GroupByFilter = memo(function GroupByFilter({
}; };
const handleChange = (values: SelectOption<string, string>[]): void => { const handleChange = (values: SelectOption<string, string>[]): void => {
const responseKeys = data?.payload?.attributeKeys || [];
const groupByValues: BaseAutocompleteData[] = values.map((item) => { const groupByValues: BaseAutocompleteData[] = values.map((item) => {
const [currentValue, id] = item.value.split(selectValueDivider); const [currentValue, id] = item.value.split(selectValueDivider);
const { key, type, isColumn } = getFilterObjectValue(currentValue); if (id && id.includes(idDivider)) {
const [key, dataType, type, isColumn] = id.split(idDivider);
const existGroupQuery = query.groupBy.find((group) => group.id === id); return {
id,
if (existGroupQuery) { key,
return existGroupQuery; dataType: dataType as DataType,
type: type as AutocompleteType,
isColumn: isColumn === 'true',
};
} }
const existGroupResponse = responseKeys.find((group) => group.id === id); return { ...initialAutocompleteData, key: currentValue };
if (existGroupResponse) {
return existGroupResponse;
}
return {
id: uuid(),
isColumn,
key,
dataType: null,
type,
};
}); });
onChange(groupByValues); const result = uniqWith(groupByValues, isEqual);
onChange(result);
}; };
const clearSearch = useCallback(() => {
setSearchText('');
}, []);
useEffect(() => { useEffect(() => {
const currentValues: SelectOption<string, string>[] = query.groupBy.map( const currentValues: SelectOption<string, string>[] = query.groupBy.map(
(item) => ({ (item) => ({
@ -129,7 +133,7 @@ export const GroupByFilter = memo(function GroupByFilter({
str: item.key, str: item.key,
prefix: item.type || '', prefix: item.type || '',
condition: !item.isColumn, condition: !item.isColumn,
})}${selectValueDivider}${item.id || uuid()}`, })}${selectValueDivider}${item.id}`,
}), }),
); );
@ -147,6 +151,7 @@ export const GroupByFilter = memo(function GroupByFilter({
filterOption={false} filterOption={false}
onBlur={handleBlur} onBlur={handleBlur}
onFocus={handleFocus} onFocus={handleFocus}
onDeselect={clearSearch}
options={optionsData} options={optionsData}
value={localValues} value={localValues}
labelInValue labelInValue

View File

@ -5,9 +5,11 @@ import {
KeyboardEvent, KeyboardEvent,
ReactElement, ReactElement,
ReactNode, ReactNode,
useCallback,
useEffect, useEffect,
useMemo, useMemo,
} from 'react'; } from 'react';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { import {
IBuilderQuery, IBuilderQuery,
TagFilter, TagFilter,
@ -44,7 +46,11 @@ function QueryBuilderSearch({
searchKey, searchKey,
} = useAutoComplete(query); } = useAutoComplete(query);
const { sourceKeys } = useFetchKeysAndValues(searchValue, query, searchKey); const { sourceKeys, handleRemoveSourceKey } = useFetchKeysAndValues(
searchValue,
query,
searchKey,
);
const onTagRender = ({ const onTagRender = ({
value, value,
@ -94,6 +100,14 @@ function QueryBuilderSearch({
if (isExistsNotExistsOperator(searchValue)) handleKeyDown(event); if (isExistsNotExistsOperator(searchValue)) handleKeyDown(event);
}; };
const handleDeselect = useCallback(
(deselectedItem: string) => {
handleClearTag(deselectedItem);
handleRemoveSourceKey(deselectedItem);
},
[handleClearTag, handleRemoveSourceKey],
);
const isMetricsDataSource = useMemo( const isMetricsDataSource = useMemo(
() => query.dataSource === DataSource.METRICS, () => query.dataSource === DataSource.METRICS,
[query.dataSource], [query.dataSource],
@ -106,9 +120,12 @@ function QueryBuilderSearch({
useEffect(() => { useEffect(() => {
const initialTagFilters: TagFilter = { items: [], op: 'AND' }; const initialTagFilters: TagFilter = { items: [], op: 'AND' };
const initialSourceKeys = query.filters.items.map(
(item) => item.key as BaseAutocompleteData,
);
initialTagFilters.items = tags.map((tag) => { initialTagFilters.items = tags.map((tag) => {
const { tagKey, tagOperator, tagValue } = getTagToken(tag); const { tagKey, tagOperator, tagValue } = getTagToken(tag);
const filterAttribute = sourceKeys.find( const filterAttribute = [...initialSourceKeys, ...sourceKeys].find(
(key) => key.key === getRemovePrefixFromKey(tagKey), (key) => key.key === getRemovePrefixFromKey(tagKey),
); );
return { return {
@ -128,7 +145,7 @@ function QueryBuilderSearch({
}); });
onChange(initialTagFilters); onChange(initialTagFilters);
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
}, [sourceKeys, tags]); }, [sourceKeys]);
return ( return (
<Select <Select
@ -146,7 +163,7 @@ function QueryBuilderSearch({
onSearch={handleSearch} onSearch={handleSearch}
onChange={onChangeHandler} onChange={onChangeHandler}
onSelect={handleSelect} onSelect={handleSelect}
onDeselect={handleClearTag} onDeselect={handleDeselect}
onInputKeyDown={onInputKeyDownHandler} onInputKeyDown={onInputKeyDownHandler}
notFoundContent={isFetching ? <Spin size="small" /> : null} notFoundContent={isFetching ? <Spin size="small" /> : null}
> >

View File

@ -8,7 +8,7 @@ import {
} from 'container/QueryBuilder/filters/QueryBuilderSearch/utils'; } from 'container/QueryBuilder/filters/QueryBuilderSearch/utils';
import { isEqual, uniqWith } from 'lodash-es'; import { isEqual, uniqWith } from 'lodash-es';
import debounce from 'lodash-es/debounce'; import debounce from 'lodash-es/debounce';
import { useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
import { useDebounce } from 'react-use'; import { useDebounce } from 'react-use';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
@ -20,6 +20,7 @@ type IuseFetchKeysAndValues = {
results: string[]; results: string[];
isFetching: boolean; isFetching: boolean;
sourceKeys: BaseAutocompleteData[]; sourceKeys: BaseAutocompleteData[];
handleRemoveSourceKey: (newSourceKey: string) => void;
}; };
/** /**
@ -127,6 +128,12 @@ export const useFetchKeysAndValues = (
} }
}; };
const handleRemoveSourceKey = useCallback((sourceKey: string) => {
setSourceKeys((prevState) =>
prevState.filter((item) => item.key !== sourceKey),
);
}, []);
// creates a ref to the fetch function so that it doesn't change on every render // creates a ref to the fetch function so that it doesn't change on every render
const clearFetcher = useRef(handleFetchOption).current; const clearFetcher = useRef(handleFetchOption).current;
@ -155,5 +162,6 @@ export const useFetchKeysAndValues = (
results, results,
isFetching, isFetching,
sourceKeys, sourceKeys,
handleRemoveSourceKey,
}; };
}; };

View File

@ -1,5 +1,5 @@
import { import {
initialAggregateAttribute, initialAutocompleteData,
initialQueryBuilderFormValues, initialQueryBuilderFormValues,
mapOfFilters, mapOfFilters,
} from 'constants/queryBuilder'; } from 'constants/queryBuilder';
@ -44,9 +44,8 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
aggregateOperator: value, aggregateOperator: value,
having: [], having: [],
limit: null, limit: null,
filters: { items: [], op: 'AND' },
...(shouldResetAggregateAttribute ...(shouldResetAggregateAttribute
? { aggregateAttribute: initialAggregateAttribute } ? { aggregateAttribute: initialAutocompleteData }
: {}), : {}),
}; };

View File

@ -5,7 +5,7 @@ import {
} from 'container/QueryBuilder/filters/QueryBuilderSearch/utils'; } from 'container/QueryBuilder/filters/QueryBuilderSearch/utils';
// eslint-disable-next-line import/no-extraneous-dependencies // eslint-disable-next-line import/no-extraneous-dependencies
import * as Papa from 'papaparse'; import * as Papa from 'papaparse';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
type IUseTag = { type IUseTag = {
@ -30,7 +30,19 @@ export const useTag = (
query: IBuilderQuery, query: IBuilderQuery,
setSearchKey: (value: string) => void, setSearchKey: (value: string) => void,
): IUseTag => { ): IUseTag => {
const [tags, setTags] = useState<string[]>([]); const initTagsData = useMemo(
() =>
(query?.filters?.items || []).map((ele) => {
if (isInNInOperator(getOperatorFromValue(ele.op))) {
const csvString = Papa.unparse([ele.value]);
return `${ele.key?.key} ${getOperatorFromValue(ele.op)} ${csvString}`;
}
return `${ele.key?.key} ${getOperatorFromValue(ele.op)} ${ele.value}`;
}),
[query.filters],
);
const [tags, setTags] = useState<string[]>(initTagsData);
const updateTag = (value: string): void => { const updateTag = (value: string): void => {
const newTags = tags?.filter((item: string) => item !== value); const newTags = tags?.filter((item: string) => item !== value);
@ -61,16 +73,8 @@ export const useTag = (
}, []); }, []);
useEffect(() => { useEffect(() => {
const initialTags = (query?.filters?.items || []).map((ele) => { setTags(initTagsData);
if (isInNInOperator(getOperatorFromValue(ele.op))) { }, [initTagsData]);
const csvString = Papa.unparse([ele.value]);
return `${ele.key?.key} ${getOperatorFromValue(ele.op)} ${csvString}`;
}
return `${ele.key?.key} ${getOperatorFromValue(ele.op)} ${ele.value}`;
});
setTags(initialTags);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return { handleAddTag, handleClearTag, tags, updateTag }; return { handleAddTag, handleClearTag, tags, updateTag };
}; };

View File

@ -0,0 +1,6 @@
import { idDivider } from 'constants/queryBuilder';
export const createIdFromObjectFields = <T, K extends keyof T>(
obj: T,
orderedKeys: K[],
): string => orderedKeys.map((key) => obj[key]).join(idDivider);

View File

@ -1,33 +0,0 @@
import { TYPE_ADDON_REGEXP } from 'constants/regExp';
import {
AutocompleteType,
BaseAutocompleteData,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
const getType = (str: string): AutocompleteType | null => {
const types: AutocompleteType[] = ['tag', 'resource'];
let currentType: AutocompleteType | null = null;
types.forEach((type) => {
if (str.includes(type)) {
currentType = type;
}
});
return currentType;
};
export const getFilterObjectValue = (
value: string,
): Omit<BaseAutocompleteData, 'dataType' | 'id'> => {
const type = getType(value);
if (!type) {
return { isColumn: true, key: value, type: null };
}
const splittedValue = value.split(TYPE_ADDON_REGEXP);
return { isColumn: false, key: splittedValue[1], type };
};

View File

@ -1,5 +1,6 @@
import { import {
alphabet, alphabet,
baseAutoCompleteIdKeysOrder,
formulasNames, formulasNames,
initialClickHouseData, initialClickHouseData,
initialFormulaBuilderFormValues, initialFormulaBuilderFormValues,
@ -15,6 +16,7 @@ import {
import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames'; import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import useUrlQuery from 'hooks/useUrlQuery'; import useUrlQuery from 'hooks/useUrlQuery';
import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName'; import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName';
import { getOperatorsBySourceAndPanelType } from 'lib/newQueryBuilder/getOperatorsBySourceAndPanelType'; import { getOperatorsBySourceAndPanelType } from 'lib/newQueryBuilder/getOperatorsBySourceAndPanelType';
import { replaceIncorrectObjectFields } from 'lib/replaceIncorrectObjectFields'; import { replaceIncorrectObjectFields } from 'lib/replaceIncorrectObjectFields';
@ -100,6 +102,7 @@ export function QueryBuilderProvider({
const initQueryBuilderData = useCallback((query: Partial<Query>): void => { const initQueryBuilderData = useCallback((query: Partial<Query>): void => {
const { queryType, ...queryState } = query; const { queryType, ...queryState } = query;
const builder: QueryBuilderData = { const builder: QueryBuilderData = {
queryData: queryState.builder queryData: queryState.builder
? queryState.builder.queryData.map((item) => ({ ? queryState.builder.queryData.map((item) => ({
@ -129,7 +132,27 @@ export function QueryBuilderProvider({
})) }))
: initialQuery.clickhouse_sql; : initialQuery.clickhouse_sql;
setCurrentQuery({ builder, clickhouse_sql: clickHouse, promql }); setCurrentQuery({
clickhouse_sql: clickHouse,
promql,
builder: {
...builder,
queryData: builder.queryData.map((q) => ({
...q,
groupBy: q.groupBy.map(({ id: _, ...item }) => ({
...item,
id: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder),
})),
aggregateAttribute: {
...q.aggregateAttribute,
id: createIdFromObjectFields(
q.aggregateAttribute,
baseAutoCompleteIdKeysOrder,
),
},
})),
},
});
setQueryType(queryType || EQueryType.QUERY_BUILDER); setQueryType(queryType || EQueryType.QUERY_BUILDER);
}, []); }, []);