fix: resolve the list view issues (#3020)

* feat: add dynamic table based on query

* feat: add the list view for the traces explorer

* fix: fix the options menu

* feat: update the list view columns config for the traces explorer

* feat: fix columns for the list view for the traces explorer page

* feat: update customization columns for the list view from the traces explorer

* feat: add error msg for the list view, fix creating data for the table

* fix: resolve the list view issues

* fix: update the date column for the list view

* fix: remove additional filter title for the list view

* fix: add initial orderBy filter for the list view

---------

Co-authored-by: Yevhen Shevchenko <y.shevchenko@seedium.io>
Co-authored-by: Nazarenko19 <danil.nazarenko2000@gmail.com>
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
dnazarenkoo 2023-07-05 13:50:20 +03:00 committed by GitHub
parent b1c1a95e29
commit 8363dadd8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 108 additions and 77 deletions

View File

@ -38,20 +38,12 @@ function AddColumnField({ config }: AddColumnFieldProps): JSX.Element | null {
</SearchIconWrapper> </SearchIconWrapper>
</Input.Group> </Input.Group>
{config.value.map((selectedValue: string) => { {config.value?.map(({ key, id }) => (
const option = config?.options?.find( <AddColumnItem direction="horizontal" key={id}>
({ value }) => value === selectedValue, <Typography>{key}</Typography>
); <DeleteOutlinedIcon onClick={(): void => config.onRemove(id as string)} />
</AddColumnItem>
return ( ))}
<AddColumnItem direction="horizontal" key={option?.value}>
<Typography>{option?.label}</Typography>
<DeleteOutlinedIcon
onClick={(): void => config.onRemove(selectedValue)}
/>
</AddColumnItem>
);
})}
</AddColumnWrapper> </AddColumnWrapper>
); );
} }

View File

@ -15,7 +15,8 @@ export interface InitialOptions
export type OptionsMenuConfig = { export type OptionsMenuConfig = {
format?: Pick<RadioProps, 'value' | 'onChange'>; format?: Pick<RadioProps, 'value' | 'onChange'>;
maxLines?: Pick<InputNumberProps, 'value' | 'onChange'>; maxLines?: Pick<InputNumberProps, 'value' | 'onChange'>;
addColumn?: Pick<SelectProps, 'options' | 'value' | 'onChange'> & { addColumn?: Pick<SelectProps, 'options' | 'onChange'> & {
value: BaseAutocompleteData[];
onRemove: (key: string) => void; onRemove: (key: string) => void;
}; };
}; };

View File

