mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 15:39:06 +08:00
feat: added kafka - scenario - 4 - drop rate table (#6380)
* feat: added kafka - scenario - 4 - drop rate table * feat: added api, new table and traceid redirection * feat: code refactor
This commit is contained in:
parent
e623c92615
commit
abe0ab69b0
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable no-nested-ternary */
|
||||||
import '../MessagingQueues.styles.scss';
|
import '../MessagingQueues.styles.scss';
|
||||||
|
|
||||||
import { Select, Typography } from 'antd';
|
import { Select, Typography } from 'antd';
|
||||||
@ -15,6 +16,7 @@ import {
|
|||||||
MessagingQueuesViewTypeOptions,
|
MessagingQueuesViewTypeOptions,
|
||||||
ProducerLatencyOptions,
|
ProducerLatencyOptions,
|
||||||
} from '../MessagingQueuesUtils';
|
} from '../MessagingQueuesUtils';
|
||||||
|
import DropRateView from '../MQDetails/DropRateView/DropRateView';
|
||||||
import MessagingQueueOverview from '../MQDetails/MessagingQueueOverview';
|
import MessagingQueueOverview from '../MQDetails/MessagingQueueOverview';
|
||||||
import MessagingQueuesDetails from '../MQDetails/MQDetails';
|
import MessagingQueuesDetails from '../MQDetails/MQDetails';
|
||||||
import MessagingQueuesConfigOptions from '../MQGraph/MQConfigOptions';
|
import MessagingQueuesConfigOptions from '../MQGraph/MQConfigOptions';
|
||||||
@ -103,26 +105,28 @@ function MQDetailPage(): JSX.Element {
|
|||||||
</div>
|
</div>
|
||||||
<DateTimeSelectionV2 showAutoRefresh={false} hideShareModal />
|
<DateTimeSelectionV2 showAutoRefresh={false} hideShareModal />
|
||||||
</div>
|
</div>
|
||||||
<div className="messaging-queue-main-graph">
|
{selectedView === MessagingQueuesViewType.consumerLag.value ? (
|
||||||
<MessagingQueuesConfigOptions />
|
<div className="messaging-queue-main-graph">
|
||||||
{selectedView === MessagingQueuesViewType.consumerLag.value ? (
|
<MessagingQueuesConfigOptions />
|
||||||
<MessagingQueuesGraph />
|
<MessagingQueuesGraph />
|
||||||
) : (
|
</div>
|
||||||
<MessagingQueueOverview
|
) : selectedView === MessagingQueuesViewType.dropRate.value ? (
|
||||||
selectedView={selectedView}
|
<DropRateView />
|
||||||
option={producerLatencyOption}
|
) : (
|
||||||
setOption={setproducerLatencyOption}
|
<MessagingQueueOverview
|
||||||
/>
|
selectedView={selectedView}
|
||||||
)}
|
option={producerLatencyOption}
|
||||||
</div>
|
setOption={setproducerLatencyOption}
|
||||||
<div className="messaging-queue-details">
|
/>
|
||||||
{selectedView !== MessagingQueuesViewType.dropRate.value && (
|
)}
|
||||||
|
{selectedView !== MessagingQueuesViewType.dropRate.value && (
|
||||||
|
<div className="messaging-queue-details">
|
||||||
<MessagingQueuesDetails
|
<MessagingQueuesDetails
|
||||||
selectedView={selectedView}
|
selectedView={selectedView}
|
||||||
producerLatencyOption={producerLatencyOption}
|
producerLatencyOption={producerLatencyOption}
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
.evaluation-time-selector {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.eval-title {
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 28px;
|
||||||
|
color: var(--bg-vanilla-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-selector {
|
||||||
|
background-color: var(--bg-ink-400);
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-dropdown-render {
|
||||||
|
padding: 8px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 200px;
|
||||||
|
margin: 6px;
|
||||||
|
}
|
@ -0,0 +1,251 @@
|
|||||||
|
/* eslint-disable sonarjs/no-duplicate-string */
|
||||||
|
import '../MQDetails.style.scss';
|
||||||
|
|
||||||
|
import { Table, Typography } from 'antd';
|
||||||
|
import axios from 'axios';
|
||||||
|
import cx from 'classnames';
|
||||||
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
|
import { isNumber } from 'lodash-es';
|
||||||
|
import {
|
||||||
|
convertToTitleCase,
|
||||||
|
MessagingQueuesViewType,
|
||||||
|
RowData,
|
||||||
|
} from 'pages/MessagingQueues/MessagingQueuesUtils';
|
||||||
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { useMutation } from 'react-query';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
|
import { MessagingQueueServicePayload } from '../MQTables/getConsumerLagDetails';
|
||||||
|
import { getKafkaSpanEval } from '../MQTables/getKafkaSpanEval';
|
||||||
|
import {
|
||||||
|
convertToMilliseconds,
|
||||||
|
DropRateAPIResponse,
|
||||||
|
DropRateResponse,
|
||||||
|
} from './dropRateViewUtils';
|
||||||
|
import EvaluationTimeSelector from './EvaluationTimeSelector';
|
||||||
|
|
||||||
|
export function getTableData(data: DropRateResponse[]): RowData[] {
|
||||||
|
if (data?.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableData: RowData[] =
|
||||||
|
data?.map(
|
||||||
|
(row: DropRateResponse, index: number): RowData => ({
|
||||||
|
...(row.data as any), // todo-sagar
|
||||||
|
key: index,
|
||||||
|
}),
|
||||||
|
) || [];
|
||||||
|
|
||||||
|
return tableData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
|
export function getColumns(
|
||||||
|
data: DropRateResponse[],
|
||||||
|
visibleCounts: Record<number, number>,
|
||||||
|
handleShowMore: (index: number) => void,
|
||||||
|
): any[] {
|
||||||
|
if (data?.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const columnsOrder = [
|
||||||
|
'producer_service',
|
||||||
|
'consumer_service',
|
||||||
|
'breach_percentage',
|
||||||
|
'top_traceIDs',
|
||||||
|
'breached_spans',
|
||||||
|
'total_spans',
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns: {
|
||||||
|
title: string;
|
||||||
|
dataIndex: string;
|
||||||
|
key: string;
|
||||||
|
}[] = columnsOrder.map((column) => ({
|
||||||
|
title: convertToTitleCase(column),
|
||||||
|
dataIndex: column,
|
||||||
|
key: column,
|
||||||
|
render: (
|
||||||
|
text: string | string[],
|
||||||
|
_record: any,
|
||||||
|
index: number,
|
||||||
|
): JSX.Element => {
|
||||||
|
if (Array.isArray(text)) {
|
||||||
|
const visibleCount = visibleCounts[index] || 4;
|
||||||
|
const visibleItems = text.slice(0, visibleCount);
|
||||||
|
const remainingCount = (text || []).length - visibleCount;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="trace-id-list">
|
||||||
|
{visibleItems.map((item, idx) => {
|
||||||
|
const shouldShowMore = remainingCount > 0 && idx === visibleCount - 1;
|
||||||
|
return (
|
||||||
|
<div key={item} className="traceid-style">
|
||||||
|
<Typography.Text
|
||||||
|
key={item}
|
||||||
|
className="traceid-text"
|
||||||
|
onClick={(): void => {
|
||||||
|
window.open(`${ROUTES.TRACE}/${item}`, '_blank');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</Typography.Text>
|
||||||
|
{shouldShowMore && (
|
||||||
|
<Typography
|
||||||
|
onClick={(): void => handleShowMore(index)}
|
||||||
|
className="remaing-count"
|
||||||
|
>
|
||||||
|
+ {remainingCount} more
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (column === 'consumer_service' || column === 'producer_service') {
|
||||||
|
return (
|
||||||
|
<Typography.Link
|
||||||
|
onClick={(e): void => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
window.open(`/services/${encodeURIComponent(text)}`, '_blank');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Typography.Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (column === 'breach_percentage' && text) {
|
||||||
|
if (!isNumber(text))
|
||||||
|
return <Typography.Text>{text.toString()}</Typography.Text>;
|
||||||
|
return (
|
||||||
|
<Typography.Text>
|
||||||
|
{(typeof text === 'string' ? parseFloat(text) : text).toFixed(2)} %
|
||||||
|
</Typography.Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Typography.Text>{text}</Typography.Text>;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
const showPaginationItem = (total: number, range: number[]): JSX.Element => (
|
||||||
|
<>
|
||||||
|
<Typography.Text className="numbers">
|
||||||
|
{range[0]} — {range[1]}
|
||||||
|
</Typography.Text>
|
||||||
|
<Typography.Text className="total"> of {total}</Typography.Text>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
function DropRateView(): JSX.Element {
|
||||||
|
const [columns, setColumns] = useState<any[]>([]);
|
||||||
|
const [tableData, setTableData] = useState<any[]>([]);
|
||||||
|
const { notifications } = useNotifications();
|
||||||
|
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
const [data, setData] = useState<
|
||||||
|
DropRateAPIResponse['data']['result'][0]['list']
|
||||||
|
>([]);
|
||||||
|
const [interval, setInterval] = useState<string>('');
|
||||||
|
|
||||||
|
const [visibleCounts, setVisibleCounts] = useState<Record<number, number>>({});
|
||||||
|
|
||||||
|
const paginationConfig = useMemo(
|
||||||
|
() =>
|
||||||
|
tableData?.length > 10 && {
|
||||||
|
pageSize: 10,
|
||||||
|
showTotal: showPaginationItem,
|
||||||
|
showSizeChanger: false,
|
||||||
|
hideOnSinglePage: true,
|
||||||
|
},
|
||||||
|
[tableData],
|
||||||
|
);
|
||||||
|
|
||||||
|
const evaluationTime = useMemo(() => convertToMilliseconds(interval), [
|
||||||
|
interval,
|
||||||
|
]);
|
||||||
|
const tableApiPayload: MessagingQueueServicePayload = useMemo(
|
||||||
|
() => ({
|
||||||
|
start: minTime,
|
||||||
|
end: maxTime,
|
||||||
|
evalTime: evaluationTime * 1e6,
|
||||||
|
}),
|
||||||
|
[evaluationTime, maxTime, minTime],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleOnError = (error: Error): void => {
|
||||||
|
notifications.error({
|
||||||
|
message: axios.isAxiosError(error) ? error?.message : SOMETHING_WENT_WRONG,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShowMore = (index: number): void => {
|
||||||
|
setVisibleCounts((prevCounts) => ({
|
||||||
|
...prevCounts,
|
||||||
|
[index]: (prevCounts[index] || 4) + 4,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const { mutate: getViewDetails, isLoading } = useMutation(getKafkaSpanEval, {
|
||||||
|
onSuccess: (data) => {
|
||||||
|
if (data.payload) {
|
||||||
|
setData(data.payload.result[0].list);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: handleOnError,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data?.length > 0) {
|
||||||
|
setColumns(getColumns(data, visibleCounts, handleShowMore));
|
||||||
|
setTableData(getTableData(data));
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [data, visibleCounts]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (evaluationTime) {
|
||||||
|
getViewDetails(tableApiPayload);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [minTime, maxTime, evaluationTime]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cx('mq-overview-container', 'droprate-view')}>
|
||||||
|
<div className="mq-overview-title">
|
||||||
|
<div className="drop-rat-title">
|
||||||
|
{MessagingQueuesViewType.dropRate.label}
|
||||||
|
</div>
|
||||||
|
<EvaluationTimeSelector setInterval={setInterval} />
|
||||||
|
</div>
|
||||||
|
<Table
|
||||||
|
className={cx('mq-table', 'pagination-left')}
|
||||||
|
pagination={paginationConfig}
|
||||||
|
size="middle"
|
||||||
|
columns={columns}
|
||||||
|
dataSource={tableData}
|
||||||
|
bordered={false}
|
||||||
|
loading={isLoading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DropRateView;
|
@ -0,0 +1,111 @@
|
|||||||
|
import './DropRateView.styles.scss';
|
||||||
|
|
||||||
|
import { Input, Select, Typography } from 'antd';
|
||||||
|
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
|
interface SelectDropdownRenderProps {
|
||||||
|
menu: React.ReactNode;
|
||||||
|
inputValue: string;
|
||||||
|
handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
handleKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
||||||
|
handleAddCustomValue: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectDropdownRender({
|
||||||
|
menu,
|
||||||
|
inputValue,
|
||||||
|
handleInputChange,
|
||||||
|
handleAddCustomValue,
|
||||||
|
handleKeyDown,
|
||||||
|
}: SelectDropdownRenderProps): JSX.Element {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{menu}
|
||||||
|
<Input
|
||||||
|
placeholder="Enter custom time (ms)"
|
||||||
|
value={inputValue}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
onBlur={handleAddCustomValue}
|
||||||
|
className="select-dropdown-render"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function EvaluationTimeSelector({
|
||||||
|
setInterval,
|
||||||
|
}: {
|
||||||
|
setInterval: Dispatch<SetStateAction<string>>;
|
||||||
|
}): JSX.Element {
|
||||||
|
const [inputValue, setInputValue] = useState<string>('');
|
||||||
|
const [selectedInterval, setSelectedInterval] = useState<string | null>('5ms');
|
||||||
|
const [dropdownOpen, setDropdownOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
setInputValue(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectChange = (value: string): void => {
|
||||||
|
setSelectedInterval(value);
|
||||||
|
setInputValue('');
|
||||||
|
setDropdownOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddCustomValue = (): void => {
|
||||||
|
setSelectedInterval(inputValue);
|
||||||
|
setInputValue(inputValue);
|
||||||
|
setDropdownOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>): void => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
handleAddCustomValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderDropdown = (menu: React.ReactNode): JSX.Element => (
|
||||||
|
<SelectDropdownRender
|
||||||
|
menu={menu}
|
||||||
|
inputValue={inputValue}
|
||||||
|
handleInputChange={handleInputChange}
|
||||||
|
handleAddCustomValue={handleAddCustomValue}
|
||||||
|
handleKeyDown={handleKeyDown}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedInterval) {
|
||||||
|
setInterval(() => selectedInterval);
|
||||||
|
}
|
||||||
|
}, [selectedInterval, setInterval]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="evaluation-time-selector">
|
||||||
|
<Typography.Text className="eval-title">
|
||||||
|
Evaluation Interval:
|
||||||
|
</Typography.Text>
|
||||||
|
<Select
|
||||||
|
style={{ width: 220 }}
|
||||||
|
placeholder="Select time interval (ms)"
|
||||||
|
value={selectedInterval}
|
||||||
|
onChange={handleSelectChange}
|
||||||
|
open={dropdownOpen}
|
||||||
|
onDropdownVisibleChange={setDropdownOpen}
|
||||||
|
dropdownRender={renderDropdown}
|
||||||
|
>
|
||||||
|
<Option value="1ms">1ms</Option>
|
||||||
|
<Option value="2ms">2ms</Option>
|
||||||
|
<Option value="5ms">5ms</Option>
|
||||||
|
<Option value="10ms">10ms</Option>
|
||||||
|
<Option value="15ms">15ms</Option>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EvaluationTimeSelector;
|
@ -0,0 +1,46 @@
|
|||||||
|
export function convertToMilliseconds(timeInput: string): number {
|
||||||
|
if (!timeInput.trim()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = timeInput.match(/^(\d+)(ms|s|ns)?$/); // Match number and optional unit
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`Invalid time format: ${timeInput}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = parseInt(match[1], 10);
|
||||||
|
const unit = match[2] || 'ms'; // Default to 'ms' if no unit is provided
|
||||||
|
|
||||||
|
switch (unit) {
|
||||||
|
case 's':
|
||||||
|
return value * 1e3;
|
||||||
|
case 'ms':
|
||||||
|
return value;
|
||||||
|
case 'ns':
|
||||||
|
return value / 1e6;
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid time format');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DropRateResponse {
|
||||||
|
timestamp: string;
|
||||||
|
data: {
|
||||||
|
breach_percentage: number;
|
||||||
|
breached_spans: number;
|
||||||
|
consumer_service: string;
|
||||||
|
producer_service: string;
|
||||||
|
top_traceIDs: string[];
|
||||||
|
total_spans: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export interface DropRateAPIResponse {
|
||||||
|
status: string;
|
||||||
|
data: {
|
||||||
|
resultType: string;
|
||||||
|
result: {
|
||||||
|
queryName: string;
|
||||||
|
list: DropRateResponse[];
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
@ -17,13 +17,20 @@
|
|||||||
background: var(--bg-ink-500);
|
background: var(--bg-ink-500);
|
||||||
|
|
||||||
.mq-overview-title {
|
.mq-overview-title {
|
||||||
color: var(--bg-vanilla-200);
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
font-family: Inter;
|
.drop-rat-title {
|
||||||
font-size: 18px;
|
color: var(--bg-vanilla-200);
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
font-family: Inter;
|
||||||
line-height: 28px;
|
font-size: 18px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 28px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mq-details-options {
|
.mq-details-options {
|
||||||
@ -43,3 +50,69 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.droprate-view {
|
||||||
|
.mq-table {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.ant-table-content {
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--bg-slate-500);
|
||||||
|
box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-tbody {
|
||||||
|
.ant-table-cell {
|
||||||
|
max-width: 250px;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-thead {
|
||||||
|
.ant-table-cell {
|
||||||
|
background-color: var(--bg-ink-500);
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-id-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
width: max-content;
|
||||||
|
|
||||||
|
.traceid-style {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.traceid-text {
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-slate-400);
|
||||||
|
padding: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remaing-count {
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: normal;
|
||||||
|
letter-spacing: -0.06px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-left {
|
||||||
|
&.mq-table {
|
||||||
|
.ant-pagination {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -249,7 +249,7 @@ function MessagingQueuesTable({
|
|||||||
<Table
|
<Table
|
||||||
className={cx(
|
className={cx(
|
||||||
'mq-table',
|
'mq-table',
|
||||||
type !== 'Detail' ? 'mq-overview-row-clickable' : '',
|
type !== 'Detail' ? 'mq-overview-row-clickable' : 'pagination-left',
|
||||||
)}
|
)}
|
||||||
pagination={paginationConfig}
|
pagination={paginationConfig}
|
||||||
size="middle"
|
size="middle"
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
import axios from 'api';
|
import axios from 'api';
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
|
|
||||||
import {
|
import { DropRateAPIResponse } from '../DropRateView/dropRateViewUtils';
|
||||||
MessagingQueueServicePayload,
|
import { MessagingQueueServicePayload } from './getConsumerLagDetails';
|
||||||
MessagingQueuesPayloadProps,
|
|
||||||
} from './getConsumerLagDetails';
|
|
||||||
|
|
||||||
export const getKafkaSpanEval = async (
|
export const getKafkaSpanEval = async (
|
||||||
props: Omit<MessagingQueueServicePayload, 'detailType' | 'variables'>,
|
props: Omit<MessagingQueueServicePayload, 'detailType' | 'variables'>,
|
||||||
): Promise<
|
): Promise<SuccessResponse<DropRateAPIResponse['data']> | ErrorResponse> => {
|
||||||
SuccessResponse<MessagingQueuesPayloadProps['payload']> | ErrorResponse
|
|
||||||
> => {
|
|
||||||
const { start, end, evalTime } = props;
|
const { start, end, evalTime } = props;
|
||||||
const response = await axios.post(`messaging-queues/kafka/span/evaluation`, {
|
const response = await axios.post(`messaging-queues/kafka/span/evaluation`, {
|
||||||
start,
|
start,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user