fix: issue of new query builder v3 (#2697)

* fix: position of where caluse is changed for metrics

* fix: by default enabled for logs & traces

* fix: to many api call for key on search

* fix: make chip on enter for exists/nexists

* fix: flickering issue on selection of option

* fix: text change

* fix: orderby payload issue

* fix: removed replace logic

* fix: responsive qb & disabled issue

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
Co-authored-by: Ankit Nayan <ankit@signoz.io>
This commit is contained in:
Chintan Sudani 2023-05-18 12:55:18 +05:30 committed by GitHub
parent a0c320e47e
commit ca3ff04f7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 206 additions and 148 deletions

View File

@ -14,11 +14,11 @@ import {
GroupByFilter, GroupByFilter,
HavingFilter, HavingFilter,
OperatorsSelect, OperatorsSelect,
OrderByFilter,
ReduceToFilter, ReduceToFilter,
} from 'container/QueryBuilder/filters'; } from 'container/QueryBuilder/filters';
import AggregateEveryFilter from 'container/QueryBuilder/filters/AggregateEveryFilter'; import AggregateEveryFilter from 'container/QueryBuilder/filters/AggregateEveryFilter';
import LimitFilter from 'container/QueryBuilder/filters/LimitFilter/LimitFilter'; import LimitFilter from 'container/QueryBuilder/filters/LimitFilter/LimitFilter';
import { OrderByFilter } from 'container/QueryBuilder/filters/OrderByFilter';
import QueryBuilderSearch from 'container/QueryBuilder/filters/QueryBuilderSearch'; import QueryBuilderSearch from 'container/QueryBuilder/filters/QueryBuilderSearch';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryOperations'; import { useQueryOperations } from 'hooks/queryBuilder/useQueryOperations';
@ -233,6 +233,25 @@ export const Query = memo(function Query({
<FilterLabel label={transformToUpperCase(query.dataSource)} /> <FilterLabel label={transformToUpperCase(query.dataSource)} />
)} )}
</Col> </Col>
{isMetricsDataSource && (
<Col span={12}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<OperatorsSelect
value={query.aggregateOperator}
onChange={handleChangeOperator}
operators={operators}
/>
</Col>
<Col flex="1 1 12.5rem">
<AggregatorFilter
onChange={handleChangeAggregatorAttribute}
query={query}
/>
</Col>
</Row>
</Col>
)}
<Col flex="1 1 20rem"> <Col flex="1 1 20rem">
<Row gutter={[11, 5]}> <Row gutter={[11, 5]}>
{isMetricsDataSource && ( {isMetricsDataSource && (
@ -247,25 +266,26 @@ export const Query = memo(function Query({
</Col> </Col>
</Row> </Row>
</Col> </Col>
<Col span={11}> {!isMetricsDataSource && (
<Row gutter={[11, 5]}> <Col span={11}>
<Col flex="5.93rem"> <Row gutter={[11, 5]}>
<OperatorsSelect <Col flex="5.93rem">
value={query.aggregateOperator} <OperatorsSelect
onChange={handleChangeOperator} value={query.aggregateOperator}
operators={operators} onChange={handleChangeOperator}
/> operators={operators}
</Col> />
<Col flex="1 1 12.5rem"> </Col>
<AggregatorFilter <Col flex="1 1 12.5rem">
onChange={handleChangeAggregatorAttribute} <AggregatorFilter
query={query} onChange={handleChangeAggregatorAttribute}
/> query={query}
</Col> />
</Row> </Col>
</Col> </Row>
</Col>
<Col span={11} offset={2}> )}
<Col span={11} offset={isMetricsDataSource ? 0 : 2}>
<Row gutter={[11, 5]}> <Row gutter={[11, 5]}>
<Col flex="5.93rem"> <Col flex="5.93rem">
<FilterLabel <FilterLabel

View File

@ -4,6 +4,7 @@ import React, { useMemo } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { selectStyle } from '../QueryBuilderSearch/config'; import { selectStyle } from '../QueryBuilderSearch/config';
@ -41,11 +42,16 @@ function AggregateEveryFilter({
} }
}; };
const isMetricsDataSource = useMemo(
() => query.dataSource === DataSource.METRICS,
[query.dataSource],
);
return ( return (
<Input <Input
type="text" type="text"
placeholder="Enter in seconds" placeholder="Enter in seconds"
disabled={!query.aggregateAttribute.key} disabled={isMetricsDataSource && !query.aggregateAttribute.key}
style={selectStyle} style={selectStyle}
defaultValue={query.stepInterval ?? stepInterval} defaultValue={query.stepInterval ?? stepInterval}
onChange={(event): void => onChange(Number(event.target.value))} onChange={(event): void => onChange(Number(event.target.value))}

View File

@ -14,6 +14,7 @@ import {
import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix'; import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix';
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Having, HavingForm } from 'types/api/queryBuilder/queryBuilderData'; import { Having, HavingForm } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { SelectOption } from 'types/common/select'; import { SelectOption } from 'types/common/select';
// ** Types // ** Types
@ -214,6 +215,11 @@ export function HavingFilter({
setLocalValues(transformHavingToStringValue(having)); setLocalValues(transformHavingToStringValue(having));
}, [having]); }, [having]);
const isMetricsDataSource = useMemo(
() => query.dataSource === DataSource.METRICS,
[query.dataSource],
);
return ( return (
<Select <Select
autoClearSearchValue={false} autoClearSearchValue={false}
@ -223,7 +229,7 @@ export function HavingFilter({
tagRender={tagRender} tagRender={tagRender}
value={localValues} value={localValues}
data-testid="havingSelect" data-testid="havingSelect"
disabled={!query.aggregateAttribute.key} disabled={isMetricsDataSource && !query.aggregateAttribute.key}
style={{ width: '100%' }} style={{ width: '100%' }}
notFoundContent={currentFormValue.value.length === 0 ? undefined : null} notFoundContent={currentFormValue.value.length === 0 ? undefined : null}
placeholder="Count(operation) > 5" placeholder="Count(operation) > 5"

View File

@ -1,6 +1,7 @@
import { InputNumber } from 'antd'; import { InputNumber } from 'antd';
import React from 'react'; import React, { useMemo } from 'react';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { selectStyle } from '../QueryBuilderSearch/config'; import { selectStyle } from '../QueryBuilderSearch/config';
@ -20,12 +21,17 @@ function LimitFilter({ onChange, query }: LimitFilterProps): JSX.Element {
} }
}; };
const isMetricsDataSource = useMemo(
() => query.dataSource === DataSource.METRICS,
[query.dataSource],
);
return ( return (
<InputNumber <InputNumber
min={1} min={1}
type="number" type="number"
defaultValue={query.limit ?? 1} defaultValue={query.limit ?? 1}
disabled={!query.aggregateAttribute.key} disabled={isMetricsDataSource && !query.aggregateAttribute.key}
style={selectStyle} style={selectStyle}
onChange={onChange} onChange={onChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}

View File

@ -1,9 +1,11 @@
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import {
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; IBuilderQuery,
OrderByPayload,
} from 'types/api/queryBuilder/queryBuilderData';
export type OrderByFilterProps = { export type OrderByFilterProps = {
query: IBuilderQuery; query: IBuilderQuery;
onChange: (values: BaseAutocompleteData[]) => void; onChange: (values: OrderByPayload[]) => void;
}; };
export type OrderByFilterValue = { export type OrderByFilterValue = {

View File

@ -1,25 +1,28 @@
import { Select, Spin } from 'antd'; import { Select, Spin } from 'antd';
import { getAggregateKeys } from 'api/queryBuilder/getAttributeKeys'; import { getAggregateKeys } from 'api/queryBuilder/getAttributeKeys';
import { QueryBuilderKeys } from 'constants/queryBuilder'; import { QueryBuilderKeys } from 'constants/queryBuilder';
import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix'; import * as Papa from 'papaparse';
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { OrderByPayload } from 'types/api/queryBuilder/queryBuilderData';
import { MetricAggregateOperator } from 'types/common/queryBuilder'; import { DataSource, MetricAggregateOperator } from 'types/common/queryBuilder';
import { selectStyle } from '../QueryBuilderSearch/config'; import { selectStyle } from '../QueryBuilderSearch/config';
import { getRemoveOrderFromValue } from '../QueryBuilderSearch/utils';
import { OrderByFilterProps } from './OrderByFilter.interfaces';
import { import {
OrderByFilterProps, checkIfKeyPresent,
OrderByFilterValue, getLabelFromValue,
} from './OrderByFilter.interfaces'; mapLabelValuePairs,
import { getLabelFromValue, mapLabelValuePairs } from './utils'; orderByValueDelimiter,
} from './utils';
export function OrderByFilter({ export function OrderByFilter({
query, query,
onChange, onChange,
}: OrderByFilterProps): JSX.Element { }: OrderByFilterProps): JSX.Element {
const [searchText, setSearchText] = useState<string>(''); const [searchText, setSearchText] = useState<string>('');
const [selectedValue, setSelectedValue] = useState<OrderByFilterValue[]>([]); const [selectedValue, setSelectedValue] = useState<string[]>([]);
const { data, isFetching } = useQuery( const { data, isFetching } = useQuery(
[QueryBuilderKeys.GET_AGGREGATE_KEYS, searchText], [QueryBuilderKeys.GET_AGGREGATE_KEYS, searchText],
@ -41,14 +44,9 @@ export function OrderByFilter({
const noAggregationOptions = useMemo( const noAggregationOptions = useMemo(
() => () =>
data?.payload?.attributeKeys data?.payload?.attributeKeys
? mapLabelValuePairs(data?.payload?.attributeKeys) ? mapLabelValuePairs(data?.payload?.attributeKeys).flat()
.flat()
.filter(
(option) =>
!getLabelFromValue(selectedValue).includes(option.label.split(' ')[0]),
)
: [], : [],
[data?.payload?.attributeKeys, selectedValue], [data?.payload?.attributeKeys],
); );
const aggregationOptions = useMemo( const aggregationOptions = useMemo(
@ -58,78 +56,56 @@ export function OrderByFilter({
.concat([ .concat([
{ {
label: `${query.aggregateOperator}(${query.aggregateAttribute.key}) asc`, label: `${query.aggregateOperator}(${query.aggregateAttribute.key}) asc`,
value: `${query.aggregateOperator}(${query.aggregateAttribute.key}) asc`, value: `${query.aggregateOperator}(${query.aggregateAttribute.key})${orderByValueDelimiter}asc`,
}, },
{ {
label: `${query.aggregateOperator}(${query.aggregateAttribute.key}) desc`, label: `${query.aggregateOperator}(${query.aggregateAttribute.key}) desc`,
value: `${query.aggregateOperator}(${query.aggregateAttribute.key}) desc`, value: `${query.aggregateOperator}(${query.aggregateAttribute.key})${orderByValueDelimiter}desc`,
}, },
]) ]),
.filter( [query.aggregateAttribute.key, query.aggregateOperator, query.groupBy],
(option) =>
!getLabelFromValue(selectedValue).includes(option.label.split(' ')[0]),
),
[
query.aggregateAttribute.key,
query.aggregateOperator,
query.groupBy,
selectedValue,
],
); );
const optionsData = useMemo( const optionsData = useMemo(() => {
() => const options =
query.aggregateOperator === MetricAggregateOperator.NOOP query.aggregateOperator === MetricAggregateOperator.NOOP
? noAggregationOptions ? noAggregationOptions
: aggregationOptions, : aggregationOptions;
[aggregationOptions, noAggregationOptions, query.aggregateOperator], return options.filter(
); (option) =>
!getLabelFromValue(selectedValue).includes(
getRemoveOrderFromValue(option.value),
),
);
}, [
aggregationOptions,
noAggregationOptions,
query.aggregateOperator,
selectedValue,
]);
const handleChange = (values: OrderByFilterValue[]): void => { const handleChange = (values: string[]): void => {
setSelectedValue(values); setSelectedValue(values);
const orderByValues: BaseAutocompleteData[] = values?.map((item) => { const orderByValues: OrderByPayload[] = values.map((item) => {
const iterationArray = data?.payload?.attributeKeys || query.orderBy; const match = Papa.parse(item, { delimiter: '|' });
const existingOrderValues = iterationArray.find( if (match) {
(group) => group.key === item.value, const [columnName, order] = match.data.flat() as string[];
); return {
if (existingOrderValues) { columnName: checkIfKeyPresent(columnName, query.aggregateAttribute.key)
return existingOrderValues; ? '#SIGNOZ_VALUE'
: columnName,
order,
};
} }
return { return {
isColumn: null, columnName: item,
key: item.value, order: '',
dataType: null,
type: null,
}; };
}); });
onChange(orderByValues); onChange(orderByValues);
}; };
const values: OrderByFilterValue[] = useMemo(
() =>
query.orderBy
.filter((order) =>
query.groupBy.find(
(group) =>
order.key.includes(group.key) ||
order.key.includes(query.aggregateOperator),
),
)
.map((item) => ({
label: transformStringWithPrefix({
str: item.key,
prefix: item.type || '',
condition: !item.isColumn,
}),
key: item.key,
value: item.key,
disabled: undefined,
title: undefined,
})),
[query.aggregateOperator, query.groupBy, query.orderBy],
);
const isDisabledSelect = useMemo( const isDisabledSelect = useMemo(
() => () =>
!query.aggregateAttribute.key || !query.aggregateAttribute.key ||
@ -137,18 +113,21 @@ export function OrderByFilter({
[query.aggregateAttribute.key, query.aggregateOperator], [query.aggregateAttribute.key, query.aggregateOperator],
); );
const isMetricsDataSource = useMemo(
() => query.dataSource === DataSource.METRICS,
[query.dataSource],
);
return ( return (
<Select <Select
mode="tags" mode="tags"
style={selectStyle} style={selectStyle}
onSearch={handleSearchKeys} onSearch={handleSearchKeys}
showSearch showSearch
disabled={isDisabledSelect} disabled={isMetricsDataSource && isDisabledSelect}
showArrow={false} showArrow={false}
filterOption={false} filterOption={false}
options={optionsData} options={optionsData}
labelInValue
value={values}
notFoundContent={isFetching ? <Spin size="small" /> : null} notFoundContent={isFetching ? <Spin size="small" /> : null}
onChange={handleChange} onChange={handleChange}
/> />

View File

@ -1,8 +1,9 @@
import { IOption } from 'hooks/useResourceAttribute/types'; import { IOption } from 'hooks/useResourceAttribute/types';
import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix'; import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix';
import * as Papa from 'papaparse';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { OrderByFilterValue } from './OrderByFilter.interfaces'; export const orderByValueDelimiter = '|';
export function mapLabelValuePairs( export function mapLabelValuePairs(
arr: BaseAutocompleteData[], arr: BaseAutocompleteData[],
@ -17,16 +18,27 @@ export function mapLabelValuePairs(
return [ return [
{ {
label: `${label} asc`, label: `${label} asc`,
value: `${value} asc`, value: `${value}${orderByValueDelimiter}asc`,
}, },
{ {
label: `${label} desc`, label: `${label} desc`,
value: `${value} desc`, value: `${value}${orderByValueDelimiter}desc`,
}, },
]; ];
}); });
} }
export function getLabelFromValue(arr: OrderByFilterValue[]): string[] { export function getLabelFromValue(arr: string[]): string[] {
return arr.map((value) => value.label.split(' ')[0]); return arr.flat().map((item) => {
const match = Papa.parse(item, { delimiter: orderByValueDelimiter });
if (match) {
const [key] = match.data as string[];
return key[0];
}
return item;
});
}
export function checkIfKeyPresent(str: string, valueToCheck: string): boolean {
return new RegExp(`\\(${valueToCheck}\\)`).test(str);
} }

View File

@ -1 +1 @@
export const selectStyle = { width: '100%', minWidth: '10rem' }; export const selectStyle = { width: '100%', minWidth: '7.7rem' };

View File

@ -88,15 +88,15 @@ function QueryBuilderSearch({
if (isExistsNotExistsOperator(searchValue)) handleKeyDown(event); if (isExistsNotExistsOperator(searchValue)) handleKeyDown(event);
}; };
const isMatricsDataSource = useMemo( const isMetricsDataSource = useMemo(
() => query.dataSource === DataSource.METRICS, () => query.dataSource === DataSource.METRICS,
[query.dataSource], [query.dataSource],
); );
const queryTags = useMemo(() => { const queryTags = useMemo(() => {
if (!query.aggregateAttribute.key && isMatricsDataSource) return []; if (!query.aggregateAttribute.key && isMetricsDataSource) return [];
return tags; return tags;
}, [isMatricsDataSource, query.aggregateAttribute.key, tags]); }, [isMetricsDataSource, query.aggregateAttribute.key, tags]);
useEffect(() => { useEffect(() => {
const initialTagFilters: TagFilter = { items: [], op: 'AND' }; const initialTagFilters: TagFilter = { items: [], op: 'AND' };
@ -135,7 +135,7 @@ function QueryBuilderSearch({
placeholder="Search Filter" placeholder="Search Filter"
value={queryTags} value={queryTags}
searchValue={searchValue} searchValue={searchValue}
disabled={isMatricsDataSource && !query.aggregateAttribute.key} disabled={isMetricsDataSource && !query.aggregateAttribute.key}
style={selectStyle} style={selectStyle}
onSearch={handleSearch} onSearch={handleSearch}
onChange={onChangeHandler} onChange={onChangeHandler}

View File

@ -2,6 +2,8 @@ import { OPERATORS } from 'constants/queryBuilder';
// 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 { orderByValueDelimiter } from '../OrderByFilter/utils';
export const tagRegexp = /([a-zA-Z0-9_.:@$()\-/\\]+)\s*(!=|=|<=|<|>=|>|IN|NOT_IN|LIKE|NOT_LIKE|EXISTS|NOT_EXISTS|CONTAINS|NOT_CONTAINS)\s*([\s\S]*)/g; export const tagRegexp = /([a-zA-Z0-9_.:@$()\-/\\]+)\s*(!=|=|<=|<|>=|>|IN|NOT_IN|LIKE|NOT_LIKE|EXISTS|NOT_EXISTS|CONTAINS|NOT_CONTAINS)\s*([\s\S]*)/g;
export function isInNInOperator(value: string): boolean { export function isInNInOperator(value: string): boolean {
@ -39,12 +41,13 @@ export function getTagToken(tag: string): ITagToken {
export function isExistsNotExistsOperator(value: string): boolean { export function isExistsNotExistsOperator(value: string): boolean {
const { tagOperator } = getTagToken(value); const { tagOperator } = getTagToken(value);
return ( return (
tagOperator === OPERATORS.NOT_EXISTS || tagOperator === OPERATORS.EXISTS tagOperator?.trim() === OPERATORS.NOT_EXISTS ||
tagOperator?.trim() === OPERATORS.EXISTS
); );
} }
export function getRemovePrefixFromKey(tag: string): string { export function getRemovePrefixFromKey(tag: string): string {
return tag?.replace(/^(tag_|resource_)/, ''); return tag?.replace(/^(tag_|resource_)/, '').trim();
} }
export function getOperatorValue(op: string): string { export function getOperatorValue(op: string): string {
@ -106,3 +109,12 @@ export function replaceStringWithMaxLength(
export function checkCommaInValue(str: string): string { export function checkCommaInValue(str: string): string {
return str.includes(',') ? `"${str}"` : str; return str.includes(',') ? `"${str}"` : str;
} }
export function getRemoveOrderFromValue(tag: string): string {
const match = Papa.parse(tag, { delimiter: orderByValueDelimiter });
if (match) {
const [key] = match.data.flat() as string[];
return key;
}
return tag;
}

View File

@ -2,4 +2,5 @@ export { AggregatorFilter } from './AggregatorFilter';
export { GroupByFilter } from './GroupByFilter'; export { GroupByFilter } from './GroupByFilter';
export { HavingFilter } from './HavingFilter'; export { HavingFilter } from './HavingFilter';
export { OperatorsSelect } from './OperatorsSelect'; export { OperatorsSelect } from './OperatorsSelect';
export { OrderByFilter } from './OrderByFilter';
export { ReduceToFilter } from './ReduceToFilter'; export { ReduceToFilter } from './ReduceToFilter';

View File

@ -73,11 +73,9 @@ export const useAutoComplete = (query: IBuilderQuery): IAutoComplete => {
return replaceStringWithMaxLength(prev, data as string[], value); return replaceStringWithMaxLength(prev, data as string[], value);
}); });
} }
if (!isMulti && isValidTag && !isExistsNotExistsOperator(value)) { if (!isMulti) {
handleAddTag(value); if (isExistsNotExistsOperator(value)) handleAddTag(value);
} if (isValidTag && !isExistsNotExistsOperator(value)) handleAddTag(value);
if (!isMulti && isValidTag && isExistsNotExistsOperator(value)) {
handleAddTag(value);
} }
}, },
[handleAddTag, isMulti, isValidTag], [handleAddTag, isMulti, isValidTag],

View File

@ -6,6 +6,7 @@ import {
getTagToken, getTagToken,
isInNInOperator, isInNInOperator,
} from 'container/QueryBuilder/filters/QueryBuilderSearch/utils'; } from 'container/QueryBuilder/filters/QueryBuilderSearch/utils';
import debounce from 'lodash-es/debounce';
import { useEffect, useMemo, useRef, useState } from 'react'; import { 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';
@ -34,6 +35,25 @@ export const useFetchKeysAndValues = (
const [keys, setKeys] = useState<BaseAutocompleteData[]>([]); const [keys, setKeys] = useState<BaseAutocompleteData[]>([]);
const [results, setResults] = useState<string[]>([]); const [results, setResults] = useState<string[]>([]);
const searchParams = useMemo(
() =>
debounce(
() => [
searchKey,
query.dataSource,
query.aggregateOperator,
query.aggregateAttribute.key,
],
300,
),
[
query.aggregateAttribute.key,
query.aggregateOperator,
query.dataSource,
searchKey,
],
);
const isQueryEnabled = useMemo( const isQueryEnabled = useMemo(
() => () =>
query.dataSource === DataSource.METRICS query.dataSource === DataSource.METRICS
@ -49,13 +69,7 @@ export const useFetchKeysAndValues = (
); );
const { data, isFetching, status } = useQuery( const { data, isFetching, status } = useQuery(
[ [QueryBuilderKeys.GET_ATTRIBUTE_KEY, searchParams()],
QueryBuilderKeys.GET_ATTRIBUTE_KEY,
searchKey,
query.dataSource,
query.aggregateOperator,
query.aggregateAttribute.key,
],
async () => async () =>
getAggregateKeys({ getAggregateKeys({
searchText: searchKey, searchText: searchKey,

View File

@ -52,41 +52,39 @@ export const useOptions = (
); );
useEffect(() => { useEffect(() => {
let newOptions: Option[] = [];
if (!key) { if (!key) {
setOptions( newOptions = searchValue
searchValue ? [
? [ { label: `${searchValue} `, value: `${searchValue} ` },
{ label: `${searchValue} `, value: `${searchValue} ` }, ...getOptionsFromKeys(keys),
...getOptionsFromKeys(keys), ]
] : getOptionsFromKeys(keys);
: getOptionsFromKeys(keys),
);
} else if (key && !operator) { } else if (key && !operator) {
setOptions( newOptions = operators?.map((operator) => ({
operators?.map((operator) => ({ value: `${key} ${operator} `,
value: `${key} ${operator} `, label: `${key} ${operator} `,
label: `${key} ${operator} `, }));
})),
);
} else if (key && operator) { } else if (key && operator) {
if (isMulti) { if (isMulti) {
setOptions( newOptions = results.map((item) => ({
results.map((item) => ({ label: checkCommaInValue(String(item)),
label: checkCommaInValue(String(item)), value: String(item),
value: String(item), }));
})),
);
} else if (isExist) { } else if (isExist) {
setOptions([]); newOptions = [];
} else if (isValidOperator) { } else if (isValidOperator) {
const hasAllResults = results.every((value) => result.includes(value)); const hasAllResults = results.every((value) => result.includes(value));
const values = getKeyOpValue(results); const values = getKeyOpValue(results);
const options = hasAllResults newOptions = hasAllResults
? [{ label: searchValue, value: searchValue }] ? [{ label: searchValue, value: searchValue }]
: [{ label: searchValue, value: searchValue }, ...values]; : [{ label: searchValue, value: searchValue }, ...values];
setOptions(options);
} }
} }
if (newOptions.length > 0) {
setOptions(newOptions);
}
}, [ }, [
getKeyOpValue, getKeyOpValue,
getOptionsFromKeys, getOptionsFromKeys,

View File

@ -42,7 +42,6 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
...query, ...query,
aggregateOperator: value, aggregateOperator: value,
having: [], having: [],
orderBy: [],
limit: null, limit: null,
filters: { items: [], op: 'AND' }, filters: { items: [], op: 'AND' },
...(shouldResetAggregateAttribute ...(shouldResetAggregateAttribute

View File

@ -33,6 +33,11 @@ export type HavingForm = Omit<Having, 'value'> & {
value: string[]; value: string[];
}; };
export type OrderByPayload = {
columnName: string;
order: string;
};
// Type for query builder // Type for query builder
export type IBuilderQuery = { export type IBuilderQuery = {
queryName: string; queryName: string;
@ -46,7 +51,7 @@ export type IBuilderQuery = {
having: Having[]; having: Having[];
limit: number | null; limit: number | null;
stepInterval: number; stepInterval: number;
orderBy: BaseAutocompleteData[]; orderBy: OrderByPayload[];
reduceTo: ReduceOperators; reduceTo: ReduceOperators;
legend: string; legend: string;
}; };