Skip to content

Commit

Permalink
feat: consumed new 2 table merging logic for producer latency overview
Browse files Browse the repository at this point in the history
  • Loading branch information
SagarRajput-7 committed Dec 10, 2024
1 parent 8de3782 commit bcc55f4
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 166 deletions.
Original file line number Diff line number Diff line change
@@ -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<MessagingQueueServicePayload, 'variables'>,
): Promise<
| SuccessResponse<
(
| MessagingQueuesPayloadProps
| TopicThroughputProducerOverviewResponse
)['payload']
>
| ErrorResponse
SuccessResponse<MessagingQueuesPayloadProps['payload']> | ErrorResponse
> => {
const { detailType, start, end } = props;
const response = await axios.post(
Expand Down
7 changes: 0 additions & 7 deletions frontend/src/pages/MessagingQueues/MQDetails/MQDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
111 changes: 27 additions & 84 deletions frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTableUtils.tsx
Original file line number Diff line number Diff line change
@@ -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<unknown>,
): 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 (
<Typography.Link
onClick={(e): void => {
e.preventDefault();
e.stopPropagation();
history.push(`/services/${encodeURIComponent(data as string)}`);
}}
>
{data}
</Typography.Link>
);
}

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 <Typography.Text>{date}</Typography.Text>;
}

if (typeof data === 'number') {
return <Typography.Text>{data.toFixed(3)}</Typography.Text>;
}

return <Typography.Text>{data}</Typography.Text>;
},
}));
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;
}
91 changes: 44 additions & 47 deletions frontend/src/pages/MessagingQueues/MQDetails/MQTables/MQTables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,32 @@ import {
MessagingQueueServicePayload,
MessagingQueuesPayloadProps,
} from './getConsumerLagDetails';
import {
getColumnsForProducerLatencyOverview,
getTableDataForProducerLatencyOverview,
TopicThroughputProducerOverviewResponse,
} from './MQTableUtils';
import { getTableDataForProducerLatencyOverview } from './MQTableUtils';

const INITIAL_PAGE_SIZE = 10;

// eslint-disable-next-line sonarjs/cognitive-complexity
export function getColumns(
data: MessagingQueuesPayloadProps['payload'],
history: History<unknown>,
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,
Expand Down Expand Up @@ -131,13 +135,7 @@ function MessagingQueuesTable({
tableApi: (
props: MessagingQueueServicePayload,
) => Promise<
| SuccessResponse<
(
| MessagingQueuesPayloadProps
| TopicThroughputProducerOverviewResponse
)['payload']
>
| ErrorResponse
SuccessResponse<MessagingQueuesPayloadProps['payload']> | ErrorResponse
>;
validConfigPresent?: boolean;
type?: 'Detail' | 'Overview';
Expand Down Expand Up @@ -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,
Expand All @@ -237,15 +220,29 @@ function MessagingQueuesTable({
const [, setSelectedRows] = useState<any>();
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)) {
Expand Down Expand Up @@ -305,7 +302,7 @@ function MessagingQueuesTable({
: {}
}
rowClassName={(record): any =>
`${record.key}_${selectedView}` === selectedRowKey
selectedRowKeyGenerator(record) === selectedRowKey
? 'ant-table-row-selected'
: ''
}
Expand Down
Loading

0 comments on commit bcc55f4

Please sign in to comment.