ydb-embedded-ui 4.19.3 → 4.20.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/CellWithPopover/CellWithPopover.scss +13 -0
  3. package/dist/components/CellWithPopover/CellWithPopover.tsx +26 -0
  4. package/dist/components/LinkToSchemaObject/LinkToSchemaObject.tsx +20 -0
  5. package/dist/components/NodeHostWrapper/NodeHostWrapper.scss +0 -2
  6. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +28 -29
  7. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +3 -2
  8. package/dist/components/TruncatedQuery/TruncatedQuery.scss +8 -0
  9. package/dist/components/TruncatedQuery/TruncatedQuery.tsx +15 -1
  10. package/dist/components/UsageLabel/UsageLabel.scss +6 -0
  11. package/dist/components/UsageLabel/UsageLabel.tsx +22 -0
  12. package/dist/containers/AsideNavigation/AsideNavigation.tsx +13 -8
  13. package/dist/containers/AsideNavigation/i18n/en.json +13 -0
  14. package/dist/containers/AsideNavigation/i18n/index.ts +11 -0
  15. package/dist/containers/AsideNavigation/i18n/ru.json +13 -0
  16. package/dist/containers/Node/NodeStructure/Pdisk.tsx +74 -68
  17. package/dist/containers/Node/NodeStructure/Vdisk.tsx +9 -33
  18. package/dist/containers/Nodes/Nodes.tsx +10 -2
  19. package/dist/containers/Nodes/getNodesColumns.tsx +207 -123
  20. package/dist/containers/Storage/Storage.tsx +9 -2
  21. package/dist/containers/Storage/StorageGroups/StorageGroups.scss +0 -11
  22. package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx +11 -11
  23. package/dist/containers/Storage/utils/index.ts +1 -22
  24. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -3
  25. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +0 -1
  26. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +4 -2
  27. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +1 -0
  28. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +8 -1
  29. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +11 -1
  30. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/IssuesViewer/IssueTree.tsx +0 -1
  31. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +3 -0
  32. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx +21 -0
  33. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +53 -0
  34. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +53 -0
  35. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +83 -0
  36. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +53 -0
  37. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx +9 -0
  38. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +55 -0
  39. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +44 -0
  40. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +35 -19
  41. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +53 -0
  42. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx +4 -2
  43. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +9 -36
  44. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +22 -41
  45. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -3
  46. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -3
  47. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +0 -2
  48. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +19 -61
  49. package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +102 -0
  50. package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.tsx +2 -2
  51. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +18 -97
  52. package/dist/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx +138 -0
  53. package/dist/containers/Tenant/Info/ExternalTable/ExternalTable.tsx +2 -4
  54. package/dist/containers/Tenant/Query/ExecuteResult/{ExecuteResult.js → ExecuteResult.tsx} +51 -31
  55. package/dist/containers/Tenant/Query/Issues/Issues.tsx +4 -6
  56. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.tsx +1 -1
  57. package/dist/containers/Tenant/utils/paneVisibilityToggleHelpers.tsx +1 -1
  58. package/dist/routes.ts +26 -1
  59. package/dist/store/reducers/{executeTopQueries.ts → executeTopQueries/executeTopQueries.ts} +23 -75
  60. package/dist/{types/store/executeTopQueries.ts → store/reducers/executeTopQueries/types.ts} +3 -7
  61. package/dist/store/reducers/executeTopQueries/utils.ts +36 -0
  62. package/dist/store/reducers/index.ts +12 -2
  63. package/dist/store/reducers/nodes/types.ts +1 -0
  64. package/dist/store/reducers/nodes/utils.ts +16 -6
  65. package/dist/store/reducers/{shardsWorkload.ts → shardsWorkload/shardsWorkload.ts} +5 -11
  66. package/dist/{types/store/shardsWorkload.ts → store/reducers/shardsWorkload/types.ts} +3 -7
  67. package/dist/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts +87 -0
  68. package/dist/store/reducers/tenantOverview/topNodesByCpu/types.ts +29 -0
  69. package/dist/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts +87 -0
  70. package/dist/store/reducers/tenantOverview/topNodesByLoad/types.ts +29 -0
  71. package/dist/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts +87 -0
  72. package/dist/store/reducers/tenantOverview/topNodesByMemory/types.ts +29 -0
  73. package/dist/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts +93 -0
  74. package/dist/store/reducers/tenantOverview/topQueries/types.ts +14 -0
  75. package/dist/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts +103 -0
  76. package/dist/store/reducers/tenantOverview/topShards/types.ts +14 -0
  77. package/dist/store/reducers/tenantOverview/topShards/utils.ts +3 -0
  78. package/dist/styles/mixins.scss +4 -0
  79. package/dist/types/additionalProps.ts +3 -1
  80. package/dist/types/api/compute.ts +1 -1
  81. package/dist/types/react-json-inspector.d.ts +21 -0
  82. package/dist/utils/diagnostics.ts +23 -0
  83. package/dist/utils/generateEvaluator.ts +21 -0
  84. package/dist/utils/generateHash.ts +11 -0
  85. package/package.json +3 -2
  86. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.scss +0 -41
