From 8c46de8eacd867b28ef490de9f5869b7a3dd7fc3 Mon Sep 17 00:00:00 2001 From: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:25:39 +0530 Subject: [PATCH] feat: added table column and row logic for the new api response structure for producer overview (#6433) * feat: added table column and row logic for the new api response structure for prodcure overview * feat: fixed typo in function name * feat: consumed new 2 table merging logic for producer latency overview * feat: added 3 digit precision to 'ingestion_rate' and 'byte_rate'in consumer overview --- .../getTopicThroughputOverview.ts | 5 +- .../MessagingQueues/MQDetails/MQDetails.tsx | 7 --- .../MQDetails/MQTables/MQTableUtils.tsx | 35 ++++++++++++ .../MQDetails/MQTables/MQTables.tsx | 53 ++++++++++++++++--- .../MQDetails/MessagingQueueOverview.tsx | 51 ++++++++++-------- 5 files changed, 112 insertions(+), 39 deletions(-) rename frontend/src/{pages/MessagingQueues/MQDetails/MQTables => api/messagingQueues}/getTopicThroughputOverview.ts (89%) create mode 100644 frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTableUtils.tsx diff --git a/frontend/src/pages/MessagingQueues/MQDetails/MQTables/getTopicThroughputOverview.ts b/frontend/src/api/messagingQueues/getTopicThroughputOverview.ts similarity index 89% rename from frontend/src/pages/MessagingQueues/MQDetails/MQTables/getTopicThroughputOverview.ts rename to frontend/src/api/messagingQueues/getTopicThroughputOverview.ts index ac955e8405..072f5eccf2 100644 --- a/frontend/src/pages/MessagingQueues/MQDetails/MQTables/getTopicThroughputOverview.ts +++ b/frontend/src/api/messagingQueues/getTopicThroughputOverview.ts @@ -1,10 +1,9 @@ import axios from 'api'; -import { ErrorResponse, SuccessResponse } from 'types/api'; - import { MessagingQueueServicePayload, MessagingQueuesPayloadProps, -} from './getConsumerLagDetails'; +} from 'pages/MessagingQueues/MQDetails/MQTables/getConsumerLagDetails'; +import { ErrorResponse, SuccessResponse } from 'types/api'; export const getTopicThroughputOverview = async ( props: Omit, diff --git a/frontend/src/pages/MessagingQueues/MQDetails/MQDetails.tsx b/frontend/src/pages/MessagingQueues/MQDetails/MQDetails.tsx index 9f30fbbd00..7eab107e59 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 new file mode 100644 index 0000000000..1671baf7f9 --- /dev/null +++ b/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTableUtils.tsx @@ -0,0 +1,35 @@ +import { RowData } from 'pages/MessagingQueues/MessagingQueuesUtils'; + +import { MessagingQueuesPayloadProps } from './getConsumerLagDetails'; + +export function getTableDataForProducerLatencyOverview( + data: MessagingQueuesPayloadProps['payload'], +): RowData[] { + if (data?.result?.length === 0) { + return []; + } + + const firstTableData = data.result[0].table.rows || []; + const secondTableData = data.result[1]?.table.rows || []; + + // 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, + ]), + ); + + // 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 73fd1b2f41..d4ee82b8b7 100644 --- a/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTables.tsx +++ b/frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTables.tsx @@ -32,6 +32,7 @@ import { MessagingQueueServicePayload, MessagingQueuesPayloadProps, } from './getConsumerLagDetails'; +import { getTableDataForProducerLatencyOverview } from './MQTableUtils'; const INITIAL_PAGE_SIZE = 10; @@ -39,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, @@ -58,6 +67,8 @@ export function getColumns( 'throughput', 'avg_msg_size', 'error_percentage', + 'ingestion_rate', + 'byte_rate', ].includes(column.name) ? (value: number | string): string => { if (!isNumber(value)) return value.toString(); @@ -172,13 +183,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) { - setColumns(getColumns(data?.payload, history)); - setTableData(getTableData(data?.payload)); + setColumns(getColumns(data?.payload, history, isProducerOverview)); + setTableData( + isProducerOverview + ? getTableDataForProducerLatencyOverview(data?.payload) + : getTableData(data?.payload), + ); } }, onError: handleConsumerDetailsOnError, @@ -199,15 +222,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}`; + }; + + useEffect(() => { + if (isEmpty(configDetailQueryData)) { + setSelectedRowKey(undefined); + setSelectedRows({}); + } + }, [configDetailQueryData]); - if (`${selectedKey}_${selectedView}` === selectedRowKey) { + 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)) { @@ -267,7 +304,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 ea55384ac3..c4c9cfb253 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,27 +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, - evalTime: - selectedView === MessagingQueuesViewType.dropRate.value - ? 2363404 - : 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}