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
This commit is contained in:
SagarRajput-7 2024-12-13 11:25:39 +05:30 committed by GitHub
parent 0fbfb6b22b
commit 8c46de8eac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 112 additions and 39 deletions

View File

@ -1,10 +1,9 @@
import axios from 'api'; import axios from 'api';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { import {
MessagingQueueServicePayload, MessagingQueueServicePayload,
MessagingQueuesPayloadProps, MessagingQueuesPayloadProps,
} from './getConsumerLagDetails'; } from 'pages/MessagingQueues/MQDetails/MQTables/getConsumerLagDetails';
import { ErrorResponse, SuccessResponse } from 'types/api';
export const getTopicThroughputOverview = async ( export const getTopicThroughputOverview = async (
props: Omit<MessagingQueueServicePayload, 'variables'>, props: Omit<MessagingQueueServicePayload, 'variables'>,

View File

@ -108,13 +108,6 @@ const checkValidityOfDetailConfigs = (
return false; return false;
} }
if (currentTab === MessagingQueueServiceDetailType.ProducerDetails) {
return Boolean(
configDetails?.topic &&
configDetails?.partition &&
configDetails?.service_name,
);
}
return Boolean(configDetails?.topic && configDetails?.service_name); return Boolean(configDetails?.topic && configDetails?.service_name);
} }

View File

@ -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;
}

View File