@@ -1,26 +1,20 @@
1
1
  import {useDispatch} from 'react-redux';
2
- import cn from 'bem-cn-lite';
2
+ import {useLocation} from 'react-router';
3
3
 
4
4
  import DataTable, {Column} from '@gravity-ui/react-data-table';
5
- import {Popover} from '@gravity-ui/uikit';
6
5
 
7
6
  import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
8
7
  import {
9
8
  fetchTopTables,
10
9
  setDataWasNotLoaded,
11
10
  } from '../../../../../store/reducers/tenantOverview/executeTopTables/executeTopTables';
12
- import {
13
- TENANT_OVERVIEW_TABLES_LIMIT,
14
- TENANT_OVERVIEW_TABLES_SETTINGS,
15
- } from '../../../../../utils/constants';
16
11
  import type {KeyValueRow} from '../../../../../types/api/query';
17
12
  import {formatBytes, getSizeWithSignificantDigits} from '../../../../../utils/bytesParsers';
18
- import {TableSkeleton} from '../../../../../components/TableSkeleton/TableSkeleton';
19
- import {ResponseError} from '../../../../../components/Errors/ResponseError';
20
-
21
- import './TenantStorage.scss';
13
+ import {LinkToSchemaObject} from '../../../../../components/LinkToSchemaObject/LinkToSchemaObject';
14
+ import {CellWithPopover} from '../../../../../components/CellWithPopover/CellWithPopover';
15
+ import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
22
16
 
23
- const b = cn('tenant-overview-storage');
17
+ import '../TenantOverview.scss';
24
18
 
