From bcc55f4479baa3d146edbaa7892157d435016e15 Mon Sep 17 00:00:00 2001 From: SagarRajput-7 Date: Tue, 10 Dec 2024 10:46:22 +0530 Subject: [PATCH] feat: consumed new 2 table merging logic for producer latency overview --- .../getTopicThroughputOverview.ts | 14 +-- .../MessagingQueues/MQDetails/MQDetails.tsx | 7 -- .../MQDetails/MQTables/MQTableUtils.tsx | 111 +++++------------- .../MQDetails/MQTables/MQTables.tsx | 91 +++++++------- .../MQDetails/MessagingQueueOverview.tsx | 47 +++++--- 5 files changed, 104 insertions(+), 166 deletions(-) rename frontend/src/{pages/MessagingQueues/MQDetails/MQTables => api/messagingQueues}/getTopicThroughputOverview.ts (69%) diff --git a/frontend/src/pages/MessagingQueues/MQDetails/MQTables/getTopicThroughputOverview.ts b/frontend/src/api/messagingQueues/getTopicThroughputOverview.ts similarity index 69% rename from frontend/src/pages/MessagingQueues/MQDetails/MQTables/getTopicThroughputOverview.ts rename to frontend/src/api/messagingQueues/getTopicThroughputOverview.ts index 0edcf54413f..072f5eccf2f 100644 --- a/frontend/src/pages/MessagingQueues/MQDetails/MQTables/getTopicThroughputOverview.ts +++ b/frontend/src/api/messagingQueues/getTopicThroughputOverview.ts @@ -1,22 +1,14 @@ import axios from 'api'; -import { ErrorResponse, SuccessResponse } from 'types/api'; - import { MessagingQueueServicePayload, MessagingQueuesPayloadProps, -} from './getConsumerLagDetails'; -import { TopicThroughputProducerOverviewResponse } from './MQTableUtils'; +} from 'pages/MessagingQueues/MQDetails/MQTables/getConsumerLagDetails'; +import { ErrorResponse, SuccessResponse } from 'types/api'; export const getTopicThroughputOverview = async ( props: Omit, ): Promise< - | SuccessResponse< - ( - | MessagingQueuesPayloadProps - | TopicThroughputProducerOverviewResponse - )['payload'] - > - | ErrorResponse + SuccessResponse | ErrorResponse > => { const { detailType, start, end } = props; const response = await axios.post( diff --git a/frontend/src/pages/MessagingQueues/MQDetails/MQDetails.tsx b/frontend/src/pages/MessagingQueues/MQDetails/MQDetails.tsx index 9f30fbbd00b..7eab107e590 100644 --- a/frontend/src/pages/MessagingQueues/MQDetails/MQDetails.tsx +++ b/frontend/src/pages/MessagingQueues/MQDetails/MQDetails.tsx @@ -108,13 +108,6 @@ const checkValidityOfDetailConfigs = ( return false; } - if (currentTab === MessagingQueueServiceDetailType.ProducerDetails) { - return Boolean( - configDetails?.topic && - configDetails?.partition && - configDetails?.service_name, - ); - } return Boolean(configDetails?.topic && configDetails?.service_name); } diff --git a/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTableUtils.tsx b/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTableUtils.tsx index 99818fb5cf3..1671baf7f93 100644 --- a/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTableUtils.tsx +++ b/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTableUtils.tsx @@ -1,92 +1,35 @@ -import { Typography } from 'antd'; -import dayjs from 'dayjs'; -import { History } from 'history'; -import { - convertToTitleCase, - RowData, -} from 'pages/MessagingQueues/MessagingQueuesUtils'; +import { RowData } from 'pages/MessagingQueues/MessagingQueuesUtils'; -interface ProducerLatencyOverviewColumn { - timestamp: string; - data: { - [key: string]: number | string; - }; -} - -export interface TopicThroughputProducerOverviewResponse { - status: string; - payload: { - resultType: string; - result: { - queryName: string; - list: ProducerLatencyOverviewColumn[]; - }[]; - }; -} +import { MessagingQueuesPayloadProps } from './getConsumerLagDetails'; -export const getColumnsForProducerLatencyOverview = ( - list: ProducerLatencyOverviewColumn[], - history: History, -): RowData[] => { - if (list?.length === 0) { +export function getTableDataForProducerLatencyOverview( + data: MessagingQueuesPayloadProps['payload'], +): RowData[] { + if (data?.result?.length === 0) { return []; } - const columns: { - title: string; - dataIndex: string; - key: string; - }[] = Object.keys(list[0].data)?.map((column) => ({ - title: convertToTitleCase(column), - dataIndex: column, - key: column, - render: (data: string | number): JSX.Element => { - if (column === 'service_name') { - return ( - { - e.preventDefault(); - e.stopPropagation(); - history.push(`/services/${encodeURIComponent(data as string)}`); - }} - > - {data} - - ); - } - - if (column === 'ts') { - const date = - typeof data === 'string' - ? dayjs(data).format('YYYY-MM-DD HH:mm:ss.SSS') - : dayjs(data / 1e6).format('YYYY-MM-DD HH:mm:ss.SSS'); - return {date}; - } - - if (typeof data === 'number') { - return {data.toFixed(3)}; - } - - return {data}; - }, - })); + const firstTableData = data.result[0].table.rows || []; + const secondTableData = data.result[1]?.table.rows || []; - return columns; -}; - -export const getTableDataForProducerLatencyOverview = ( - list: ProducerLatencyOverviewColumn[], -): RowData[] => { - if (list?.length === 0) { - return []; - } - - const tableData: RowData[] = list?.map( - (row, index: number): RowData => ({ - ...row.data, - key: index, - }), + // Create a map for quick lookup of byte_rate using service_name and topic + const byteRateMap = new Map( + secondTableData.map((row) => [ + `${row.data.service_name}--${row.data.topic}`, + row.data.byte_rate, + ]), ); - return tableData; -}; + // Merge the data from both tables + const mergedTableData: RowData[] = + firstTableData.map( + (row, index): RowData => ({ + ...row.data, + byte_rate: + byteRateMap.get(`${row.data.service_name}--${row.data.topic}`) || 0, + key: index, + }), + ) || []; + + return mergedTableData; +} diff --git a/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTables.tsx b/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTables.tsx index 34c945190f2..d839db1068c 100644 --- a/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTables.tsx +++ b/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTables.tsx @@ -32,11 +32,7 @@ import { MessagingQueueServicePayload, MessagingQueuesPayloadProps, } from './getConsumerLagDetails'; -import { - getColumnsForProducerLatencyOverview, - getTableDataForProducerLatencyOverview, - TopicThroughputProducerOverviewResponse, -} from './MQTableUtils'; +import { getTableDataForProducerLatencyOverview } from './MQTableUtils'; const INITIAL_PAGE_SIZE = 10; @@ -44,16 +40,24 @@ const INITIAL_PAGE_SIZE = 10; export function getColumns( data: MessagingQueuesPayloadProps['payload'], history: History, + isProducerOverview?: boolean, ): RowData[] { if (data?.result?.length === 0) { return []; } + const mergedColumns = isProducerOverview + ? [ + ...(data?.result?.[0]?.table?.columns || []), + { name: 'byte_rate', queryName: 'byte_rate' }, + ] + : data?.result?.[0]?.table?.columns; + const columns: { title: string; dataIndex: string; key: string; - }[] = data?.result?.[0]?.table?.columns.map((column) => ({ + }[] = mergedColumns.map((column) => ({ title: convertToTitleCase(column.name), dataIndex: column.name, key: column.name, @@ -131,13 +135,7 @@ function MessagingQueuesTable({ tableApi: ( props: MessagingQueueServicePayload, ) => Promise< - | SuccessResponse< - ( - | MessagingQueuesPayloadProps - | TopicThroughputProducerOverviewResponse - )['payload'] - > - | ErrorResponse + SuccessResponse | ErrorResponse >; validConfigPresent?: boolean; type?: 'Detail' | 'Overview'; @@ -183,40 +181,25 @@ function MessagingQueuesTable({ }); }; + const isProducerOverview = useMemo( + () => + type === 'Overview' && + selectedView === MessagingQueuesViewType.producerLatency.value && + tableApiPayload?.detailType === 'producer', + [type, selectedView, tableApiPayload], + ); + const { mutate: getViewDetails, isLoading, error, isError } = useMutation( tableApi, { onSuccess: (data) => { if (data.payload) { - if ( - type === 'Overview' && - selectedView === MessagingQueuesViewType.producerLatency.value && - tableApiPayload?.detailType === 'producer' - ) { - setColumns( - getColumnsForProducerLatencyOverview( - (data?.payload as TopicThroughputProducerOverviewResponse['payload']) - .result[0].list, - history, - ), - ); - setTableData( - getTableDataForProducerLatencyOverview( - (data?.payload as TopicThroughputProducerOverviewResponse['payload']) - .result[0].list, - ), - ); - } else { - setColumns( - getColumns( - data?.payload as MessagingQueuesPayloadProps['payload'], - history, - ), - ); - setTableData( - getTableData(data?.payload as MessagingQueuesPayloadProps['payload']), - ); - } + setColumns(getColumns(data?.payload, history, isProducerOverview)); + setTableData( + isProducerOverview + ? getTableDataForProducerLatencyOverview(data?.payload) + : getTableData(data?.payload), + ); } }, onError: handleConsumerDetailsOnError, @@ -237,15 +220,29 @@ function MessagingQueuesTable({ const [, setSelectedRows] = useState(); const location = useLocation(); - const onRowClick = (record: { [key: string]: string }): void => { - const selectedKey = record.key; + const selectedRowKeyGenerator = (record: { + [key: string]: string; + }): React.Key => { + if (!isEmpty(tableApiPayload?.detailType)) { + return `${record.key}_${selectedView}_${tableApiPayload?.detailType}`; + } + return `${record.key}_${selectedView}`; + }; - if (`${selectedKey}_${selectedView}` === selectedRowKey) { + useEffect(() => { + if (isEmpty(configDetailQueryData)) { + setSelectedRowKey(undefined); + setSelectedRows({}); + } + }, [configDetailQueryData]); + + const onRowClick = (record: { [key: string]: string }): void => { + if (selectedRowKeyGenerator(record) === selectedRowKey) { setSelectedRowKey(undefined); setSelectedRows({}); setConfigDetail(urlQuery, location, history, {}); } else { - setSelectedRowKey(`${selectedKey}_${selectedView}`); + setSelectedRowKey(selectedRowKeyGenerator(record)); setSelectedRows(record); if (!isEmpty(record)) { @@ -305,7 +302,7 @@ function MessagingQueuesTable({ : {} } rowClassName={(record): any => - `${record.key}_${selectedView}` === selectedRowKey + selectedRowKeyGenerator(record) === selectedRowKey ? 'ant-table-row-selected' : '' } diff --git a/frontend/src/pages/MessagingQueues/MQDetails/MessagingQueueOverview.tsx b/frontend/src/pages/MessagingQueues/MQDetails/MessagingQueueOverview.tsx index 5e3b752a33b..c4c9cfb2537 100644 --- a/frontend/src/pages/MessagingQueues/MQDetails/MessagingQueueOverview.tsx +++ b/frontend/src/pages/MessagingQueues/MQDetails/MessagingQueueOverview.tsx @@ -1,8 +1,11 @@ import './MQDetails.style.scss'; import { Radio } from 'antd'; -import { Dispatch, SetStateAction } from 'react'; +import { getTopicThroughputOverview } from 'api/messagingQueues/getTopicThroughputOverview'; +import useUrlQuery from 'hooks/useUrlQuery'; +import { Dispatch, SetStateAction, useMemo } from 'react'; import { useSelector } from 'react-redux'; +import { useHistory, useLocation } from 'react-router-dom'; import { AppState } from 'store/reducers'; import { GlobalReducer } from 'types/reducer/globalTime'; @@ -10,25 +13,32 @@ import { MessagingQueuesViewType, MessagingQueuesViewTypeOptions, ProducerLatencyOptions, + setConfigDetail, } from '../MessagingQueuesUtils'; import { MessagingQueueServicePayload } from './MQTables/getConsumerLagDetails'; import { getKafkaSpanEval } from './MQTables/getKafkaSpanEval'; import { getPartitionLatencyOverview } from './MQTables/getPartitionLatencyOverview'; -import { getTopicThroughputOverview } from './MQTables/getTopicThroughputOverview'; import MessagingQueuesTable from './MQTables/MQTables'; type SelectedViewType = keyof typeof MessagingQueuesViewType; -function PartitionLatencyTabs({ +function ProducerLatencyTabs({ option, setOption, }: { option: ProducerLatencyOptions; setOption: Dispatch>; }): JSX.Element { + const urlQuery = useUrlQuery(); + const location = useLocation(); + const history = useHistory(); + return ( setOption(e.target.value)} + onChange={(e): void => { + setConfigDetail(urlQuery, location, history, {}); + setOption(e.target.value); + }} value={option} className="mq-details-options" > @@ -71,23 +81,26 @@ function MessagingQueueOverview({ (state) => state.globalTime, ); - const tableApiPayload: MessagingQueueServicePayload = { - variables: {}, - start: minTime, - end: maxTime, - detailType: - // eslint-disable-next-line no-nested-ternary - selectedView === MessagingQueuesViewType.producerLatency.value - ? option === ProducerLatencyOptions.Producers - ? 'producer' - : 'consumer' - : undefined, - }; + const tableApiPayload: MessagingQueueServicePayload = useMemo( + () => ({ + variables: {}, + start: minTime, + end: maxTime, + detailType: + // eslint-disable-next-line no-nested-ternary + selectedView === MessagingQueuesViewType.producerLatency.value + ? option === ProducerLatencyOptions.Producers + ? 'producer' + : 'consumer' + : undefined, + }), + [minTime, maxTime, selectedView, option], + ); return (
{selectedView === MessagingQueuesViewType.producerLatency.value ? ( - + ) : (
{MessagingQueuesViewType[selectedView as SelectedViewType].label}