Skip to content

Commit 83251a8

Browse files
feat: add ShardsTable to componentsRegistry
1 parent 5065ddf commit 83251a8

File tree

15 files changed

+225
-174
lines changed

15 files changed

+225
-174
lines changed

src/components/ComponentsProvider/componentsRegistry.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {AsideNavigation} from '../../containers/AsideNavigation/AsideNavigation';
22
import {ErrorBoundaryInner} from '../ErrorBoundary/ErrorBoundary';
3+
import {ShardsTable} from '../ShardsTable/ShardsTable';
34
import {StaffCard} from '../User/StaffCard';
45

56
import type {ComponentsRegistryTemplate} from './registry';
@@ -8,7 +9,8 @@ import {Registry} from './registry';
89
const componentsRegistryInner = new Registry()
910
.register('StaffCard', StaffCard)
1011
.register('AsideNavigation', AsideNavigation)
11-
.register('ErrorBoundary', ErrorBoundaryInner);
12+
.register('ErrorBoundary', ErrorBoundaryInner)
13+
.register('ShardsTable', ShardsTable);
1214

1315
export type ComponentsRegistry = ComponentsRegistryTemplate<typeof componentsRegistryInner>;
1416

src/components/LinkToSchemaObject/LinkToSchemaObject.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import {Link} from '@gravity-ui/uikit';
22
import type {LinkProps} from '@gravity-ui/uikit';
3-
import type {Location} from 'history';
3+
import {useLocation} from 'react-router-dom';
44

55
import {createExternalUILink, parseQuery} from '../../routes';
66

77
interface LinkToSchemaObjectProps extends Omit<LinkProps, 'href'> {
88
path: string;
9-
location: Location;
109
}
1110