25
19
  interface TopTablesProps {
26
20
  path: string;
@@ -28,6 +22,7 @@ interface TopTablesProps {
28
22
 
29
23
  export function TopTables({path}: TopTablesProps) {
30
24
  const dispatch = useDispatch();
25
+ const location = useLocation();
31
26
 
32
27
  const {autorefresh} = useTypedSelector((state) => state.schema);
33
28
 
@@ -67,39 +62,25 @@ export function TopTables({path}: TopTablesProps) {
67
62
  {
68
63
  name: 'Path',
69
64
  sortable: false,
70
- render: ({row}) => (
71
- <div className={b('cell-with-popover-wrapper')}>
72
- <Popover className={b('cell-with-popover')} content={row.Path}>
73
- {row.Path}
74
- </Popover>
75
- </div>
76
- ),
65
+ render: ({row}) =>
66
+ row.Path ? (
67
+ <CellWithPopover content={row.Path}>
68
+ <LinkToSchemaObject path={String(row.Path)} location={location}>
69
+ {row.Path}
70
+ </LinkToSchemaObject>
71
+ </CellWithPopover>
72
+ ) : null,
77
73
  },
78
74
  ];
79
75
 
80
- const renderContent = () => {
81
- if (error) {
82
- return <ResponseError error={error} />;
83
- }
84
-
85
- if (loading && !wasLoaded) {
86
- return <TableSkeleton rows={TENANT_OVERVIEW_TABLES_LIMIT} />;
87
- }
88
-
89
- return (
90
- <DataTable
91
- theme="yandex-cloud"
92
- columns={columns}
93
- settings={TENANT_OVERVIEW_TABLES_SETTINGS}
94
- data={data || []}
95
- />
96
- );
97
- };
98
-
99
76
  return (
100
- <>
101
- <div className={b('title')}>Top tables by size</div>
102
- <div className={b('table')}>{renderContent()}</div>
103
- </>
77
+ <TenantOverviewTableLayout
78
+ data={data || []}
79
+ columns={columns}
80
+ title="Top tables by size"
81
+ loading={loading}
82
+ wasLoaded={wasLoaded}
83
+ error={error}
84
+ />
104
85
  );
105
86
  }
@@ -2,10 +2,10 @@
2
2
  "no-data": "No data",
3
3
  "no-pools-data": "No pools data",
4
4
 
5
+ "top-nodes.empty-data": "No such nodes",
6
+
5
7
  "title.pools": "Pools",
6
8
  "title.metrics": "Metrics",
7
9
 
8
- "top-groups.empty-data": "No such groups",
9
-
10
- "label.under-development": "This section is under development"
10
+ "top-groups.empty-data": "No such groups"
11
11
  }
@@ -2,10 +2,10 @@
2
2
  "no-data": "Нет данных",
3
3
  "no-pools-data": "Нет данных о пулах",
4
4
 
5
+ "top-nodes.empty-data": "Нет узлов",
6
+
5
7
  "title.pools": "Пулы",
6
8
  "title.metrics": "Метрики",
7
9
 
8
- "top-groups.empty-data": "Нет групп",
9
-
10
- "label.under-development": "Этот раздел находится в разработке"
10
+ "top-groups.empty-data": "Нет групп"
11
11
  }
