fix: added support for group by sorting in endpoints table

This commit is contained in:
sawhil 2025-04-24 01:01:54 +05:30 committed by Sahil Khan
parent 6504f2565b
commit 7edb047c0c
3 changed files with 121 additions and 82 deletions

View File

@ -1,5 +1,13 @@
import { LoadingOutlined } from '@ant-design/icons';
import { Select, Spin, Table, Typography } from 'antd';
import {
Select,
Spin,
Table,
TablePaginationConfig,
TableProps,
Typography,
} from 'antd';
import { SorterResult } from 'antd/lib/table/interface';
import logEvent from 'api/common/logEvent';
import { ENTITY_VERSION_V4 } from 'constants/app';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
@ -53,6 +61,11 @@ function AllEndPoints({
{ value: string; label: string }[]
>([]);
const [orderBy, setOrderBy] = useState<{
columnName: string;
order: 'asc' | 'desc';
} | null>(null);
const [expandedRowKeys, setExpandedRowKeys] = useState<React.Key[]>([]);
const handleGroupByChange = useCallback(
@ -137,6 +150,7 @@ function AllEndPoints({
selectedRowData={record}
setSelectedEndPointName={setSelectedEndPointName}
setSelectedView={setSelectedView}
orderBy={orderBy}
/>
);
@ -158,13 +172,34 @@ function AllEndPoints({
}
};
const handleTableChange: TableProps<EndPointsTableRowData>['onChange'] = useCallback(
(
_pagination: TablePaginationConfig,
_filters: Record<string, (string | number | boolean)[] | null>,
sorter:
| SorterResult<EndPointsTableRowData>
| SorterResult<EndPointsTableRowData>[],
): void => {
if ('field' in sorter && sorter.order) {
setOrderBy({
columnName: sorter.field as string,
order: sorter.order === 'ascend' ? 'asc' : 'desc',
});
} else {
setOrderBy(null);
}
},
[],
);
const formattedEndPointsData = useMemo(
() =>
formatEndPointsDataForTable(
allEndPointsData?.payload?.data?.result[0]?.table?.rows,
groupBy,
orderBy,
),
[groupBy, allEndPointsData],
[groupBy, allEndPointsData, orderBy],
);
if (isError) {
@ -232,6 +267,7 @@ function AllEndPoints({
rowClassName={(_, index): string =>
index % 2 === 0 ? 'table-row-dark' : 'table-row-light'
}
onChange={handleTableChange}
/>
</div>
</div>

View File

@ -19,6 +19,7 @@ import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { SuccessResponse } from 'types/api';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { OrderByPayload } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime';
import { VIEW_TYPES, VIEWS } from '../constants';
@ -28,11 +29,13 @@ function ExpandedRow({
selectedRowData,
setSelectedEndPointName,
setSelectedView,
orderBy,
}: {
domainName: string;
selectedRowData: EndPointsTableRowData;
setSelectedEndPointName: (name: string) => void;
setSelectedView: (view: VIEWS) => void;
orderBy: OrderByPayload | null;
}): JSX.Element {
const nestedColumns = useMemo(() => getEndPointsColumnsConfig(false, []), []);
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
@ -100,6 +103,7 @@ function ExpandedRow({
? formatEndPointsDataForTable(
groupedByRowQuery.data?.payload.data.result[0].table?.rows,
[],
orderBy,
)
: []
}

View File

@ -24,6 +24,7 @@ import {
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import {
IBuilderQuery,
OrderByPayload,
TagFilterItem,
} from 'types/api/queryBuilder/queryBuilderData';
import { QueryData } from 'types/api/widgets/getQuery';
@ -676,16 +677,6 @@ export const getEndPointsColumnsConfig = (
key: 'callCount',
width: 180,
ellipsis: true,
sorter: (
rowA: EndPointsTableRowData,
rowB: EndPointsTableRowData,
): number => {
const callCountA =
rowA.callCount === '-' || rowA.callCount === 'n/a' ? 0 : rowA.callCount;
const callCountB =
rowB.callCount === '-' || rowB.callCount === 'n/a' ? 0 : rowB.callCount;
return Number(callCountA) - Number(callCountB);
},
align: 'right',
className: `column`,
},
@ -698,18 +689,7 @@ export const getEndPointsColumnsConfig = (
dataIndex: 'errorRate',
key: 'errorRate',
width: 120,
sorter: (
rowA: EndPointsTableRowData,
rowB: EndPointsTableRowData,
// eslint-disable-next-line sonarjs/no-identical-functions
): number => {
const errorRateA =
rowA.errorRate === '-' || rowA.errorRate === 'n/a' ? 0 : rowA.errorRate;
const errorRateB =
rowB.errorRate === '-' || rowB.errorRate === 'n/a' ? 0 : rowB.errorRate;
return Number(errorRateA) - Number(errorRateB);
},
sorter: true,
align: 'right',
className: `column`,
render: (
@ -746,17 +726,7 @@ export const getEndPointsColumnsConfig = (
dataIndex: 'latency',
key: 'latency',
width: 120,
sorter: (
rowA: EndPointsTableRowData,
rowB: EndPointsTableRowData,
// eslint-disable-next-line sonarjs/no-identical-functions
): number => {
const latencyA =
rowA.latency === '-' || rowA.latency === 'n/a' ? 0 : rowA.latency;
const latencyB =
rowB.latency === '-' || rowB.latency === 'n/a' ? 0 : rowB.latency;
return Number(latencyA) - Number(latencyB);
},
sorter: true,
align: 'right',
className: `column`,
},
@ -765,22 +735,7 @@ export const getEndPointsColumnsConfig = (
dataIndex: 'lastUsed',
key: 'lastUsed',
width: 120,
sorter: (
rowA: EndPointsTableRowData,
rowB: EndPointsTableRowData,
// eslint-disable-next-line sonarjs/no-identical-functions
): number => {
const dateA =
rowA.lastUsed === '-' || rowA.lastUsed === 'n/a'
? new Date(0).toISOString()
: rowA.lastUsed;
const dateB =
rowB.lastUsed === '-' || rowB.lastUsed === 'n/a'
? new Date(0).toISOString()
: rowB.lastUsed;
return new Date(dateB).getTime() - new Date(dateA).getTime();
},
sorter: true,
align: 'right',
className: `column`,
// eslint-disable-next-line sonarjs/no-identical-functions
@ -794,12 +749,16 @@ export const getEndPointsColumnsConfig = (
export const formatEndPointsDataForTable = (
data: EndPointsResponseRow[] | undefined,
groupBy: BaseAutocompleteData[],
orderBy?: OrderByPayload | null,
// eslint-disable-next-line sonarjs/cognitive-complexity
): EndPointsTableRowData[] => {
if (!data) return [];
const isGroupedByAttribute = groupBy.length > 0;
let formattedData: EndPointsTableRowData[] = [];
if (!isGroupedByAttribute) {
return data?.map((endpoint) => {
formattedData = data?.map((endpoint) => {
const { port } = extractPortAndEndpoint(
(endpoint.data['http.url'] as string) || '',
);
@ -826,39 +785,79 @@ export const formatEndPointsDataForTable = (
: Number(endpoint.data.F1),
};
});
} else {
const groupedByAttributeData = groupBy.map((attribute) => attribute.key);
formattedData = data?.map((endpoint) => {
const newEndpointName = groupedByAttributeData
.map((attribute) => endpoint.data[attribute])
.join(',');
return {
key: v4(),
endpointName: newEndpointName,
callCount:
endpoint.data.A === 'n/a' || endpoint.data.A === undefined
? '-'
: endpoint.data.A,
latency:
endpoint.data.B === 'n/a' || endpoint.data.B === undefined
? '-'
: Math.round(Number(endpoint.data.B) / 1000000), // Convert from nanoseconds to milliseconds
lastUsed:
endpoint.data.C === 'n/a' || endpoint.data.C === undefined
? '-'
: getLastUsedRelativeTime(Math.floor(Number(endpoint.data.C) / 1000000)), // Convert from nanoseconds to milliseconds
errorRate:
endpoint.data.D === 'n/a' || endpoint.data.D === undefined
? 0
: Number(endpoint.data.D),
groupedByMeta: groupedByAttributeData.reduce((acc, attribute) => {
acc[attribute] = endpoint.data[attribute] || '';
return acc;
}, {} as Record<string, string | number>),
};
});
}
const groupedByAttributeData = groupBy.map((attribute) => attribute.key);
// Apply sorting if orderBy is provided
if (orderBy) {
formattedData.sort((a, b) => {
let valueA: number | string = a[
orderBy.columnName as keyof EndPointsTableRowData
] as number | string;
let valueB: number | string = b[
orderBy.columnName as keyof EndPointsTableRowData
] as number | string;
return data?.map((endpoint) => {
const newEndpointName = groupedByAttributeData
.map((attribute) => endpoint.data[attribute])
.join(',');
return {
key: v4(),
endpointName: newEndpointName,
callCount:
endpoint.data.A === 'n/a' || endpoint.data.A === undefined
? '-'
: endpoint.data.A,
latency:
endpoint.data.B === 'n/a' || endpoint.data.B === undefined
? '-'
: Math.round(Number(endpoint.data.B) / 1000000), // Convert from nanoseconds to milliseconds
lastUsed:
endpoint.data.C === 'n/a' || endpoint.data.C === undefined
? '-'
: getLastUsedRelativeTime(Math.floor(Number(endpoint.data.C) / 1000000)), // Convert from nanoseconds to milliseconds
errorRate:
endpoint.data.D === 'n/a' || endpoint.data.D === undefined
? 0
: Number(endpoint.data.D),
groupedByMeta: groupedByAttributeData.reduce((acc, attribute) => {
acc[attribute] = endpoint.data[attribute] || '';
return acc;
}, {} as Record<string, string | number>),
};
});
// Handle special cases for each column type
if (
orderBy.columnName === 'callCount' ||
orderBy.columnName === 'latency' ||
orderBy.columnName === 'errorRate'
) {
valueA = valueA === '-' || valueA === 'n/a' ? 0 : Number(valueA);
valueB = valueB === '-' || valueB === 'n/a' ? 0 : Number(valueB);
} else if (orderBy.columnName === 'lastUsed') {
// confirm once the implication of this
valueA =
valueA === '-' || valueA === 'n/a'
? new Date(0).getTime()
: new Date(valueA as string).getTime();
valueB =
valueB === '-' || valueB === 'n/a'
? new Date(0).getTime()
: new Date(valueB as string).getTime();
}
// Apply sort direction
if (orderBy.order === 'asc') {
return valueA > valueB ? 1 : -1;
}
return valueA < valueB ? 1 : -1;
});
}
return formattedData;
};
export const createFiltersForSelectedRowData = (