@ -63,15 +63,16 @@ const useOptionsMenu = ({
[initialOptions, attributeKeys], [initialOptions, attributeKeys],
); );
const options = useMemo(() => getOptionsFromKeys(attributeKeys), [
attributeKeys,
]);
const selectedColumnKeys = useMemo( const selectedColumnKeys = useMemo(
() => optionsQueryData?.selectColumns?.map(({ id }) => id) || [], () => optionsQueryData?.selectColumns?.map(({ id }) => id) || [],
[optionsQueryData], [optionsQueryData],
); );
const addColumnOptions = useMemo(
() => getOptionsFromKeys(attributeKeys, selectedColumnKeys),
[attributeKeys, selectedColumnKeys],
);
const handleSelectedColumnsChange = useCallback( const handleSelectedColumnsChange = useCallback(
(value: string[]) => { (value: string[]) => {
const newSelectedColumnKeys = [ const newSelectedColumnKeys = [
@ -135,8 +136,8 @@ const useOptionsMenu = ({
const optionsMenuConfig: Required<OptionsMenuConfig> = useMemo( const optionsMenuConfig: Required<OptionsMenuConfig> = useMemo(
() => ({ () => ({
addColumn: { addColumn: {
value: selectedColumnKeys || defaultOptionsQuery.selectColumns, value: optionsQueryData?.selectColumns || defaultOptionsQuery.selectColumns,
options: options || [], options: addColumnOptions || [],
onChange: handleSelectedColumnsChange, onChange: handleSelectedColumnsChange,
onRemove: handleRemoveSelectedColumn, onRemove: handleRemoveSelectedColumn,
}, },
@ -150,10 +151,10 @@ const useOptionsMenu = ({
}, },
}), }),
[ [
options, addColumnOptions,
selectedColumnKeys,
optionsQueryData?.maxLines, optionsQueryData?.maxLines,
optionsQueryData?.format, optionsQueryData?.format,
optionsQueryData?.selectColumns,
handleSelectedColumnsChange, handleSelectedColumnsChange,
handleRemoveSelectedColumn, handleRemoveSelectedColumn,
handleFormatChange, handleFormatChange,

View File

@ -3,12 +3,18 @@ import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteRe
export const getOptionsFromKeys = ( export const getOptionsFromKeys = (
keys: BaseAutocompleteData[], keys: BaseAutocompleteData[],
): SelectProps['options'] => selectedKeys: (string | undefined)[],
keys.map(({ id, key }) => ({ ): SelectProps['options'] => {
const options = keys.map(({ id, key }) => ({
label: key, label: key,
value: id, value: id,
})); }));
return options.filter(
({ value }) => !selectedKeys.find((key) => key === value),
);
};
export const getInitialColumns = ( export const getInitialColumns = (
initialColumnTitles: string[], initialColumnTitles: string[],
attributeKeys: BaseAutocompleteData[], attributeKeys: BaseAutocompleteData[],

View File

@ -230,19 +230,21 @@ export const Query = memo(function Query({
</Row> </Row>
</Col> </Col>
<Col span={11}> {panelType !== PANEL_TYPES.LIST && (
<Row gutter={[11, 5]}> <Col span={11}>
<Col flex="5.93rem"> <Row gutter={[11, 5]}>
<FilterLabel label="Aggregate Every" /> <Col flex="5.93rem">
</Col> <FilterLabel label="Aggregate Every" />
<Col flex="1 1 6rem"> </Col>
<AggregateEveryFilter <Col flex="1 1 6rem">
query={query} <AggregateEveryFilter
onChange={handleChangeAggregateEvery} query={query}
/> onChange={handleChangeAggregateEvery}
</Col> />
</Row> </Col>
</Col> </Row>
</Col>
)}
</> </>
); );
} }
@ -326,8 +328,11 @@ export const Query = memo(function Query({
</Col> </Col>
<Col flex="1 1 12.5rem"> <Col flex="1 1 12.5rem">
<AggregatorFilter <AggregatorFilter
onChange={handleChangeAggregatorAttribute}
query={query} query={query}
onChange={handleChangeAggregatorAttribute}
disabled={
panelType === PANEL_TYPES.LIST || panelType === PANEL_TYPES.TRACE
}
/> />
</Col> </Col>
</Row> </Row>
@ -362,14 +367,16 @@ export const Query = memo(function Query({
</AdditionalFiltersToggler> </AdditionalFiltersToggler>
</Col> </Col>
)} )}
<Row style={{ width: '100%' }}> {panelType !== PANEL_TYPES.LIST && panelType !== PANEL_TYPES.TRACE && (
<Input <Row style={{ width: '100%' }}>
onChange={handleChangeQueryLegend} <Input
size="middle" onChange={handleChangeQueryLegend}
value={query.legend} size="middle"
addonBefore="Legend Format" value={query.legend}
/> addonBefore="Legend Format"
</Row> />
</Row>
)}
</ListItemWrapper> </ListItemWrapper>
); );
}); });

View File

@ -1,7 +1,8 @@
import { AutoCompleteProps } from 'antd';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
export type AgregatorFilterProps = { export type AgregatorFilterProps = Pick<AutoCompleteProps, 'disabled'> & {
onChange: (value: BaseAutocompleteData) => void;
query: IBuilderQuery; query: IBuilderQuery;
onChange: (value: BaseAutocompleteData) => void;
}; };

View File

@ -28,8 +28,9 @@ import { selectStyle } from '../QueryBuilderSearch/config';
import { AgregatorFilterProps } from './AggregatorFilter.intefaces'; import { AgregatorFilterProps } from './AggregatorFilter.intefaces';
export const AggregatorFilter = memo(function AggregatorFilter({ export const AggregatorFilter = memo(function AggregatorFilter({
onChange,
query, query,
disabled,
onChange,
}: 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);
@ -119,6 +120,7 @@ export const AggregatorFilter = memo(function AggregatorFilter({
options={optionsData} options={optionsData}
value={value} value={value}
onChange={handleChangeAttribute} onChange={handleChangeAttribute}
disabled={disabled}
/> />
); );
}); });

View File

@ -18,6 +18,7 @@ import {
getLabelFromValue, getLabelFromValue,
mapLabelValuePairs, mapLabelValuePairs,
orderByValueDelimiter, orderByValueDelimiter,
transformToOrderByStringValues,
} from './utils'; } from './utils';
export function OrderByFilter({ export function OrderByFilter({
@ -25,7 +26,9 @@ 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<IOption[]>([]); const [selectedValue, setSelectedValue] = useState<IOption[]>(
transformToOrderByStringValues(query.orderBy) || [],
);
const { data, isFetching } = useQuery( const { data, isFetching } = useQuery(
[QueryBuilderKeys.GET_AGGREGATE_KEYS, searchText], [QueryBuilderKeys.GET_AGGREGATE_KEYS, searchText],

View File

@ -21,7 +21,7 @@ function TimeSeriesView({
}, },
], ],
}), }),
[data], [data?.payload?.data?.result],
); );
return ( return (

View File

@ -1,10 +1,7 @@
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { PANEL_TYPES_QUERY } from 'constants/queryBuilderQueryNames';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import useUrlQueryData from 'hooks/useUrlQueryData';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
import { DataSource } from 'types/common/queryBuilder'; import { DataSource } from 'types/common/queryBuilder';
@ -15,22 +12,17 @@ import TimeSeriesView from './TimeSeriesView';
function TimeSeriesViewContainer({ function TimeSeriesViewContainer({
dataSource = DataSource.TRACES, dataSource = DataSource.TRACES,
}: TimeSeriesViewProps): JSX.Element { }: TimeSeriesViewProps): JSX.Element {
const { stagedQuery } = useQueryBuilder(); const { stagedQuery, panelType } = useQueryBuilder();
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector< const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
AppState, AppState,
GlobalReducer GlobalReducer
>((state) => state.globalTime); >((state) => state.globalTime);
const { queryData: panelTypeParam } = useUrlQueryData<GRAPH_TYPES>(
PANEL_TYPES_QUERY,
PANEL_TYPES.TIME_SERIES,
);
const { data, isLoading, isError } = useGetQueryRange( const { data, isLoading, isError } = useGetQueryRange(
{ {
query: stagedQuery || initialQueriesMap[dataSource], query: stagedQuery || initialQueriesMap[dataSource],
graphType: panelTypeParam, graphType: panelType || PANEL_TYPES.TIME_SERIES,
selectedTime: 'GLOBAL_TIME', selectedTime: 'GLOBAL_TIME',
globalSelectedInterval: globalSelectedTime, globalSelectedInterval: globalSelectedTime,
params: { params: {
@ -45,7 +37,7 @@ function TimeSeriesViewContainer({
minTime, minTime,
stagedQuery, stagedQuery,
], ],
enabled: !!stagedQuery && panelTypeParam === PANEL_TYPES.TIME_SERIES, enabled: !!stagedQuery && panelType === PANEL_TYPES.TIME_SERIES,
}, },
); );

View File

@ -65,7 +65,8 @@ function ListView(): JSX.Element {
paginationQueryData, paginationQueryData,
options?.selectColumns, options?.selectColumns,
], ],
enabled: !!stagedQuery && panelType === PANEL_TYPES.LIST, enabled:
!!stagedQuery && panelType === PANEL_TYPES.LIST && !!options?.selectColumns,
}, },
); );

View File

@ -15,3 +15,7 @@ export const Container = styled.div`
export const ErrorText = styled(Typography)` export const ErrorText = styled(Typography)`
text-align: center; text-align: center;
`; `;
export const DateText = styled(Typography)`
min-width: 145px;
`;

View File

@ -9,6 +9,8 @@ import { RowData } from 'lib/query/createTableColumnsFromQuery';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { QueryDataV3 } from 'types/api/widgets/getQuery'; import { QueryDataV3 } from 'types/api/widgets/getQuery';
import { DateText } from './styles';
export const transformDataWithDate = (data: QueryDataV3[]): QueryDataV3[] => export const transformDataWithDate = (data: QueryDataV3[]): QueryDataV3[] =>
data.map((query) => ({ data.map((query) => ({
...query, ...query,
@ -78,9 +80,10 @@ export const modifyColumns = (
if (key === 'date') { if (key === 'date') {
return { return {
...column, ...column,
width: 145,
render: (date: string): JSX.Element => { render: (date: string): JSX.Element => {
const day = dayjs(date); const day = dayjs(date);
return <Typography>{day.format('YYYY/MM/DD HH:mm:ss')}</Typography>; return <DateText>{day.format('YYYY/MM/DD HH:mm:ss')}</DateText>;
}, },
}; };
} }

View File

@ -57,9 +57,16 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
); );
const getNewListOfAdditionalFilters = useCallback( const getNewListOfAdditionalFilters = useCallback(
(dataSource: DataSource): string[] => (dataSource: DataSource): string[] => {
mapOfFilters[dataSource].map((item) => item.text), const listOfFilters = mapOfFilters[dataSource].map((item) => item.text);
[],
if (panelType === PANEL_TYPES.LIST) {
return listOfFilters.filter((filter) => filter !== 'Aggregation interval');
}
return listOfFilters;
},
[panelType],
); );
const handleChangeAggregatorAttribute = useCallback( const handleChangeAggregatorAttribute = useCallback(

View File

@ -52,15 +52,26 @@ function TracesExplorer(): JSX.Element {
return groupByCount > 0; return groupByCount > 0;
}, [currentQuery]); }, [currentQuery]);
const defaultQuery = useMemo( const defaultQuery = useMemo(() => {
() => const query = updateAllQueriesOperators(
updateAllQueriesOperators( initialQueriesMap.traces,
initialQueriesMap.traces, PANEL_TYPES.LIST,
PANEL_TYPES.LIST, DataSource.TRACES,
DataSource.TRACES, );
),
[updateAllQueriesOperators], return {
); ...query,
builder: {
...query.builder,
queryData: [
{
...query.builder.queryData[0],
orderBy: [{ columnName: 'timestamp', order: 'desc' }],
},
],
},
};
}, [updateAllQueriesOperators]);
const tabsItems = getTabsItems({ const tabsItems = getTabsItems({
isListViewDisabled: isMultipleQueries || isGroupByExist, isListViewDisabled: isMultipleQueries || isGroupByExist,