chore: summary view fixes

This commit is contained in:
amlannandy 2025-06-02 17:58:54 +07:00 committed by Amlan Kumar Nandy
parent 61b2f8cb31
commit f713040b9c
8 changed files with 104 additions and 168 deletions

View File

@ -10,24 +10,21 @@ import {
} from 'antd';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useGetMetricsListFilterValues } from 'hooks/metricsExplorer/useGetMetricsListFilterValues';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
import useDebouncedFn from 'hooks/useDebouncedFunction';
import { Search } from 'lucide-react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useSearchParams } from 'react-router-dom-v5-compat';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { COMPOSITE_QUERY_KEY } from './constants';
import { SUMMARY_FILTERS_KEY } from './constants';
function MetricNameSearch(): JSX.Element {
const { currentQuery } = useQueryBuilder();
const { handleChangeQueryData } = useQueryOperations({
index: 0,
query: currentQuery.builder.queryData[0],
entityVersion: '',
});
const [, setSearchParams] = useSearchParams();
function MetricNameSearch({
queryFilters,
}: {
queryFilters: TagFilter;
}): JSX.Element {
const [searchParams, setSearchParams] = useSearchParams();
const [isPopoverOpen, setIsPopoverOpen] = useState<boolean>(false);
const [searchString, setSearchString] = useState<string>('');
@ -70,9 +67,9 @@ function MetricNameSearch(): JSX.Element {
const handleSelect = useCallback(
(selectedMetricName: string): void => {
const newFilter = {
const newFilters = {
items: [
...currentQuery.builder.queryData[0].filters.items,
...queryFilters.items,
{
id: 'metric_name',
op: 'CONTAINS',
@ -84,27 +81,15 @@ function MetricNameSearch(): JSX.Element {
value: selectedMetricName,
},
],
op: 'AND',
op: 'and',
};
const compositeQuery = {
...currentQuery,
builder: {
...currentQuery.builder,
queryData: [
{
...currentQuery.builder.queryData[0],
filters: newFilter,
},
],
},
};
handleChangeQueryData('filters', newFilter);
setSearchParams({
[COMPOSITE_QUERY_KEY]: JSON.stringify(compositeQuery),
...Object.fromEntries(searchParams.entries()),
[SUMMARY_FILTERS_KEY]: JSON.stringify(newFilters),
});
setIsPopoverOpen(false);
},
[currentQuery, handleChangeQueryData, setSearchParams],
[queryFilters.items, setSearchParams, searchParams],
);
const metricNameFilterValues = useMemo(
@ -198,7 +183,7 @@ function MetricNameSearch(): JSX.Element {
const handleInputChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>): void => {
const value = e.target.value.trim().toLowerCase();
const value = e.target.value.trim();
setSearchString(value);
debouncedUpdate(value);
},

View File

@ -1,26 +1,23 @@
import { Button, Menu, Popover, Tooltip } from 'antd';
import { MetricType } from 'api/metricsExplorer/getMetricsList';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
import { Search } from 'lucide-react';
import { useCallback, useMemo, useState } from 'react';
import { useSearchParams } from 'react-router-dom-v5-compat';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import {
COMPOSITE_QUERY_KEY,
METRIC_TYPE_LABEL_MAP,
METRIC_TYPE_VALUES_MAP,
SUMMARY_FILTERS_KEY,
} from './constants';
function MetricTypeSearch(): JSX.Element {
const { currentQuery } = useQueryBuilder();
const { handleChangeQueryData } = useQueryOperations({
index: 0,
query: currentQuery.builder.queryData[0],
entityVersion: '',
});
function MetricTypeSearch({
queryFilters,
}: {
queryFilters: TagFilter;
}): JSX.Element {
const [searchParams, setSearchParams] = useSearchParams();
const [, setSearchParams] = useSearchParams();
const [isPopoverOpen, setIsPopoverOpen] = useState<boolean>(false);
const menuItems = useMemo(
@ -40,9 +37,9 @@ function MetricTypeSearch(): JSX.Element {
const handleSelect = useCallback(
(selectedMetricType: string): void => {
if (selectedMetricType !== 'all') {
const newFilter = {
const newFilters = {
items: [
...currentQuery.builder.queryData[0].filters.items,
...queryFilters.items,
{
id: 'metric_type',
op: '=',
@ -56,49 +53,23 @@ function MetricTypeSearch(): JSX.Element {
],
op: 'AND',
};
const compositeQuery = {
...currentQuery,
builder: {
...currentQuery.builder,
queryData: [
{
...currentQuery.builder.queryData[0],
filters: newFilter,
},
],
},
};
handleChangeQueryData('filters', newFilter);
setSearchParams({
[COMPOSITE_QUERY_KEY]: JSON.stringify(compositeQuery),
...Object.fromEntries(searchParams.entries()),
[SUMMARY_FILTERS_KEY]: JSON.stringify(newFilters),
});
} else {
const newFilter = {
items: currentQuery.builder.queryData[0].filters.items.filter(
(item) => item.id !== 'metric_type',
),
const newFilters = {
items: queryFilters.items.filter((item) => item.id !== 'metric_type'),
op: 'AND',
};
const compositeQuery = {
...currentQuery,
builder: {
...currentQuery.builder,
queryData: [
{
...currentQuery.builder.queryData[0],
filters: newFilter,
},
],
},
};
handleChangeQueryData('filters', newFilter);
setSearchParams({
[COMPOSITE_QUERY_KEY]: JSON.stringify(compositeQuery),
...Object.fromEntries(searchParams.entries()),
[SUMMARY_FILTERS_KEY]: JSON.stringify(newFilters),
});
}
setIsPopoverOpen(false);
},
[currentQuery, handleChangeQueryData, setSearchParams],
[queryFilters.items, setSearchParams, searchParams],
);
const menu = (

View File

@ -12,7 +12,7 @@ import { Info } from 'lucide-react';
import { useCallback } from 'react';
import { MetricsListItemRowData, MetricsTableProps } from './types';
import { metricsTableColumns } from './utils';
import { getMetricsTableColumns } from './utils';
function MetricsTable({
isLoading,
@ -24,6 +24,7 @@ function MetricsTable({
setOrderBy,
totalCount,
openMetricDetails,
queryFilters,
}: MetricsTableProps): JSX.Element {
const handleTableChange: TableProps<MetricsListItemRowData>['onChange'] = useCallback(
(
@ -74,7 +75,7 @@ function MetricsTable({
),
}}
dataSource={data}
columns={metricsTableColumns}
columns={getMetricsTableColumns(queryFilters)}
locale={{
emptyText: isLoading ? null : (
<div

View File

@ -1,29 +1,25 @@
import './Summary.styles.scss';
import * as Sentry from '@sentry/react';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { initialQueriesMap } from 'constants/queryBuilder';
import { usePageSize } from 'container/InfraMonitoringK8s/utils';
import { useGetMetricsList } from 'hooks/metricsExplorer/useGetMetricsList';
import { useGetMetricsTreeMap } from 'hooks/metricsExplorer/useGetMetricsTreeMap';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { useCallback, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { useSearchParams } from 'react-router-dom-v5-compat';
import { AppState } from 'store/reducers';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { GlobalReducer } from 'types/reducer/globalTime';
import InspectModal from '../Inspect';
import MetricDetails from '../MetricDetails';
import {
COMPOSITE_QUERY_KEY,
IS_INSPECT_MODAL_OPEN_KEY,
IS_METRIC_DETAILS_OPEN_KEY,
SELECTED_METRIC_NAME_KEY,
SUMMARY_FILTERS_KEY,
} from './constants';
import MetricsSearch from './MetricsSearch';
import MetricsTable from './MetricsTable';
@ -63,57 +59,25 @@ function Summary(): JSX.Element {
(state) => state.globalTime,
);
const { currentQuery, updateAllQueriesOperators } = useQueryBuilder();
const defaultQuery = useMemo(() => {
const query = updateAllQueriesOperators(
initialQueriesMap.metrics,
PANEL_TYPES.LIST,
DataSource.METRICS,
);
const queryFilters: TagFilter = useMemo(() => {
const encodedFilters = searchParams.get(SUMMARY_FILTERS_KEY);
if (encodedFilters) {
return JSON.parse(encodedFilters);
}
return {
...query,
builder: {
...query.builder,
queryData: [
{
...query.builder.queryData[0],
orderBy: [DEFAULT_ORDER_BY],
},
],
},
items: [],
op: 'AND',
};
}, [updateAllQueriesOperators]);
useShareBuilderUrl(defaultQuery);
}, [searchParams]);
// This is used to avoid the filters from being serialized with the id
const currentQueryFiltersString = useMemo(() => {
const filters = currentQuery?.builder?.queryData[0]?.filters;
if (!filters) return '';
const queryFiltersWithoutId = useMemo(() => {
const filtersWithoutId = {
...filters,
items: filters.items.map(({ id, ...rest }) => rest),
...queryFilters,
items: queryFilters.items.map(({ id, ...rest }) => rest),
};
return JSON.stringify(filtersWithoutId);
}, [currentQuery]);
const queryFilters = useMemo(
() =>
currentQuery?.builder?.queryData[0]?.filters || {
items: [],
op: 'and',
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[currentQueryFiltersString],
);
const { handleChangeQueryData } = useQueryOperations({
index: 0,
query: currentQuery.builder.queryData[0],
entityVersion: '',
});
}, [queryFilters]);
const metricsListQuery = useMemo(() => {
const baseQuery = getMetricsListQuery();
@ -146,6 +110,15 @@ function Summary(): JSX.Element {
isError: isMetricsError,
} = useGetMetricsList(metricsListQuery, {
enabled: !!metricsListQuery && !isInspectModalOpen,
queryKey: [
'metricsList',
queryFiltersWithoutId,
orderBy,
pageSize,
currentPage,
minTime,
maxTime,
],
});
const isListViewError = useMemo(
@ -160,6 +133,13 @@ function Summary(): JSX.Element {
isError: isTreeMapError,
} = useGetMetricsTreeMap(metricsTreemapQuery, {
enabled: !!metricsTreemapQuery && !isInspectModalOpen,
queryKey: [
'metricsTreemap',
queryFiltersWithoutId,
heatmapView,
minTime,
maxTime,
],
});
const isProportionViewError = useMemo(
@ -169,48 +149,23 @@ function Summary(): JSX.Element {
const handleFilterChange = useCallback(
(value: TagFilter) => {
handleChangeQueryData('filters', value);
const compositeQuery = {
...currentQuery,
builder: {
...currentQuery.builder,
queryData: [
{
...currentQuery.builder.queryData[0],
filters: value,
},
],
},
};
setSearchParams({
[COMPOSITE_QUERY_KEY]: JSON.stringify(compositeQuery),
...Object.fromEntries(searchParams.entries()),
[SUMMARY_FILTERS_KEY]: JSON.stringify(value),
});
setCurrentPage(1);
},
[handleChangeQueryData, currentQuery, setSearchParams],
[setSearchParams, searchParams],
);
const updatedCurrentQuery = useMemo(
const searchQuery = useMemo(
() => ({
...currentQuery,
builder: {
...currentQuery.builder,
queryData: [
{
...currentQuery.builder.queryData[0],
aggregateOperator: 'noop',
aggregateAttribute: {
...currentQuery.builder.queryData[0].aggregateAttribute,
},
},
],
},
...initialQueriesMap.metrics.builder.queryData[0],
filters: queryFilters,
}),
[currentQuery],
[queryFilters],
);
const searchQuery = updatedCurrentQuery?.builder?.queryData[0] || null;
const onPaginationChange = (page: number, pageSize: number): void => {
setCurrentPage(page);
setPageSize(pageSize);
@ -225,6 +180,7 @@ function Summary(): JSX.Element {
setSelectedMetricName(metricName);
setIsMetricDetailsOpen(true);
setSearchParams({
...Object.fromEntries(searchParams.entries()),
[IS_METRIC_DETAILS_OPEN_KEY]: 'true',
[SELECTED_METRIC_NAME_KEY]: metricName,
});
@ -234,6 +190,7 @@ function Summary(): JSX.Element {
setSelectedMetricName(null);
setIsMetricDetailsOpen(false);
setSearchParams({
...Object.fromEntries(searchParams.entries()),
[IS_METRIC_DETAILS_OPEN_KEY]: 'false',
[SELECTED_METRIC_NAME_KEY]: '',
});
@ -244,19 +201,17 @@ function Summary(): JSX.Element {
setIsInspectModalOpen(true);
setIsMetricDetailsOpen(false);
setSearchParams({
...Object.fromEntries(searchParams.entries()),
[IS_INSPECT_MODAL_OPEN_KEY]: 'true',
[SELECTED_METRIC_NAME_KEY]: metricName,
});
};
const closeInspectModal = (): void => {
handleChangeQueryData('filters', {
items: [],
op: 'AND',
});
setIsInspectModalOpen(false);
setSelectedMetricName(null);
setSearchParams({
...Object.fromEntries(searchParams.entries()),
[IS_INSPECT_MODAL_OPEN_KEY]: 'false',
[SELECTED_METRIC_NAME_KEY]: '',
});
@ -284,6 +239,7 @@ function Summary(): JSX.Element {
setOrderBy={setOrderBy}
totalCount={metricsData?.payload?.data?.total || 0}
openMetricDetails={openMetricDetails}
queryFilters={queryFilters}
/>
</div>
{isMetricDetailsOpen && (

View File

@ -36,4 +36,4 @@ export const METRIC_TYPE_VALUES_MAP = {
export const IS_METRIC_DETAILS_OPEN_KEY = 'isMetricDetailsOpen';
export const IS_INSPECT_MODAL_OPEN_KEY = 'isInspectModalOpen';
export const SELECTED_METRIC_NAME_KEY = 'selectedMetricName';
export const COMPOSITE_QUERY_KEY = 'compositeQuery';
export const SUMMARY_FILTERS_KEY = 'summaryFilters';

View File

@ -15,6 +15,7 @@ export interface MetricsTableProps {
setOrderBy: Dispatch<SetStateAction<OrderByPayload>>;
totalCount: number;
openMetricDetails: (metricName: string) => void;
queryFilters: TagFilter;
}
export interface MetricsSearchProps {

View File

@ -18,18 +18,21 @@ import {
Gauge,
} from 'lucide-react';
import { useMemo } from 'react';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { METRIC_TYPE_LABEL_MAP } from './constants';
import MetricNameSearch from './MetricNameSearch';
import MetricTypeSearch from './MetricTypeSearch';
import { MetricsListItemRowData, TreemapTile, TreemapViewType } from './types';
export const metricsTableColumns: ColumnType<MetricsListItemRowData>[] = [
export const getMetricsTableColumns = (
queryFilters: TagFilter,
): ColumnType<MetricsListItemRowData>[] => [
{
title: (
<div className="metric-name-column-header">
<span className="metric-name-column-header-text">METRIC</span>
<MetricNameSearch />
<MetricNameSearch queryFilters={queryFilters} />
</div>
),
dataIndex: 'metric_name',
@ -51,7 +54,7 @@ export const metricsTableColumns: ColumnType<MetricsListItemRowData>[] = [
title: (
<div className="metric-type-column-header">
<span className="metric-type-column-header-text">TYPE</span>
<MetricTypeSearch />
<MetricTypeSearch queryFilters={queryFilters} />
</div>
),
dataIndex: 'metric_type',

View File

@ -2,8 +2,13 @@ import './MetricsExplorerPage.styles.scss';
import RouteTab from 'components/RouteTab';
import { TabRoutes } from 'components/RouteTab/types';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import history from 'lib/history';
import { useMemo } from 'react';
import { useLocation } from 'react-use';
import { DataSource } from 'types/common/queryBuilder';
import { Explorer, Summary, Views } from './constants';
@ -12,6 +17,20 @@ function MetricsExplorerPage(): JSX.Element {
const routes: TabRoutes[] = [Summary, Explorer, Views];
const { updateAllQueriesOperators } = useQueryBuilder();
const defaultQuery = useMemo(
() =>
updateAllQueriesOperators(
initialQueriesMap[DataSource.METRICS],
PANEL_TYPES.LIST,
DataSource.METRICS,
),
[updateAllQueriesOperators],
);
useShareBuilderUrl(defaultQuery);
return (
<div className="metrics-explorer-page">
<RouteTab routes={routes} activeKey={pathname} history={history} />