@@ -39,8 +39,6 @@
39
39
  &__query {
40
40
  overflow: hidden;
41
41
 
42
- width: 500px;
43
-
44
42
  vertical-align: top;
45
43
  white-space: pre-wrap;
46
44
  text-overflow: ellipsis;
@@ -1,91 +1,45 @@
1
1
  import {useCallback, useEffect, useRef, useState} from 'react';
2
2
  import {useDispatch} from 'react-redux';
3
3
  import {useHistory, useLocation} from 'react-router';
4
- import qs from 'qs';
5
4
  import cn from 'bem-cn-lite';
6
5
 
7
- import DataTable, {Column} from '@gravity-ui/react-data-table';
6
+ import DataTable from '@gravity-ui/react-data-table';
8
7
  import {Loader} from '@gravity-ui/uikit';
9
8
 
10
9
  import {DateRange, DateRangeValues} from '../../../../components/DateRange';
11
10
  import {Search} from '../../../../components/Search';
12
- import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery';
13
11
 
14
12
  import {changeUserInput} from '../../../../store/reducers/executeQuery';
15
- import {
16
- fetchTopQueries,
17
- setTopQueriesFilters,
18
- setTopQueriesState,
19
- } from '../../../../store/reducers/executeTopQueries';
20
13
 
21
- import type {KeyValueRow} from '../../../../types/api/query';
22
14
  import type {EPathType} from '../../../../types/api/schema';
23
- import type {ITopQueriesFilters} from '../../../../types/store/executeTopQueries';
24
15
  import type {IQueryResult} from '../../../../types/store/query';
16
+ import type {ITopQueriesFilters} from '../../../../store/reducers/executeTopQueries/types';
25
17
 
26
18
  import {
27
19
  TENANT_PAGE,
28
20
  TENANT_PAGES_IDS,
29
21
  TENANT_QUERY_TABS_ID,
30
22
  } from '../../../../store/reducers/tenant/constants';
31
- import {formatDateTime, formatNumber} from '../../../../utils/dataFormatters/dataFormatters';
23
+ import {
24
+ setTopQueriesFilters,
25
+ setTopQueriesState,
26
+ fetchTopQueries,
27
+ } from '../../../../store/reducers/executeTopQueries/executeTopQueries';
32
28
  import {HOUR_IN_SECONDS} from '../../../../utils/constants';
33
29
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
34
30
  import {prepareQueryError} from '../../../../utils/query';
35
-
36
- import {MAX_QUERY_HEIGHT, QUERY_TABLE_SETTINGS} from '../../utils/constants';
31
+ import {parseQuery} from '../../../../routes';
32
+ import {QUERY_TABLE_SETTINGS} from '../../utils/constants';
33
+ import {isSortableTopQueriesProperty} from '../../../../utils/diagnostics';
37
34
  import {isColumnEntityType} from '../../utils/schema';
38
35
  import {TenantTabsGroups, getTenantPath} from '../../TenantPages';
36
+ import {getTopQueriesColumns} from './getTopQueriesColumns';
39
37
 
40
38
  import i18n from './i18n';
41
39
  import './TopQueries.scss';
42
40
 
43
41
  const b = cn('kv-top-queries');
44
42
 
45
- const COLUMNS: Column<KeyValueRow>[] = [
46
- {
47
- name: 'CPUTimeUs',
48
- sortAccessor: (row) => Number(row.CPUTimeUs),
49
- align: DataTable.RIGHT,
50
- },
51
- {
52
- name: 'QueryText',
53
- width: 500,
54
- sortable: false,
55
- render: ({row}) => (
56
- <div className={b('query')}>
57
- <TruncatedQuery
58
- value={row.QueryText?.toString()}
59
- maxQueryHeight={MAX_QUERY_HEIGHT}
60
- />
61
- </div>
62
- ),
63
- },
64
- {
65
- name: 'EndTime',
66
- render: ({row}) => formatDateTime(new Date(row.EndTime as string).getTime()),
67
- align: DataTable.RIGHT,
68
- },
69
- {
70
- name: 'ReadRows',
71
- render: ({row}) => formatNumber(row.ReadRows),
72
- sortAccessor: (row) => Number(row.ReadRows),
73
- align: DataTable.RIGHT,
74
- },
75
- {
76
- name: 'ReadBytes',
77
- render: ({row}) => formatNumber(row.ReadBytes),
78
- sortAccessor: (row) => Number(row.ReadBytes),
79
- align: DataTable.RIGHT,
80
- },
81
- {
82
- name: 'UserSID',
83
- render: ({row}) => <div className={b('user-sid')}>{row.UserSID || '–'}</div>,
84
- sortAccessor: (row) => String(row.UserSID),
85
- align: DataTable.LEFT,
86
- },
87
- ];
88
-
89
43
  interface TopQueriesProps {
90
44
  path: string;
91
45
  type?: EPathType;
@@ -105,6 +59,7 @@ export const TopQueries = ({path, type}: TopQueriesProps) => {
105
59
  data: {result: data = undefined} = {},
106
60
  filters: storeFilters,
107
61
  } = useTypedSelector((state) => state.executeTopQueries);
62
+ const rawColumns = getTopQueriesColumns();
108
63
 
109
64
  const preventFetch = useRef(false);
110
65
 
@@ -117,6 +72,11 @@ export const TopQueries = ({path, type}: TopQueriesProps) => {
117
72
  dispatch(setTopQueriesFilters(filters));
118
73
  }, [dispatch, filters]);
119
74
 
75
+ const columns = rawColumns.map((column) => ({
76
+ ...column,
77
+ sortable: isSortableTopQueriesProperty(column.name),
78
+ }));
79
+
120
80
  const setDefaultFiltersFromResponse = (responseData?: IQueryResult) => {
121
81
  const intervalEnd = responseData?.result?.[0]?.IntervalEnd;
122
82
 
@@ -173,9 +133,7 @@ export const TopQueries = ({path, type}: TopQueriesProps) => {
173
133
 
174
134
  dispatch(changeUserInput({input}));
175
135
 
176
- const queryParams = qs.parse(location.search, {
177
- ignoreQueryPrefix: true,
178
- });
136
+ const queryParams = parseQuery(location);
179
137
 
180
138
  const queryPath = getTenantPath({
181
139
  ...queryParams,
@@ -220,7 +178,7 @@ export const TopQueries = ({path, type}: TopQueriesProps) => {
220
178
  return (
221
179
  <div className={b('table')}>
222
180
  <DataTable
223
- columns={COLUMNS}
181
+ columns={columns}
224
182
  data={data}
225
183
  settings={QUERY_TABLE_SETTINGS}
226
184
  onRowClick={handleRowClick}
@@ -0,0 +1,102 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import DataTable, {type Column} from '@gravity-ui/react-data-table';
4
+
5
+ import type {KeyValueRow} from '../../../../types/api/query';
6
+ import {formatDateTime, formatNumber} from '../../../../utils/dataFormatters/dataFormatters';
7
+ import {generateHash} from '../../../../utils/generateHash';
8
+ import {
9
+ TruncatedQuery,
10
+ OneLineQueryWithPopover,
11
+ } from '../../../../components/TruncatedQuery/TruncatedQuery';
12
+ import {MAX_QUERY_HEIGHT} from '../../utils/constants';
13
+
14
+ import './TopQueries.scss';
15
+
16
+ const b = cn('kv-top-queries');
17
+
18
+ const TOP_QUERIES_COLUMNS_IDS = {
19
+ CPUTimeUs: 'CPUTimeUs',
20
+ QueryText: 'QueryText',
21
+ EndTime: 'EndTime',
22
+ ReadRows: 'ReadRows',
23
+ ReadBytes: 'ReadBytes',
24
+ UserSID: 'UserSID',
25
+ OneLineQueryText: 'OneLineQueryText',
26
+ QueryHash: 'QueryHash',
27
+ };
28
+
29
+ const cpuTimeUsColumn: Column<KeyValueRow> = {
30
+ name: TOP_QUERIES_COLUMNS_IDS.CPUTimeUs,
31
+ sortAccessor: (row) => Number(row.CPUTimeUs),
32
+ width: 120,
33
+ align: DataTable.RIGHT,
34
+ sortable: false,
35
+ };
36
+
37
+ const queryTextColumn: Column<KeyValueRow> = {
38
+ name: TOP_QUERIES_COLUMNS_IDS.QueryText,
39
+ sortAccessor: (row) => Number(row.CPUTimeUs),
40
+ render: ({row}) => (
41
+ <div className={b('query')}>
42
+ <TruncatedQuery value={row.QueryText?.toString()} maxQueryHeight={MAX_QUERY_HEIGHT} />
43
+ </div>
44
+ ),
45
+ sortable: false,
46
+ };
47
+
48
+ const endTimeColumn: Column<KeyValueRow> = {
49
+ name: TOP_QUERIES_COLUMNS_IDS.EndTime,
50
+ render: ({row}) => formatDateTime(new Date(row.EndTime as string).getTime()),
51
+ align: DataTable.RIGHT,
52
+ };
53
+
54
+ const readRowsColumn: Column<KeyValueRow> = {
55
+ name: TOP_QUERIES_COLUMNS_IDS.ReadRows,
56
+ render: ({row}) => formatNumber(row.ReadRows),
57
+ sortAccessor: (row) => Number(row.ReadRows),
58
+ align: DataTable.RIGHT,
59
+ };
60
+
61
+ const readBytesColumn: Column<KeyValueRow> = {
62
+ name: TOP_QUERIES_COLUMNS_IDS.ReadBytes,
63
+ render: ({row}) => formatNumber(row.ReadBytes),
64
+ sortAccessor: (row) => Number(row.ReadBytes),
65
+ align: DataTable.RIGHT,
66
+ };
67
+
68
+ const userSIDColumn: Column<KeyValueRow> = {
69
+ name: TOP_QUERIES_COLUMNS_IDS.UserSID,
70
+ render: ({row}) => <div className={b('user-sid')}>{row.UserSID || '–'}</div>,
71
+ sortAccessor: (row) => String(row.UserSID),
72
+ align: DataTable.LEFT,
73
+ };
74
+
75
+ const oneLineQueryTextColumn: Column<KeyValueRow> = {
76
+ name: TOP_QUERIES_COLUMNS_IDS.OneLineQueryText,
77
+ header: 'QueryText',
78
+ render: ({row}) => <OneLineQueryWithPopover value={row.QueryText?.toString()} />,
79
+ sortable: false,
80
+ };
81
+
82
+ const queryHashColumn: Column<KeyValueRow> = {
83
+ name: TOP_QUERIES_COLUMNS_IDS.QueryHash,
84
+ render: ({row}) => generateHash(String(row.QueryText)),
85
+ width: 130,
86
+ sortable: false,
87
+ };
88
+
89
+ export const getTopQueriesColumns = (): Column<KeyValueRow>[] => {
90
+ return [
91
+ cpuTimeUsColumn,
92
+ queryTextColumn,
93
+ endTimeColumn,
94
+ readRowsColumn,
95
+ readBytesColumn,
96
+ userSIDColumn,
97
+ ];
98
+ };
99
+
100
+ export const getTenantOverviewTopQueriesColumns = (): Column<KeyValueRow>[] => {
101
+ return [queryHashColumn, oneLineQueryTextColumn, cpuTimeUsColumn];
102
+ };
@@ -4,8 +4,8 @@ import {DateRange, DateRangeValues} from '../../../../../components/DateRange';
4
4
 
5
5
  import {
6
6
  EShardsWorkloadMode,
7
- IShardsWorkloadFilters,
8
- } from '../../../../../types/store/shardsWorkload';
7
+ type IShardsWorkloadFilters,
8
+ } from '../../../../../store/reducers/shardsWorkload/types';
9
9
 
10
10
  import {isEnumMember} from '../../../../../utils/typecheckers';
11
11
 
@@ -1,43 +1,38 @@
1
- import {useState, useContext, useEffect, useMemo} from 'react';
1
+ import {useState, useEffect, useMemo} from 'react';
2
2
  import {useDispatch} from 'react-redux';
3
3
  import cn from 'bem-cn-lite';
4
+ import {useLocation} from 'react-router';
4
5
 
5
6
  import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
6
7
  import {Loader} from '@gravity-ui/uikit';
7
8
 
8
- import {InternalLink} from '../../../../components/InternalLink';
9
-
10
- import HistoryContext from '../../../../contexts/HistoryContext';
11
-
12
- import routes, {createHref} from '../../../../routes';
13
-
14
9
  import {
15
10
  sendShardQuery,
16
11
  setShardsState,
17
12
  setShardsQueryFilters,
18
- } from '../../../../store/reducers/shardsWorkload';
19
- import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema/schema';
20
- import {EShardsWorkloadMode, IShardsWorkloadFilters} from '../../../../types/store/shardsWorkload';
13
+ } from '../../../../store/reducers/shardsWorkload/shardsWorkload';
14
+ import {
15
+ EShardsWorkloadMode,
16
+ type IShardsWorkloadFilters,
17
+ } from '../../../../store/reducers/shardsWorkload/types';
21
18
 
22
19
  import type {EPathType} from '../../../../types/api/schema';
23
20
  import type {CellValue, KeyValueRow} from '../../../../types/api/query';
24
21
 
25
- import {formatDateTime, formatNumber} from '../../../../utils/dataFormatters/dataFormatters';
22
+ import {formatDateTime} from '../../../../utils/dataFormatters/dataFormatters';
26
23
  import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
27
24
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
28
25
  import {prepareQueryError} from '../../../../utils/query';
29
-
30
- import {getDefaultNodePath} from '../../../Node/NodePages';
31
-
26
+ import {isSortableTopShardsProperty} from '../../../../utils/diagnostics';
32
27
  import {isColumnEntityType} from '../../utils/schema';
33
28
 
34
29
  import {Filters} from './Filters';
30
+ import {getShardsWorkloadColumns} from './getTopShardsColumns';
35
31
 
36
32
  import i18n from './i18n';
37
33
  import './TopShards.scss';
38
34
 
39
35
  export const b = cn('top-shards');
40
- const bLink = cn('yc-link');
41
36
 
42
37
  const TABLE_SETTINGS: Settings = {
43
38
  ...DEFAULT_TABLE_SETTINGS,
@@ -58,10 +53,6 @@ const tableColumnsNames = {
58
53
  IntervalEnd: 'IntervalEnd',
59
54
  };
60
55
 
61
- function prepareCPUWorkloadValue(value: string | number) {
62
- return `${(Number(value) * 100).toFixed(2)}%`;
63
- }
64
-
65
56
  function prepareDateTimeValue(value: CellValue) {
66
57
  if (!value) {
67
58
  return '–';
@@ -105,6 +96,7 @@ interface TopShardsProps {
105
96
 
106
97
  export const TopShards = ({tenantPath, type}: TopShardsProps) => {
107
98
  const dispatch = useDispatch();
99
+ const location = useLocation();
108
100
 
109
101
  const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
110
102
 
@@ -159,8 +151,6 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
159
151
  );
160
152
  }, [dispatch, currentSchemaPath, tenantPath, filters]);
161
153
 
162
- const history = useContext(HistoryContext);
163
-
164
154
  const onSort = (newSortOrder?: SortOrder | SortOrder[]) => {
165
155
  // omit information about sort order to disable ASC order, only DESC makes sense for top shards
166
156
  // use a string (and not the DataTable default format) to prevent reference change,
@@ -190,81 +180,12 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
190
180
  };
191
181
 
192
182
  const tableColumns = useMemo(() => {
193
- const onSchemaClick = (schemaPath: string) => {
194
- return () => {
195
- dispatch(setCurrentSchemaPath(schemaPath));
196
- dispatch(getSchema({path: schemaPath}));
197
- history.go(0);
198
- };
199
- };
200
-
201
- const columns: Column<KeyValueRow>[] = [
202
- {
203
- name: tableColumnsNames.Path,
204
- render: ({row}) => {
205
- // row.Path - relative schema path
206
- return (
207
- <span
208
- onClick={onSchemaClick(tenantPath + row.Path)}
209
- className={bLink({view: 'normal'})}
210
- >
211
- {row.Path}
212
- </span>
213
- );
214
- },
215
- sortable: false,
216
- },
217
- {
218
- name: tableColumnsNames.CPUCores,
219
- render: ({row}) => {
220
- return prepareCPUWorkloadValue(row.CPUCores || 0);
221
- },
222
- align: DataTable.RIGHT,
223
- },
224
- {
225
- name: tableColumnsNames.DataSize,
226
- header: 'DataSize (B)',
227
- render: ({row}) => {
228
- return formatNumber(row.DataSize);
229
- },
230
- align: DataTable.RIGHT,
231
- },
232
- {
233
- name: tableColumnsNames.TabletId,
234
- render: ({row}) => {
235
- if (!row.TabletId) {
236
- return '–';
237
- }
238
- return (
239
- <InternalLink to={createHref(routes.tablet, {id: row.TabletId})}>
240
- {row.TabletId}
241
- </InternalLink>
242
- );
243
- },
244
- sortable: false,
245
- },
246
- {
247
- name: tableColumnsNames.NodeId,
248
- render: ({row}) => {
249
- if (!row.NodeId) {
250
- return '–';
251
- }
252
- return (
253
- <InternalLink to={getDefaultNodePath(row.NodeId)}>
254
- {row.NodeId}
255
- </InternalLink>
256
- );
257
- },
258
- align: DataTable.RIGHT,
259
- sortable: false,
260
- },
261
- {
262
- name: tableColumnsNames.InFlightTxCount,
263
- render: ({row}) => formatNumber(row.InFlightTxCount),
264
- align: DataTable.RIGHT,
265
- sortable: false,
266
- },
267
- ];
183
+ const rawColumns: Column<KeyValueRow>[] = getShardsWorkloadColumns(tenantPath, location);
184
+
185
+ const columns: Column<KeyValueRow>[] = rawColumns.map((column) => ({
186
+ ...column,
187
+ sortable: isSortableTopShardsProperty(column.name),
188
+ }));
268
189
 
269
190
  if (filters.mode === EShardsWorkloadMode.History) {
270
191
  // after NodeId
@@ -284,7 +205,7 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
284
205
  }
285
206
 
286
207
  return columns;
287
- }, [dispatch, filters.mode, history, tenantPath]);
208
+ }, [filters.mode, tenantPath, location]);
288
209
 
289
210
  const renderLoader = () => {
290
211
  return (