mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 21:39:05 +08:00
feat: new dep. services table added
This commit is contained in:
parent
bd071e3e60
commit
1118c56356
@ -690,30 +690,140 @@
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--bg-slate-500);
|
||||
|
||||
.top-services-title {
|
||||
border-bottom: 1px solid var(--bg-slate-500);
|
||||
padding: 10px 12px;
|
||||
border-radius: 3px 3px 0px 0px;
|
||||
background: rgba(171, 189, 255, 0.04);
|
||||
.title-wrapper {
|
||||
display: inline-flex;
|
||||
padding: 1px 2px;
|
||||
align-items: center;
|
||||
border-radius: 2px;
|
||||
background: rgba(113, 144, 249, 0.08);
|
||||
|
||||
.title-wrapper {
|
||||
display: inline-flex;
|
||||
padding: 1px 2px;
|
||||
align-items: center;
|
||||
border-radius: 2px;
|
||||
background: rgba(113, 144, 249, 0.08);
|
||||
|
||||
color: var(--bg-robin-400);
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
color: var(--bg-robin-400);
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
.dependent-services-container {
|
||||
padding: 10px 12px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--bg-slate-500);
|
||||
.ant-table {
|
||||
.ant-table-thead > tr > th {
|
||||
padding: 12px;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
border-bottom: none;
|
||||
|
||||
color: var(--text-vanilla-400);
|
||||
font-family: Inter;
|
||||
font-size: 11px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 18px;
|
||||
/* 163.636% */
|
||||
letter-spacing: 0.44px;
|
||||
text-transform: uppercase;
|
||||
background: none;
|
||||
|
||||
&::before {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-thead > tr > th:has(.status-code-header) {
|
||||
background: var(--bg-ink-300);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.ant-table-cell {
|
||||
padding: 12px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: var(--bg-vanilla-100);
|
||||
border-bottom: none;
|
||||
background: var(--bg-ink-400);
|
||||
}
|
||||
|
||||
.ant-table-cell:has(.col-title) {
|
||||
background: rgba(171, 189, 255, 0.04);
|
||||
}
|
||||
|
||||
.ant-table-cell:has(.top-services-item-latency) {
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
background: rgba(171, 189, 255, 0.04);
|
||||
}
|
||||
|
||||
.ant-table-cell:has(.top-services-item-latency-title) {
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
background: rgba(171, 189, 255, 0.04);
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr:hover > td {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.ant-table-cell:first-child {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.ant-table-cell:nth-child(2) {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.ant-table-cell:nth-child(n + 3) {
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr > td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.ant-table-thead
|
||||
> tr
|
||||
> th:not(:last-child):not(.ant-table-selection-column):not(.ant-table-row-expand-icon-cell):not([colspan])::before {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.ant-empty-normal {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.table-row-dark {
|
||||
background: var(--bg-ink-300);
|
||||
}
|
||||
|
||||
.ant-table-content {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-status-code-data-message-container {
|
||||
height: 30vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.no-status-code-data-message-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
|
||||
width: fit-content;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.no-status-code-data-message {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.top-services-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@ -743,6 +853,7 @@
|
||||
|
||||
.top-services-item-progress-bar {
|
||||
background-color: var(--bg-slate-400);
|
||||
border-radius: 2px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -758,7 +869,7 @@
|
||||
|
||||
.top-services-load-more {
|
||||
border-top: 1px solid var(--bg-slate-500);
|
||||
padding-top: 10px;
|
||||
padding: 10px;
|
||||
|
||||
color: var(--text-vanilla-400);
|
||||
font-family: Inter;
|
||||
|
@ -1,6 +1,12 @@
|
||||
import { Typography } from 'antd';
|
||||
import '../DomainDetails.styles.scss';
|
||||
|
||||
import { Table, TablePaginationConfig, Typography } from 'antd';
|
||||
import Skeleton from 'antd/lib/skeleton';
|
||||
import { getFormattedDependentServicesData } from 'container/ApiMonitoring/utils';
|
||||
import {
|
||||
dependentServicesColumns,
|
||||
DependentServicesData,
|
||||
getFormattedDependentServicesData,
|
||||
} from 'container/ApiMonitoring/utils';
|
||||
import { UnfoldVertical } from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { UseQueryResult } from 'react-query';
|
||||
@ -23,19 +29,25 @@ function DependentServices({
|
||||
isRefetching,
|
||||
} = dependentServicesQuery;
|
||||
|
||||
const [currentRenderCount, setCurrentRenderCount] = useState(0);
|
||||
const [isExpanded, setIsExpanded] = useState<boolean>(false);
|
||||
|
||||
const dependentServicesData = useMemo(() => {
|
||||
const formattedDependentServicesData = getFormattedDependentServicesData(
|
||||
data?.payload?.data?.result[0].table.rows,
|
||||
);
|
||||
setCurrentRenderCount(Math.min(formattedDependentServicesData.length, 5));
|
||||
return formattedDependentServicesData;
|
||||
}, [data]);
|
||||
const handleShowMoreClick = (): void => {
|
||||
setIsExpanded((prev) => !prev);
|
||||
};
|
||||
|
||||
const renderItems = useMemo(
|
||||
() => dependentServicesData.slice(0, currentRenderCount),
|
||||
[currentRenderCount, dependentServicesData],
|
||||
const dependentServicesData = useMemo(
|
||||
(): DependentServicesData[] =>
|
||||
getFormattedDependentServicesData(data?.payload?.data?.result[0].table.rows),
|
||||
[data],
|
||||
);
|
||||
|
||||
const paginationConfig = useMemo(
|
||||
(): TablePaginationConfig => ({
|
||||
pageSize: isExpanded ? dependentServicesData.length : 5,
|
||||
hideOnSinglePage: true,
|
||||
position: ['none', 'none'],
|
||||
}),
|
||||
[isExpanded, dependentServicesData.length],
|
||||
);
|
||||
|
||||
if (isLoading || isRefetching) {
|
||||
@ -48,56 +60,47 @@ function DependentServices({
|
||||
|
||||
return (
|
||||
<div className="top-services-content">
|
||||
<div className="top-services-title">
|
||||
<span className="title-wrapper">Dependent Services</span>
|
||||
</div>
|
||||
<div className="dependent-services-container">
|
||||
{renderItems.length === 0 ? (
|
||||
<div className="no-dependent-services-message-container">
|
||||
<div className="no-dependent-services-message-content">
|
||||
<img
|
||||
src="/Icons/emptyState.svg"
|
||||
alt="thinking-emoji"
|
||||
className="empty-state-svg"
|
||||
/>
|
||||
<Table
|
||||
loading={isLoading || isRefetching}
|
||||
dataSource={dependentServicesData || []}
|
||||
columns={dependentServicesColumns}
|
||||
rowClassName="table-row-dark"
|
||||
pagination={paginationConfig}
|
||||
locale={{
|
||||
emptyText:
|
||||
isLoading || isRefetching ? null : (
|
||||
<div className="no-status-code-data-message-container">
|
||||
<div className="no-status-code-data-message-content">
|
||||
<img
|
||||
src="/Icons/emptyState.svg"
|
||||
alt="thinking-emoji"
|
||||
className="empty-state-svg"
|
||||
/>
|
||||
|
||||
<Typography.Text className="no-dependent-services-message">
|
||||
This query had no results. Edit your query and try again!
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
renderItems.map((item) => (
|
||||
<div className="top-services-item" key={item.key}>
|
||||
<div className="top-services-item-progress">
|
||||
<div className="top-services-item-key">{item.serviceName}</div>
|
||||
<div className="top-services-item-count">{item.count}</div>
|
||||
<div
|
||||
className="top-services-item-progress-bar"
|
||||
style={{ width: `${item.percentage}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="top-services-item-percentage">
|
||||
{item.percentage.toFixed(2)}%
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
<Typography.Text className="no-status-code-data-message">
|
||||
This query had no results. Edit your query and try again!
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
{currentRenderCount < dependentServicesData.length && (
|
||||
{dependentServicesData.length > 5 && (
|
||||
<div
|
||||
className="top-services-load-more"
|
||||
onClick={(): void => setCurrentRenderCount(dependentServicesData.length)}
|
||||
onClick={handleShowMoreClick}
|
||||
onKeyDown={(e): void => {
|
||||
if (e.key === 'Enter') {
|
||||
setCurrentRenderCount(dependentServicesData.length);
|
||||
handleShowMoreClick();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<UnfoldVertical size={14} />
|
||||
Show more...
|
||||
{isExpanded ? 'Show less...' : 'Show more...'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -15,6 +15,7 @@ import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { ArrowUpDown, ChevronDown, ChevronRight } from 'lucide-react';
|
||||
import { getWidgetQuery } from 'pages/MessagingQueues/MQDetails/MetricPage/MetricPageUtil';
|
||||
import { ReactNode } from 'react';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import {
|
||||
@ -1472,14 +1473,14 @@ export const getEndPointDetailsQueryPayload = (
|
||||
key: 'span_id',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'count',
|
||||
aggregateOperator: 'count_distinct',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'A',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: 'a32988a4',
|
||||
id: 'bdac4904',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'http.url--string--tag--false',
|
||||
@ -1492,7 +1493,7 @@ export const getEndPointDetailsQueryPayload = (
|
||||
value: endPointName,
|
||||
},
|
||||
{
|
||||
id: '5a15032f',
|
||||
id: 'b78ff216',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'net.peer.name--string--tag--false',
|
||||
@ -1527,10 +1528,227 @@ export const getEndPointDetailsQueryPayload = (
|
||||
reduceTo: 'avg',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'count',
|
||||
timeAggregation: 'count_distinct',
|
||||
},
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.Float64,
|
||||
id: 'duration_nano--float64----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'duration_nano',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'p99',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'B',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: '74f9d185',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'http.url--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'http.url',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: endPointName,
|
||||
},
|
||||
{
|
||||
id: 'a9024472',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'net.peer.name--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'net.peer.name',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
},
|
||||
...filters.items,
|
||||
],
|
||||
op: 'AND',
|
||||
},
|
||||
functions: [],
|
||||
groupBy: [
|
||||
{
|
||||
dataType: DataTypes.String,
|
||||
id: 'service.name--string--resource--true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'service.name',
|
||||
type: 'resource',
|
||||
},
|
||||
],
|
||||
having: [],
|
||||
legend: 'p99 latency',
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'B',
|
||||
reduceTo: 'avg',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'p99',
|
||||
},
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.String,
|
||||
id: '------false',
|
||||
isColumn: false,
|
||||
key: '',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'rate',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: false,
|
||||
expression: 'C',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: 'b7e36a72',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'http.url--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'http.url',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: endPointName,
|
||||
},
|
||||
{
|
||||
id: '1b6c062d',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'net.peer.name--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'net.peer.name',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
},
|
||||
...filters.items,
|
||||
],
|
||||
op: 'AND',
|
||||
},
|
||||
functions: [],
|
||||
groupBy: [
|
||||
{
|
||||
dataType: DataTypes.String,
|
||||
id: 'service.name--string--resource--true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'service.name',
|
||||
type: 'resource',
|
||||
},
|
||||
],
|
||||
having: [],
|
||||
legend: 'request per second',
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'C',
|
||||
reduceTo: 'avg',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'rate',
|
||||
},
|
||||
{
|
||||
aggregateAttribute: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'span_id--string----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'span_id',
|
||||
type: '',
|
||||
},
|
||||
aggregateOperator: 'count_distinct',
|
||||
dataSource: DataSource.TRACES,
|
||||
disabled: true,
|
||||
expression: 'D',
|
||||
filters: {
|
||||
items: [
|
||||
{
|
||||
id: 'ede7cbfe',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'http.url--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'http.url',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: endPointName,
|
||||
},
|
||||
{
|
||||
id: 'd14792a8',
|
||||
key: {
|
||||
dataType: DataTypes.String,
|
||||
id: 'net.peer.name--string--tag--false',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
key: 'net.peer.name',
|
||||
type: 'tag',
|
||||
},
|
||||
op: '=',
|
||||
value: domainName,
|
||||
},
|
||||
{
|
||||
id: '3212bf1a',
|
||||
key: {
|
||||
dataType: DataTypes.bool,
|
||||
id: 'has_error--bool----true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'has_error',
|
||||
type: '',
|
||||
},
|
||||
op: '=',
|
||||
value: 'true',
|
||||
},
|
||||
...filters.items,
|
||||
],
|
||||
op: 'AND',
|
||||
},
|
||||
functions: [],
|
||||
groupBy: [
|
||||
{
|
||||
dataType: DataTypes.String,
|
||||
id: 'service.name--string--resource--true',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
key: 'service.name',
|
||||
type: 'resource',
|
||||
},
|
||||
],
|
||||
having: [],
|
||||
legend: 'count',
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'D',
|
||||
reduceTo: 'avg',
|
||||
spaceAggregation: 'sum',
|
||||
stepInterval: 60,
|
||||
timeAggregation: 'count_distinct',
|
||||
},
|
||||
],
|
||||
queryFormulas: [
|
||||
{
|
||||
queryName: 'F1',
|
||||
expression: '(D/A)*100',
|
||||
disabled: false,
|
||||
legend: 'error percentage',
|
||||
},
|
||||
],
|
||||
queryFormulas: [],
|
||||
},
|
||||
clickhouse_sql: [
|
||||
{
|
||||
@ -1963,31 +2181,135 @@ export const getFormattedEndPointDropDownData = (
|
||||
interface DependentServicesResponseRow {
|
||||
data: {
|
||||
['service.name']: string;
|
||||
A: number;
|
||||
A: number | string;
|
||||
B: number | string;
|
||||
C: number | string;
|
||||
F1: number | string;
|
||||
};
|
||||
}
|
||||
|
||||
interface DependentServicesData {
|
||||
key: string;
|
||||
export interface ServiceData {
|
||||
serviceName: string;
|
||||
count: number;
|
||||
percentage: number;
|
||||
count: number | string;
|
||||
percentage: number | string;
|
||||
}
|
||||
|
||||
export interface DependentServicesData {
|
||||
key: string;
|
||||
serviceData: ServiceData;
|
||||
latency: number | string;
|
||||
rate: number | string;
|
||||
errorPercentage: number | string;
|
||||
}
|
||||
|
||||
// Discuss once about type safety of this function
|
||||
export const getFormattedDependentServicesData = (
|
||||
data: DependentServicesResponseRow[],
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
): DependentServicesData[] => {
|
||||
if (!data) return [];
|
||||
const totalCount = data?.reduce((acc, row) => acc + row.data.A, 0);
|
||||
const totalCount = data?.reduce((acc, row) => acc + Number(row.data.A), 0);
|
||||
return data?.map((row) => ({
|
||||
key: v4(),
|
||||
serviceName: row.data['service.name'],
|
||||
count: row.data.A,
|
||||
percentage: Number(((row.data.A / totalCount) * 100).toFixed(2)),
|
||||
serviceData: {
|
||||
serviceName: row.data['service.name'] || '-',
|
||||
count:
|
||||
row.data.A !== undefined && row.data.A !== '-' && row.data.A !== 'n/a'
|
||||
? Number(row.data.A)
|
||||
: '-',
|
||||
percentage:
|
||||
totalCount > 0 &&
|
||||
row.data.A !== undefined &&
|
||||
row.data.A !== '-' &&
|
||||
row.data.A !== 'n/a'
|
||||
? Number(((Number(row.data.A) / totalCount) * 100).toFixed(2))
|
||||
: 0,
|
||||
},
|
||||
latency:
|
||||
row.data.B !== undefined && row.data.B !== '-' && row.data.B !== 'n/a'
|
||||
? Math.round(Number(row.data.B) / 1000000)
|
||||
: '-',
|
||||
rate:
|
||||
row.data.C !== undefined && row.data.C !== '-' && row.data.C !== 'n/a'
|
||||
? row.data.C
|
||||
: '-',
|
||||
errorPercentage:
|
||||
row.data.F1 !== undefined && row.data.F1 !== '-' && row.data.F1 !== 'n/a'
|
||||
? row.data.F1
|
||||
: 0,
|
||||
}));
|
||||
};
|
||||
|
||||
export const dependentServicesColumns: ColumnType<DependentServicesData>[] = [
|
||||
{
|
||||
title: <span className="title-wrapper col-title">Dependent Services</span>,
|
||||
dataIndex: 'serviceData',
|
||||
key: 'serviceData',
|
||||
render: (serviceData: ServiceData): ReactNode => (
|
||||
<div className="top-services-item">
|
||||
<div className="top-services-item-progress">
|
||||
<div className="top-services-item-key">{serviceData.serviceName}</div>
|
||||
<div className="top-services-item-count">{serviceData.count}</div>
|
||||
<div
|
||||
className="top-services-item-progress-bar"
|
||||
style={{ width: `${serviceData.percentage}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="top-services-item-percentage">
|
||||
{typeof serviceData.percentage === 'number'
|
||||
? serviceData.percentage.toFixed(2)
|
||||
: serviceData.percentage}
|
||||
%
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
sorter: (a: DependentServicesData, b: DependentServicesData): number =>
|
||||
Number(a.serviceData.count) - Number(b.serviceData.count),
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<span className="top-services-item-latency-title col-title">
|
||||
AVG. LATENCY
|
||||
</span>
|
||||
),
|
||||
dataIndex: 'latency',
|
||||
key: 'latency',
|
||||
render: (latency: number): ReactNode => (
|
||||
<div className="top-services-item-latency">{latency || '-'}ms</div>
|
||||
),
|
||||
sorter: (a: DependentServicesData, b: DependentServicesData): number =>
|
||||
Number(a.latency) - Number(b.latency),
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<span className="top-services-item-error-percentage-title col-title">
|
||||
ERROR %
|
||||
</span>
|
||||
),
|
||||
dataIndex: 'errorPercentage',
|
||||
key: 'errorPercentage',
|
||||
align: 'center',
|
||||
render: (errorPercentage: number): ReactNode => (
|
||||
<div className="top-services-item-error-percentage">{errorPercentage}%</div>
|
||||
),
|
||||
sorter: (a: DependentServicesData, b: DependentServicesData): number =>
|
||||
Number(a.errorPercentage) - Number(b.errorPercentage),
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<span className="top-services-item-rate-title col-title">AVG. RATE</span>
|
||||
),
|
||||
dataIndex: 'rate',
|
||||
key: 'rate',
|
||||
align: 'right',
|
||||
render: (rate: number): ReactNode => (
|
||||
<div className="top-services-item-rate">{rate || '-'} ops/sec</div>
|
||||
),
|
||||
sorter: (a: DependentServicesData, b: DependentServicesData): number =>
|
||||
Number(a.rate) - Number(b.rate),
|
||||
},
|
||||
];
|
||||
|
||||
export const getFormattedChartData = (
|
||||
data: MetricRangePayloadProps,
|
||||
newLegendArray: string[],
|
||||
|
Loading…
x
Reference in New Issue
Block a user