@ -32,6 +32,7 @@ import {
MessagingQueueServicePayload, MessagingQueueServicePayload,
MessagingQueuesPayloadProps, MessagingQueuesPayloadProps,
} from './getConsumerLagDetails'; } from './getConsumerLagDetails';
import { getTableDataForProducerLatencyOverview } from './MQTableUtils';
const INITIAL_PAGE_SIZE = 10; const INITIAL_PAGE_SIZE = 10;
@ -39,16 +40,24 @@ const INITIAL_PAGE_SIZE = 10;
export function getColumns( export function getColumns(
data: MessagingQueuesPayloadProps['payload'], data: MessagingQueuesPayloadProps['payload'],
history: History<unknown>, history: History<unknown>,
isProducerOverview?: boolean,
): RowData[] { ): RowData[] {
if (data?.result?.length === 0) { if (data?.result?.length === 0) {
return []; return [];
} }
const mergedColumns = isProducerOverview
? [
...(data?.result?.[0]?.table?.columns || []),
{ name: 'byte_rate', queryName: 'byte_rate' },
]
: data?.result?.[0]?.table?.columns;
const columns: { const columns: {
title: string; title: string;
dataIndex: string; dataIndex: string;
key: string; key: string;
}[] = data?.result?.[0]?.table?.columns.map((column) => ({ }[] = mergedColumns.map((column) => ({
title: convertToTitleCase(column.name), title: convertToTitleCase(column.name),
dataIndex: column.name, dataIndex: column.name,
key: column.name, key: column.name,
@ -58,6 +67,8 @@ export function getColumns(
'throughput', 'throughput',
'avg_msg_size', 'avg_msg_size',
'error_percentage', 'error_percentage',
'ingestion_rate',
'byte_rate',
].includes(column.name) ].includes(column.name)
? (value: number | string): string => { ? (value: number | string): string => {
if (!isNumber(value)) return value.toString(); 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( const { mutate: getViewDetails, isLoading, error, isError } = useMutation(
tableApi, tableApi,
{ {
onSuccess: (data) => { onSuccess: (data) => {
if (data.payload) { if (data.payload) {
setColumns(getColumns(data?.payload, history)); setColumns(getColumns(data?.payload, history, isProducerOverview));
setTableData(getTableData(data?.payload)); setTableData(
isProducerOverview
? getTableDataForProducerLatencyOverview(data?.payload)
: getTableData(data?.payload),
);
} }
}, },
onError: handleConsumerDetailsOnError, onError: handleConsumerDetailsOnError,
@ -199,15 +222,29 @@ function MessagingQueuesTable({
const [, setSelectedRows] = useState<any>(); const [, setSelectedRows] = useState<any>();
const location = useLocation(); const location = useLocation();
const onRowClick = (record: { [key: string]: string }): void => { const selectedRowKeyGenerator = (record: {
const selectedKey = record.key; [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); setSelectedRowKey(undefined);
setSelectedRows({}); setSelectedRows({});
setConfigDetail(urlQuery, location, history, {}); setConfigDetail(urlQuery, location, history, {});
} else { } else {
setSelectedRowKey(`${selectedKey}_${selectedView}`); setSelectedRowKey(selectedRowKeyGenerator(record));
setSelectedRows(record); setSelectedRows(record);
if (!isEmpty(record)) { if (!isEmpty(record)) {
@ -267,7 +304,7 @@ function MessagingQueuesTable({
: {} : {}
} }
rowClassName={(record): any => rowClassName={(record): any =>
`${record.key}_${selectedView}` === selectedRowKey selectedRowKeyGenerator(record) === selectedRowKey
? 'ant-table-row-selected' ? 'ant-table-row-selected'
: '' : ''
} }

View File

@ -1,8 +1,11 @@
import './MQDetails.style.scss'; import './MQDetails.style.scss';
import { Radio } from 'antd'; 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 { useSelector } from 'react-redux';
import { useHistory, useLocation } from 'react-router-dom';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
@ -10,25 +13,32 @@ import {
MessagingQueuesViewType, MessagingQueuesViewType,
MessagingQueuesViewTypeOptions, MessagingQueuesViewTypeOptions,
ProducerLatencyOptions, ProducerLatencyOptions,
setConfigDetail,
} from '../MessagingQueuesUtils'; } from '../MessagingQueuesUtils';
import { MessagingQueueServicePayload } from './MQTables/getConsumerLagDetails'; import { MessagingQueueServicePayload } from './MQTables/getConsumerLagDetails';
import { getKafkaSpanEval } from './MQTables/getKafkaSpanEval'; import { getKafkaSpanEval } from './MQTables/getKafkaSpanEval';
import { getPartitionLatencyOverview } from './MQTables/getPartitionLatencyOverview'; import { getPartitionLatencyOverview } from './MQTables/getPartitionLatencyOverview';
import { getTopicThroughputOverview } from './MQTables/getTopicThroughputOverview';
import MessagingQueuesTable from './MQTables/MQTables'; import MessagingQueuesTable from './MQTables/MQTables';
type SelectedViewType = keyof typeof MessagingQueuesViewType; type SelectedViewType = keyof typeof MessagingQueuesViewType;
function PartitionLatencyTabs({ function ProducerLatencyTabs({
option, option,
setOption, setOption,
}: { }: {
option: ProducerLatencyOptions; option: ProducerLatencyOptions;
setOption: Dispatch<SetStateAction<ProducerLatencyOptions>>; setOption: Dispatch<SetStateAction<ProducerLatencyOptions>>;
}): JSX.Element { }): JSX.Element {
const urlQuery = useUrlQuery();
const location = useLocation();
const history = useHistory();
return ( return (
<Radio.Group <Radio.Group
onChange={(e): void => setOption(e.target.value)} onChange={(e): void => {
setConfigDetail(urlQuery, location, history, {});
setOption(e.target.value);
}}
value={option} value={option}
className="mq-details-options" className="mq-details-options"
> >
@ -71,27 +81,26 @@ function MessagingQueueOverview({
(state) => state.globalTime, (state) => state.globalTime,
); );
const tableApiPayload: MessagingQueueServicePayload = { const tableApiPayload: MessagingQueueServicePayload = useMemo(
variables: {}, () => ({
start: minTime, variables: {},
end: maxTime, start: minTime,
detailType: end: maxTime,
// eslint-disable-next-line no-nested-ternary detailType:
selectedView === MessagingQueuesViewType.producerLatency.value // eslint-disable-next-line no-nested-ternary
? option === ProducerLatencyOptions.Producers selectedView === MessagingQueuesViewType.producerLatency.value
? 'producer' ? option === ProducerLatencyOptions.Producers
: 'consumer' ? 'producer'
: undefined, : 'consumer'
evalTime: : undefined,
selectedView === MessagingQueuesViewType.dropRate.value }),
? 2363404 [minTime, maxTime, selectedView, option],
: undefined, );
};
return ( return (
<div className="mq-overview-container"> <div className="mq-overview-container">
{selectedView === MessagingQueuesViewType.producerLatency.value ? ( {selectedView === MessagingQueuesViewType.producerLatency.value ? (
<PartitionLatencyTabs option={option} setOption={setOption} /> <ProducerLatencyTabs option={option} setOption={setOption} />
) : ( ) : (
<div className="mq-overview-title"> <div className="mq-overview-title">
{MessagingQueuesViewType[selectedView as SelectedViewType].label} {MessagingQueuesViewType[selectedView as SelectedViewType].label}