feat: add custom orderBy (#2975)

* feat: add custom orderBy

* chore: magic string is removed

---------

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-29 18:49:56 +03:00 committed by GitHub
parent 3464b2a59c
commit 0f998a4845
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 16 deletions

View File

@ -1,6 +1,8 @@
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 { IOption } from 'hooks/useResourceAttribute/types';
import { uniqWith } from 'lodash-es';
import * as Papa from 'papaparse'; import * as Papa from 'papaparse';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
@ -9,6 +11,7 @@ import { DataSource, MetricAggregateOperator } from 'types/common/queryBuilder';
import { selectStyle } from '../QueryBuilderSearch/config'; import { selectStyle } from '../QueryBuilderSearch/config';
import { getRemoveOrderFromValue } from '../QueryBuilderSearch/utils'; import { getRemoveOrderFromValue } from '../QueryBuilderSearch/utils';
import { FILTERS } from './config';
import { OrderByFilterProps } from './OrderByFilter.interfaces'; import { OrderByFilterProps } from './OrderByFilter.interfaces';
import { import {
checkIfKeyPresent, checkIfKeyPresent,
@ -22,7 +25,7 @@ export function OrderByFilter({
onChange, onChange,
}: OrderByFilterProps): JSX.Element { }: OrderByFilterProps): JSX.Element {
const [searchText, setSearchText] = useState<string>(''); const [searchText, setSearchText] = useState<string>('');
const [selectedValue, setSelectedValue] = useState<string[]>([]); const [selectedValue, setSelectedValue] = useState<IOption[]>([]);
const { data, isFetching } = useQuery( const { data, isFetching } = useQuery(
[QueryBuilderKeys.GET_AGGREGATE_KEYS, searchText], [QueryBuilderKeys.GET_AGGREGATE_KEYS, searchText],
@ -55,23 +58,41 @@ export function OrderByFilter({
.flat() .flat()
.concat([ .concat([
{ {
label: `${query.aggregateOperator}(${query.aggregateAttribute.key}) asc`, label: `${query.aggregateOperator}(${query.aggregateAttribute.key}) ${FILTERS.ASC}`,
value: `${query.aggregateOperator}(${query.aggregateAttribute.key})${orderByValueDelimiter}asc`, value: `${query.aggregateOperator}(${query.aggregateAttribute.key})${orderByValueDelimiter}${FILTERS.ASC}`,
}, },
{ {
label: `${query.aggregateOperator}(${query.aggregateAttribute.key}) desc`, label: `${query.aggregateOperator}(${query.aggregateAttribute.key}) ${FILTERS.DESC}`,
value: `${query.aggregateOperator}(${query.aggregateAttribute.key})${orderByValueDelimiter}desc`, value: `${query.aggregateOperator}(${query.aggregateAttribute.key})${orderByValueDelimiter}${FILTERS.DESC}`,
}, },
]), ]),
[query.aggregateAttribute.key, query.aggregateOperator, query.groupBy], [query.aggregateAttribute.key, query.aggregateOperator, query.groupBy],
); );
const customValue: IOption[] = useMemo(() => {
if (!searchText) return [];
return [
{
label: `${searchText} ${FILTERS.ASC}`,
value: `${searchText}${orderByValueDelimiter}${FILTERS.ASC}`,
},
{
label: `${searchText} ${FILTERS.DESC}`,
value: `${searchText}${orderByValueDelimiter}${FILTERS.DESC}`,
},
];
}, [searchText]);
const optionsData = useMemo(() => { const optionsData = useMemo(() => {
const options = const options =
query.aggregateOperator === MetricAggregateOperator.NOOP query.aggregateOperator === MetricAggregateOperator.NOOP
? noAggregationOptions ? noAggregationOptions
: aggregationOptions; : aggregationOptions;
return options.filter(
const resultOption = [...customValue, ...options];
return resultOption.filter(
(option) => (option) =>
!getLabelFromValue(selectedValue).includes( !getLabelFromValue(selectedValue).includes(
getRemoveOrderFromValue(option.value), getRemoveOrderFromValue(option.value),
@ -79,30 +100,58 @@ export function OrderByFilter({
); );
}, [ }, [
aggregationOptions, aggregationOptions,
customValue,
noAggregationOptions, noAggregationOptions,
query.aggregateOperator, query.aggregateOperator,
selectedValue, selectedValue,
]); ]);
const handleChange = (values: string[]): void => { const getUniqValues = useCallback((values: IOption[]): IOption[] => {
setSelectedValue(values); const modifiedValues = values.map((item) => {
const orderByValues: OrderByPayload[] = values.map((item) => { const match = Papa.parse(item.value, { delimiter: orderByValueDelimiter });
const match = Papa.parse(item, { delimiter: '|' }); if (!match) return { label: item.label, value: item.value };
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars
const [_, order] = match.data.flat() as string[];
if (order) return { label: item.label, value: item.value };
return {
label: `${item.value} ${FILTERS.ASC}`,
value: `${item.value}${orderByValueDelimiter}${FILTERS.ASC}`,
};
});
return uniqWith(
modifiedValues,
(current, next) =>
getRemoveOrderFromValue(current.value) ===
getRemoveOrderFromValue(next.value),
);
}, []);
const handleChange = (values: IOption[]): void => {
const result = getUniqValues(values);
setSelectedValue(result);
const orderByValues: OrderByPayload[] = result.map((item) => {
const match = Papa.parse(item.value, { delimiter: orderByValueDelimiter });
if (match) { if (match) {
const [columnName, order] = match.data.flat() as string[]; const [columnName, order] = match.data.flat() as string[];
return { return {
columnName: checkIfKeyPresent(columnName, query.aggregateAttribute.key) columnName: checkIfKeyPresent(columnName, query.aggregateAttribute.key)
? '#SIGNOZ_VALUE' ? '#SIGNOZ_VALUE'
: columnName, : columnName,
order, order: order ?? 'asc',
}; };
} }
return { return {
columnName: item, columnName: item.value,
order: '', order: 'asc',
}; };
}); });
setSearchText('');
onChange(orderByValues); onChange(orderByValues);
}; };
@ -126,6 +175,8 @@ export function OrderByFilter({
showSearch showSearch
disabled={isMetricsDataSource && isDisabledSelect} disabled={isMetricsDataSource && isDisabledSelect}
showArrow={false} showArrow={false}
value={selectedValue}
labelInValue
filterOption={false} filterOption={false}
options={optionsData} options={optionsData}
notFoundContent={isFetching ? <Spin size="small" /> : null} notFoundContent={isFetching ? <Spin size="small" /> : null}

View File

@ -0,0 +1,4 @@
export const FILTERS = {
ASC: 'asc',
DESC: 'desc',
};

View File

@ -2,9 +2,18 @@ import { IOption } from 'hooks/useResourceAttribute/types';
import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix'; import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix';
import * as Papa from 'papaparse'; import * as Papa from 'papaparse';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { OrderByPayload } from 'types/api/queryBuilder/queryBuilderData';
export const orderByValueDelimiter = '|'; export const orderByValueDelimiter = '|';
export const transformToOrderByStringValues = (
orderBy: OrderByPayload[],
): IOption[] =>
orderBy.map((item) => ({
label: `${item.columnName} ${item.order}`,
value: `${item.columnName}${orderByValueDelimiter}${item.order}`,
}));
export function mapLabelValuePairs( export function mapLabelValuePairs(
arr: BaseAutocompleteData[], arr: BaseAutocompleteData[],
): Array<IOption>[] { ): Array<IOption>[] {
@ -28,14 +37,15 @@ export function mapLabelValuePairs(
}); });
} }
export function getLabelFromValue(arr: string[]): string[] { export function getLabelFromValue(arr: IOption[]): string[] {
return arr.flat().map((item) => { return arr.flat().map((item) => {
const match = Papa.parse(item, { delimiter: orderByValueDelimiter }); const match = Papa.parse(item.value, { delimiter: orderByValueDelimiter });
if (match) { if (match) {
const [key] = match.data as string[]; const [key] = match.data as string[];
return key[0]; return key[0];
} }
return item;
return item.value;
}); });
} }