12-
export function LinkToSchemaObject({path, location, ...props}: LinkToSchemaObjectProps) {
11+
export function LinkToSchemaObject({path, ...props}: LinkToSchemaObjectProps) {
12+
const location = useLocation();
1313
const queryParams = parseQuery(location);
1414
const pathToSchemaObject = createExternalUILink({
1515
...queryParams,
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from 'react';
2+
3+
import type {KeyValueRow} from '../../types/api/query';
4+
import type {ResizeableDataTableProps} from '../ResizeableDataTable/ResizeableDataTable';
5+
import {ResizeableDataTable} from '../ResizeableDataTable/ResizeableDataTable';
6+
7+
import {shardsColumnIdToGetColumn} from './columns';
8+
import type {TopShardsColumnId} from './constants';
9+
import {TOP_SHARDS_COLUMNS_WIDTH_LS_KEY, isSortableTopShardsColumn} from './constants';
10+
11+
interface ShardsTableProps
12+
extends Omit<ResizeableDataTableProps<KeyValueRow>, 'columnsWidthLSKey' | 'columns'> {
13+
columnsIds: TopShardsColumnId[];
14+
database?: string;
15+
schemaPath?: string;
16+
}
17+
18+
export function ShardsTable({columnsIds, schemaPath, ...props}: ShardsTableProps) {
19+
const columns = React.useMemo(
20+
() =>
21+
columnsIds
22+
.map((id) => {
23+
return shardsColumnIdToGetColumn[id](schemaPath);
24+
})
25+
.map((column) => {
26+
return {
27+
...column,
28+
sortable: isSortableTopShardsColumn(column.name),
29+
};
30+
}),
31+
[columnsIds, schemaPath],
32+
);
33+
34+
return (
35+
<ResizeableDataTable
36+
{...props}
37+
columnsWidthLSKey={TOP_SHARDS_COLUMNS_WIDTH_LS_KEY}
38+
columns={columns}
39+
/>
40+
);
41+
}
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import DataTable from '@gravity-ui/react-data-table';
2+
3+
import {getDefaultNodePath} from '../../containers/Node/NodePages';
4+
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
5+
import {formatNumber, roundToPrecision} from '../../utils/dataFormatters/dataFormatters';
6+
import {getUsageSeverity} from '../../utils/generateEvaluator';
7+
import {InternalLink} from '../InternalLink';
8+
import {LinkToSchemaObject} from '../LinkToSchemaObject/LinkToSchemaObject';
9+
import {TabletNameWrapper} from '../TabletNameWrapper/TabletNameWrapper';
10+
import {UsageLabel} from '../UsageLabel/UsageLabel';
11+
12+
import {TOP_SHARDS_COLUMNS_IDS, TOP_SHARDS_COLUMNS_TITLES} from './constants';
13+
import type {GetShardsColumn} from './types';
14+
import {prepareDateTimeValue} from './utils';
15+
16+
export const getPathColumn: GetShardsColumn = (schemaPath = '') => {
17+
return {
18+
name: TOP_SHARDS_COLUMNS_IDS.Path,
19+
header: TOP_SHARDS_COLUMNS_TITLES.Path,
20+
render: ({row}) => {
21+
// row.Path - relative schema path
22+
return <LinkToSchemaObject path={schemaPath + row.Path}>{row.Path}</LinkToSchemaObject>;
23+
},
24+
width: 300,
25+
};
26+
};
27+
export const getDataSizeColumn: GetShardsColumn = () => {
28+
return {
29+
name: TOP_SHARDS_COLUMNS_IDS.DataSize,
30+
header: TOP_SHARDS_COLUMNS_TITLES.DataSize,
31+
render: ({row}) => {
32+
return formatNumber(row.DataSize);
33+
},
34+
align: DataTable.RIGHT,
35+
};
36+
};
37+
export const getTabletIdColumn: GetShardsColumn = () => {
38+
return {
39+
name: TOP_SHARDS_COLUMNS_IDS.TabletId,
40+
header: TOP_SHARDS_COLUMNS_TITLES.TabletId,
41+
render: ({row}) => {
42+
if (!row.TabletId) {
43+
return EMPTY_DATA_PLACEHOLDER;
44+
}
45+
return <TabletNameWrapper tabletId={row.TabletId} />;
46+
},
47+
width: 220,
48+
};
49+
};
50+
export const getNodeIdColumn: GetShardsColumn = () => {
51+
return {
52+
name: TOP_SHARDS_COLUMNS_IDS.NodeId,
53+
header: TOP_SHARDS_COLUMNS_TITLES.NodeId,
54+
render: ({row}) => {
55+
if (!row.NodeId) {
56+
return EMPTY_DATA_PLACEHOLDER;
57+
}
58+
return <InternalLink to={getDefaultNodePath(row.NodeId)}>{row.NodeId}</InternalLink>;
59+
},
60+
align: DataTable.RIGHT,
61+
};
62+
};
63+
export const getCpuCoresColumn: GetShardsColumn = () => {
64+
return {
65+
name: TOP_SHARDS_COLUMNS_IDS.CPUCores,
66+
header: TOP_SHARDS_COLUMNS_TITLES.CPUCores,
67+
render: ({row}) => {
68+
const usage = Number(row.CPUCores) * 100 || 0;
69+
return (
70+
<UsageLabel value={roundToPrecision(usage, 2)} theme={getUsageSeverity(usage)} />
71+
);
72+
},
73+
align: DataTable.RIGHT,
74+
width: 110,
75+
resizeMinWidth: 110,
76+
};
77+
};
78+
export const getInFlightTxCountColumn: GetShardsColumn = () => {
79+
return {
80+
name: TOP_SHARDS_COLUMNS_IDS.InFlightTxCount,
81+
header: TOP_SHARDS_COLUMNS_TITLES.InFlightTxCount,
82+
render: ({row}) => formatNumber(row.InFlightTxCount),
83+
align: DataTable.RIGHT,
84+
};
85+
};
86+
export const getPeakTimeColumn: GetShardsColumn = () => {
87+
return {
88+
name: TOP_SHARDS_COLUMNS_IDS.PeakTime,
89+
render: ({row}) => {
90+
return prepareDateTimeValue(row.PeakTime);
91+
},
92+
};
93+
};
94+
export const getIntervalEndColumn: GetShardsColumn = () => {
95+
return {
96+
name: TOP_SHARDS_COLUMNS_IDS.IntervalEnd,
97+
render: ({row}) => {
98+
return prepareDateTimeValue(row.IntervalEnd);
99+
},
100+
};
101+
};
102+
103+
export const shardsColumnIdToGetColumn = {
104+
[TOP_SHARDS_COLUMNS_IDS.Path]: getPathColumn,
105+
[TOP_SHARDS_COLUMNS_IDS.DataSize]: getDataSizeColumn,
106+
[TOP_SHARDS_COLUMNS_IDS.TabletId]: getTabletIdColumn,
107+
[TOP_SHARDS_COLUMNS_IDS.NodeId]: getNodeIdColumn,
108+
[TOP_SHARDS_COLUMNS_IDS.CPUCores]: getCpuCoresColumn,
109+
[TOP_SHARDS_COLUMNS_IDS.InFlightTxCount]: getInFlightTxCountColumn,
110+
[TOP_SHARDS_COLUMNS_IDS.PeakTime]: getPeakTimeColumn,
111+
[TOP_SHARDS_COLUMNS_IDS.IntervalEnd]: getIntervalEndColumn,
112+
};

src/containers/Tenant/Diagnostics/TopShards/columns/constants.ts src/components/ShardsTable/constants.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {ValueOf} from '../../../../../types/common';
1+
import type {ValueOf} from '../../types/common';
22

33
import i18n from './i18n';
44

@@ -15,7 +15,7 @@ export const TOP_SHARDS_COLUMNS_IDS = {
1515
IntervalEnd: 'IntervalEnd',
1616
} as const;
1717

18-
type TopShardsColumnId = ValueOf<typeof TOP_SHARDS_COLUMNS_IDS>;
18+
export type TopShardsColumnId = ValueOf<typeof TOP_SHARDS_COLUMNS_IDS>;
1919

2020
export const TOP_SHARDS_COLUMNS_TITLES: Record<TopShardsColumnId, string> = {
2121
get TabletId() {
@@ -52,7 +52,7 @@ const TOP_SHARDS_COLUMNS_TO_SORT_FIELDS: Record<TopShardsColumnId, string | unde
5252
NodeId: undefined,
5353
PeakTime: undefined,
5454
InFlightTxCount: 'InFlightTxCount',
55-
IntervalEnd: undefined,
55+
IntervalEnd: 'IntervalEnd',
5656
} as const;
5757

5858
export function getTopShardsColumnSortField(columnId?: string) {
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {registerKeysets} from '../../../utils/i18n';
2+
3+
import en from './en.json';
4+
5+
const COMPONENT = 'ydb-shards-table';
6+
7+
export default registerKeysets(COMPONENT, {en});

src/components/ShardsTable/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type {Column} from '@gravity-ui/react-data-table';
2+
3+
import type {KeyValueRow} from '../../types/api/query';
4+
5+
export type GetShardsColumn = (schemaPath?: string) => Column<KeyValueRow>;

src/components/ShardsTable/utils.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type {CellValue} from '../../types/api/query';
2+
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
3+
import {formatDateTime} from '../../utils/dataFormatters/dataFormatters';
4+
5+
export function prepareDateTimeValue(value: CellValue) {
6+
if (!value) {
7+
return EMPTY_DATA_PLACEHOLDER;
8+
}
9+
return formatDateTime(new Date(value).getTime());
10+
}

src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
import {useLocation} from 'react-router-dom';
22

3-
import {ResizeableDataTable} from '../../../../../components/ResizeableDataTable/ResizeableDataTable';
3+
import {useComponent} from '../../../../../components/ComponentsProvider/ComponentsProvider';
4+
import type {TopShardsColumnId} from '../../../../../components/ShardsTable/constants';
45
import {parseQuery} from '../../../../../routes';
56
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
67
import {topShardsApi} from '../../../../../store/reducers/tenantOverview/topShards/tenantOverviewTopShards';
78
import {TENANT_OVERVIEW_TABLES_SETTINGS} from '../../../../../utils/constants';
89
import {useAutoRefreshInterval} from '../../../../../utils/hooks';
910
import {parseQueryErrorToString} from '../../../../../utils/query';
1011
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
11-
import {getTopShardsColumns} from '../../TopShards/columns/columns';
12-
import {TOP_SHARDS_COLUMNS_WIDTH_LS_KEY} from '../../TopShards/columns/constants';
1312
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
1413
import {getSectionTitle} from '../getSectionTitle';
1514
import i18n from '../i18n';
1615

16+
const columnsIds: TopShardsColumnId[] = ['TabletId', 'Path', 'CPUCores'];
17+
1718
interface TopShardsProps {
1819
tenantName: string;
1920
path: string;
2021
}
2122

2223
export const TopShards = ({tenantName, path}: TopShardsProps) => {
24+
const ShardsTable = useComponent('ShardsTable');
25+
2326
const location = useLocation();
2427

2528
const query = parseQuery(location);
@@ -34,8 +37,6 @@ export const TopShards = ({tenantName, path}: TopShardsProps) => {
3437
const loading = isFetching && currentData === undefined;
3538
const data = currentData?.resultSets?.[0]?.result || [];
3639

37-
const columns = getTopShardsColumns(tenantName, location);
38-
3940
const title = getSectionTitle({
4041
entity: i18n('shards'),
4142
postfix: i18n('by-cpu-usage'),
@@ -52,10 +53,11 @@ export const TopShards = ({tenantName, path}: TopShardsProps) => {
5253
error={parseQueryErrorToString(error)}
5354
withData={Boolean(currentData)}
5455
>
55-
<ResizeableDataTable
56-
columnsWidthLSKey={TOP_SHARDS_COLUMNS_WIDTH_LS_KEY}
56+
<ShardsTable
5757
data={data}
58-
columns={columns}
58+
schemaPath={tenantName}
59+
database={tenantName}
60+
columnsIds={columnsIds}
5961
settings={TENANT_OVERVIEW_TABLES_SETTINGS}
6062
/>
6163
</TenantOverviewTableLayout>

src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type {Column} from '@gravity-ui/react-data-table';
22
import DataTable from '@gravity-ui/react-data-table';
3-
import {useLocation} from 'react-router-dom';
43

54
import {CellWithPopover} from '../../../../../components/CellWithPopover/CellWithPopover';
65
import {LinkToSchemaObject} from '../../../../../components/LinkToSchemaObject/LinkToSchemaObject';
@@ -24,8 +23,6 @@ interface TopTablesProps {
2423
const TOP_TABLES_COLUMNS_WIDTH_LS_KEY = 'topTablesTableColumnsWidth';
2524

2625
export function TopTables({path}: TopTablesProps) {
27-
const location = useLocation();
28-
2926
const [autoRefreshInterval] = useAutoRefreshInterval();
3027

3128
const {currentData, error, isFetching} = topTablesApi.useGetTopTablesQuery(
@@ -55,9 +52,7 @@ export function TopTables({path}: TopTablesProps) {
5552
render: ({row}) =>
5653
row.Path ? (
5754
<CellWithPopover content={row.Path}>
58-
<LinkToSchemaObject path={String(row.Path)} location={location}>
59-
{row.Path}
60-
</LinkToSchemaObject>
55+
<LinkToSchemaObject path={String(row.Path)}>{row.Path}</LinkToSchemaObject>
6156
</CellWithPopover>
6257
) : null,
6358
},

0 commit comments

Comments
 (0)