mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 05:19:04 +08:00
fix: added support for group by sorting in endpoints table
This commit is contained in:
parent
6504f2565b
commit
7edb047c0c
@ -1,5 +1,13 @@
|
|||||||
import { LoadingOutlined } from '@ant-design/icons';
|
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 logEvent from 'api/common/logEvent';
|
||||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
@ -53,6 +61,11 @@ function AllEndPoints({
|
|||||||
{ value: string; label: string }[]
|
{ value: string; label: string }[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
|
const [orderBy, setOrderBy] = useState<{
|
||||||
|
columnName: string;
|
||||||
|
order: 'asc' | 'desc';
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
const [expandedRowKeys, setExpandedRowKeys] = useState<React.Key[]>([]);
|
const [expandedRowKeys, setExpandedRowKeys] = useState<React.Key[]>([]);
|
||||||
|
|
||||||
const handleGroupByChange = useCallback(
|
const handleGroupByChange = useCallback(
|
||||||
@ -137,6 +150,7 @@ function AllEndPoints({
|
|||||||
selectedRowData={record}
|
selectedRowData={record}
|
||||||
setSelectedEndPointName={setSelectedEndPointName}
|
setSelectedEndPointName={setSelectedEndPointName}
|
||||||
setSelectedView={setSelectedView}
|
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(
|
const formattedEndPointsData = useMemo(
|
||||||
() =>
|
() =>
|
||||||
formatEndPointsDataForTable(
|
formatEndPointsDataForTable(
|
||||||
allEndPointsData?.payload?.data?.result[0]?.table?.rows,
|
allEndPointsData?.payload?.data?.result[0]?.table?.rows,
|
||||||
groupBy,
|
groupBy,
|
||||||
|
orderBy,
|
||||||
),
|
),
|
||||||
[groupBy, allEndPointsData],
|
[groupBy, allEndPointsData, orderBy],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
@ -232,6 +267,7 @@ function AllEndPoints({
|
|||||||
rowClassName={(_, index): string =>
|
rowClassName={(_, index): string =>
|
||||||
index % 2 === 0 ? 'table-row-dark' : 'table-row-light'
|
index % 2 === 0 ? 'table-row-dark' : 'table-row-light'
|
||||||
}
|
}
|
||||||
|
onChange={handleTableChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,6 +19,7 @@ import { useSelector } from 'react-redux';
|
|||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { SuccessResponse } from 'types/api';
|
import { SuccessResponse } from 'types/api';
|
||||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
|
import { OrderByPayload } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
import { VIEW_TYPES, VIEWS } from '../constants';
|
import { VIEW_TYPES, VIEWS } from '../constants';
|
||||||
@ -28,11 +29,13 @@ function ExpandedRow({
|
|||||||
selectedRowData,
|
selectedRowData,
|
||||||
setSelectedEndPointName,
|
setSelectedEndPointName,
|
||||||
setSelectedView,
|
setSelectedView,
|
||||||
|
orderBy,
|
||||||
}: {
|
}: {
|
||||||
domainName: string;
|
domainName: string;
|
||||||
selectedRowData: EndPointsTableRowData;
|
selectedRowData: EndPointsTableRowData;
|
||||||
setSelectedEndPointName: (name: string) => void;
|
setSelectedEndPointName: (name: string) => void;
|
||||||
setSelectedView: (view: VIEWS) => void;
|
setSelectedView: (view: VIEWS) => void;
|
||||||
|
orderBy: OrderByPayload | null;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const nestedColumns = useMemo(() => getEndPointsColumnsConfig(false, []), []);
|
const nestedColumns = useMemo(() => getEndPointsColumnsConfig(false, []), []);
|
||||||
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||||
@ -100,6 +103,7 @@ function ExpandedRow({
|
|||||||
? formatEndPointsDataForTable(
|
? formatEndPointsDataForTable(
|
||||||
groupedByRowQuery.data?.payload.data.result[0].table?.rows,
|
groupedByRowQuery.data?.payload.data.result[0].table?.rows,
|
||||||
[],
|
[],
|
||||||
|
orderBy,
|
||||||
)
|
)
|
||||||
: []
|
: []
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
import {
|
import {
|
||||||
IBuilderQuery,
|
IBuilderQuery,
|
||||||
|
OrderByPayload,
|
||||||
TagFilterItem,
|
TagFilterItem,
|
||||||
} from 'types/api/queryBuilder/queryBuilderData';
|
} from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { QueryData } from 'types/api/widgets/getQuery';
|
import { QueryData } from 'types/api/widgets/getQuery';
|
||||||
@ -676,16 +677,6 @@ export const getEndPointsColumnsConfig = (
|
|||||||
key: 'callCount',
|
key: 'callCount',
|
||||||
width: 180,
|
width: 180,
|
||||||
ellipsis: true,
|
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',
|
align: 'right',
|
||||||
className: `column`,
|
className: `column`,
|
||||||
},
|
},
|
||||||
@ -698,18 +689,7 @@ export const getEndPointsColumnsConfig = (
|
|||||||
dataIndex: 'errorRate',
|
dataIndex: 'errorRate',
|
||||||
key: 'errorRate',
|
key: 'errorRate',
|
||||||
width: 120,
|
width: 120,
|
||||||
sorter: (
|
sorter: true,
|
||||||
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);
|
|
||||||
},
|
|
||||||
align: 'right',
|
align: 'right',
|
||||||
className: `column`,
|
className: `column`,
|
||||||
render: (
|
render: (
|
||||||
@ -746,17 +726,7 @@ export const getEndPointsColumnsConfig = (
|
|||||||
dataIndex: 'latency',
|
dataIndex: 'latency',
|
||||||
key: 'latency',
|
key: 'latency',
|
||||||
width: 120,
|
width: 120,
|
||||||
sorter: (
|
sorter: true,
|
||||||
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);
|
|
||||||
},
|
|
||||||
align: 'right',
|
align: 'right',
|
||||||
className: `column`,
|
className: `column`,
|
||||||
},
|
},
|
||||||
@ -765,22 +735,7 @@ export const getEndPointsColumnsConfig = (
|
|||||||
dataIndex: 'lastUsed',
|
dataIndex: 'lastUsed',
|
||||||
key: 'lastUsed',
|
key: 'lastUsed',
|
||||||
width: 120,
|
width: 120,
|
||||||
sorter: (
|
sorter: true,
|
||||||
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();
|
|
||||||
},
|
|
||||||
align: 'right',
|
align: 'right',
|
||||||
className: `column`,
|
className: `column`,
|
||||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||||
@ -794,12 +749,16 @@ export const getEndPointsColumnsConfig = (
|
|||||||
export const formatEndPointsDataForTable = (
|
export const formatEndPointsDataForTable = (
|
||||||
data: EndPointsResponseRow[] | undefined,
|
data: EndPointsResponseRow[] | undefined,
|
||||||
groupBy: BaseAutocompleteData[],
|
groupBy: BaseAutocompleteData[],
|
||||||
|
orderBy?: OrderByPayload | null,
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
): EndPointsTableRowData[] => {
|
): EndPointsTableRowData[] => {
|
||||||
if (!data) return [];
|
if (!data) return [];
|
||||||
const isGroupedByAttribute = groupBy.length > 0;
|
const isGroupedByAttribute = groupBy.length > 0;
|
||||||
|
|
||||||
|
let formattedData: EndPointsTableRowData[] = [];
|
||||||
|
|
||||||
if (!isGroupedByAttribute) {
|
if (!isGroupedByAttribute) {
|
||||||
return data?.map((endpoint) => {
|
formattedData = data?.map((endpoint) => {
|
||||||
const { port } = extractPortAndEndpoint(
|
const { port } = extractPortAndEndpoint(
|
||||||
(endpoint.data['http.url'] as string) || '',
|
(endpoint.data['http.url'] as string) || '',
|
||||||
);
|
);
|
||||||
@ -826,11 +785,10 @@ export const formatEndPointsDataForTable = (
|
|||||||
: Number(endpoint.data.F1),
|
: Number(endpoint.data.F1),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
|
|
||||||
const groupedByAttributeData = groupBy.map((attribute) => attribute.key);
|
const groupedByAttributeData = groupBy.map((attribute) => attribute.key);
|
||||||
|
|
||||||
return data?.map((endpoint) => {
|
formattedData = data?.map((endpoint) => {
|
||||||
const newEndpointName = groupedByAttributeData
|
const newEndpointName = groupedByAttributeData
|
||||||
.map((attribute) => endpoint.data[attribute])
|
.map((attribute) => endpoint.data[attribute])
|
||||||
.join(',');
|
.join(',');
|
||||||
@ -859,6 +817,47 @@ export const formatEndPointsDataForTable = (
|
|||||||
}, {} as Record<string, string | number>),
|
}, {} as Record<string, string | number>),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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 = (
|
export const createFiltersForSelectedRowData = (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user