ydb-embedded-ui 4.21.1 → 4.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/ProgressViewer/ProgressViewer.tsx +1 -1
  3. package/dist/components/VirtualTable/TableChunk.tsx +2 -1
  4. package/dist/components/VirtualTable/VirtualTable.tsx +1 -1
  5. package/dist/containers/Cluster/Cluster.tsx +2 -0
  6. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +14 -5
  7. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +104 -24
  8. package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.tsx +1 -1
  9. package/dist/containers/Cluster/i18n/en.json +16 -0
  10. package/dist/containers/Cluster/i18n/index.ts +11 -0
  11. package/dist/containers/Cluster/i18n/ru.json +16 -0
  12. package/dist/containers/Node/NodeStructure/Pdisk.tsx +4 -1
  13. package/dist/containers/Nodes/getNodesColumns.tsx +57 -13
  14. package/dist/containers/Tenant/Diagnostics/Network/Network.js +5 -10
  15. package/dist/containers/Tenant/Diagnostics/Network/utils.ts +6 -0
  16. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +18 -3
  17. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +18 -3
  18. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +17 -1
  19. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +20 -1
  20. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +18 -3
  21. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +2 -1
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +19 -2
  23. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +8 -1
  24. package/dist/containers/Tenant/Diagnostics/TenantOverview/getSectionTitle.tsx +28 -0
  25. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +17 -1
  26. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +17 -1
  27. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.scss +13 -5
  28. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.tsx +72 -18
  29. package/dist/containers/Tenant/Query/ExplainResult/ExplainResult.js +2 -1
  30. package/dist/containers/Tenant/Query/ExplainResult/utils.ts +6 -0
  31. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +11 -24
  32. package/dist/containers/Tenant/Query/utils/getPreparedResult.ts +4 -5
  33. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx +19 -11
  34. package/dist/containers/UserSettings/i18n/en.json +3 -0
  35. package/dist/containers/UserSettings/i18n/ru.json +3 -0
  36. package/dist/containers/UserSettings/settings.ts +7 -0
  37. package/dist/store/reducers/cluster/__test__/parseGroupsStatsQueryResponse.test.ts +121 -0
  38. package/dist/store/reducers/cluster/cluster.ts +46 -2
  39. package/dist/store/reducers/cluster/types.ts +29 -4
  40. package/dist/store/reducers/cluster/utils.ts +88 -0
  41. package/dist/store/reducers/executeQuery.ts +4 -3
  42. package/dist/store/reducers/nodes/types.ts +11 -1
  43. package/dist/store/reducers/nodes/utils.ts +6 -0
  44. package/dist/store/reducers/settings/settings.ts +2 -0
  45. package/dist/types/api/cluster.ts +3 -0
  46. package/dist/types/api/netInfo.ts +1 -1
  47. package/dist/types/api/nodes.ts +24 -0
  48. package/dist/types/api/query.ts +23 -8
  49. package/dist/types/store/query.ts +6 -0
  50. package/dist/utils/constants.ts +3 -0
  51. package/dist/utils/developerUI/__test__/developerUI.test.ts +50 -0
  52. package/dist/utils/developerUI/developerUI.ts +42 -0
  53. package/dist/utils/diagnostics.ts +1 -0
  54. package/dist/utils/hooks/index.ts +1 -0
  55. package/dist/utils/hooks/useSearchQuery.ts +9 -0
  56. package/dist/utils/query.ts +60 -12
  57. package/package.json +1 -1
  58. package/dist/utils/developerUI.ts +0 -32
  59. package/dist/utils/index.js +0 -9
  60. /package/dist/{components/VirtualTable/utils.ts → utils/index.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.23.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.22.0...v4.23.0) (2023-12-06)
4
+
5
+
6
+ ### Features
7
+
8
+ * **ClusterInfo:** display groups stats ([#598](https://github.com/ydb-platform/ydb-embedded-ui/issues/598)) ([c31d048](https://github.com/ydb-platform/ydb-embedded-ui/commit/c31d0480a1b91cf01a660fd1d9726c6708f7c252))
9
+ * **TenantOverview:** add links to sections titles ([#599](https://github.com/ydb-platform/ydb-embedded-ui/issues/599)) ([30401fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/30401fa354d90943bc4af4ddbf65466ce10381f9))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * **Schema:** display keys in right order ([#596](https://github.com/ydb-platform/ydb-embedded-ui/issues/596)) ([c99b7e2](https://github.com/ydb-platform/ydb-embedded-ui/commit/c99b7e2e97acffc1cab450dfbf758c38b8b6e4d5))
15
+
16
+ ## [4.22.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.21.1...v4.22.0) (2023-11-27)
17
+
18
+
19
+ ### Features
20
+
21
+ * **Query:** enable queries with multiple resultsets ([#595](https://github.com/ydb-platform/ydb-embedded-ui/issues/595)) ([2eedfb6](https://github.com/ydb-platform/ydb-embedded-ui/commit/2eedfb6ec3be932c7399bb67de901798c0b31b50))
22
+ * **TenantOverview:** add columns to memory table ([#593](https://github.com/ydb-platform/ydb-embedded-ui/issues/593)) ([6379577](https://github.com/ydb-platform/ydb-embedded-ui/commit/6379577782cfa69de9fb39640d2a143f1670be39))
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * fix disks developer UI links for paths with nodeId ([#594](https://github.com/ydb-platform/ydb-embedded-ui/issues/594)) ([7f5a783](https://github.com/ydb-platform/ydb-embedded-ui/commit/7f5a78393d0c23e584ad73040fd0e73d404e5d01))
28
+ * **TopShards:** sort by InFlightTxCount ([#591](https://github.com/ydb-platform/ydb-embedded-ui/issues/591)) ([eb3592d](https://github.com/ydb-platform/ydb-embedded-ui/commit/eb3592d69a465814de27e8b1e368b34cc60fed2f))
29
+
3
30
  ## [4.21.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.21.0...v4.21.1) (2023-11-17)
4
31
 
5
32
 
@@ -44,7 +44,7 @@ Props description:
44
44
  interface ProgressViewerProps {
45
45
  value?: number | string;
46
46
  capacity?: number | string;
47
- formatValues?: (value?: number, capacity?: number) => (string | undefined)[];
47
+ formatValues?: (value?: number, capacity?: number) => (string | number | undefined)[];
48
48
  percents?: boolean;
49
49
  className?: string;
50
50
  size?: ProgressViewerSize;
@@ -1,8 +1,9 @@
1
1
  import {useEffect, useRef, memo} from 'react';
2
2
 
3
+ import {getArray} from '../../utils';
4
+
3
5
  import type {Column, Chunk, GetRowClassName} from './types';
4
6
  import {LoadingTableRow, TableRow} from './TableRow';
5
- import {getArray} from './utils';
6
7
 
7
8
  // With original memo generic types are lost
8
9
  const typedMemo: <T>(Component: T) => T = memo;
@@ -1,6 +1,7 @@
1
1
  import {useState, useReducer, useRef, useCallback, useEffect} from 'react';
2
2
 
3
3
  import type {IResponseError} from '../../types/api/error';
4
+ import {getArray} from '../../utils';
4
5
 
5
6
  import {TableWithControlsLayout} from '../TableWithControlsLayout/TableWithControlsLayout';
6
7
  import {ResponseError} from '../Errors/ResponseError';
@@ -31,7 +32,6 @@ import {TableHead} from './TableHead';
31
32
  import {TableChunk} from './TableChunk';
32
33
  import {EmptyTableRow} from './TableRow';
33
34
  import {useIntersectionObserver} from './useIntersectionObserver';
34
- import {getArray} from './utils';
35
35
  import i18n from './i18n';
36
36
  import {b} from './shared';
37
37
 
@@ -68,6 +68,7 @@ function Cluster({
68
68
  loading: clusterLoading,
69
69
  wasLoaded: clusterWasLoaded,
70
70
  error: clusterError,
71
+ groupsStats,
71
72
  } = useTypedSelector((state) => state.cluster);
72
73
  const {
73
74
  nodes,
@@ -135,6 +136,7 @@ function Cluster({
135
136
  <div className={b()} ref={container}>
136
137
  <ClusterInfo
137
138
  cluster={cluster}
139
+ groupsStats={groupsStats}
138
140
  versionsValues={versionsValues}
139
141
  loading={infoLoading}
140
142
  error={clusterError}
@@ -49,10 +49,6 @@
49
49
  }
50
50
  }
51
51
 
52
- &__metric-field {
53
- margin-top: -8px;
54
- }
55
-
56
52
  &__system-tablets {
57
53
  display: flex;
58
54
  flex-wrap: wrap;
@@ -83,7 +79,6 @@
83
79
  margin-left: 15px;
84
80
  padding: 0 !important;
85
81
  }
86
-
87
82
  &__links {
88
83
  display: flex;
89
84
  flex-flow: row wrap;
@@ -91,6 +86,20 @@
91
86
  gap: 12px;
92
87
  }
93
88
 
89
+ &__storage-groups-stats {
90
+ display: flex;
91
+ flex-direction: column;
92
+ gap: 11px;
93
+ }
94
+
95
+ &__groups-stats-bar {
96
+ cursor: pointer;
97
+ }
98
+
99
+ &__groups-stats-popup-content {
100
+ padding: 12px;
101
+ }
102
+
94
103
  &__clipboard-button {
95
104
  display: flex;
96
105
  align-items: center;
@@ -10,6 +10,7 @@ import {Tablet} from '../../../components/Tablet';
10
10
  import {ResponseError} from '../../../components/Errors/ResponseError';
11
11
  import {ExternalLinkWithIcon} from '../../../components/ExternalLinkWithIcon/ExternalLinkWithIcon';
12
12
  import {IconWrapper as Icon} from '../../../components/Icon/Icon';
13
+ import {ContentWithPopup} from '../../../components/ContentWithPopup/ContentWithPopup';
13
14
 
14
15
  import type {IResponseError} from '../../../types/api/error';
15
16
  import type {AdditionalClusterProps, ClusterLink} from '../../../types/additionalProps';
@@ -18,14 +19,21 @@ import type {TClusterInfo} from '../../../types/api/cluster';
18
19
  import {backend, customBackend} from '../../../store';
19
20
  import {formatStorageValues} from '../../../utils/dataFormatters/dataFormatters';
20
21
  import {useSetting, useTypedSelector} from '../../../utils/hooks';
22
+ import {formatBytes, getSizeWithSignificantDigits} from '../../../utils/bytesParsers';
21
23
  import {
22
24
  CLUSTER_DEFAULT_TITLE,
23
25
  CLUSTER_INFO_HIDDEN_KEY,
24
26
  DEVELOPER_UI_TITLE,
25
27
  } from '../../../utils/constants';
28
+ import type {
29
+ ClusterGroupsStats,
30
+ DiskErasureGroupsStats,
31
+ DiskGroupsStats,
32
+ } from '../../../store/reducers/cluster/types';
26
33
 
27
34
  import {VersionsBar} from '../VersionsBar/VersionsBar';
28
35
  import {ClusterInfoSkeleton} from '../ClusterInfoSkeleton/ClusterInfoSkeleton';
36
+ import i18n from '../i18n';
29
37
 
30
38
  import {compareTablets} from './utils';
31
39
 
@@ -33,9 +41,85 @@ import './ClusterInfo.scss';
33
41
 
34
42
  const b = block('cluster-info');
35
43
 
44
+ interface GroupsStatsPopupContentProps {
45
+ stats: DiskErasureGroupsStats;
46
+ }
47
+
48
+ const GroupsStatsPopupContent = ({stats}: GroupsStatsPopupContentProps) => {
49
+ const {diskType, erasure, allocatedSize, availableSize} = stats;
50
+
51
+ const sizeToConvert = getSizeWithSignificantDigits(Math.max(allocatedSize, availableSize), 2);
52
+
53
+ const convertedAllocatedSize = formatBytes({value: allocatedSize, size: sizeToConvert});
54
+ const convertedAvailableSize = formatBytes({value: availableSize, size: sizeToConvert});
55
+
56
+ const usage = Math.round((allocatedSize / (allocatedSize + availableSize)) * 100);
57
+
58
+ const info = [
59
+ {
60
+ label: i18n('disk-type'),
61
+ value: diskType,
62
+ },
63
+ {
64
+ label: i18n('erasure'),
65
+ value: erasure,
66
+ },
67
+ {
68
+ label: i18n('allocated'),
69
+ value: convertedAllocatedSize,
70
+ },
71
+ {
72
+ label: i18n('available'),
73
+ value: convertedAvailableSize,
74
+ },
75
+ {
76
+ label: i18n('usage'),
77
+ value: usage + '%',
78
+ },
79
+ ];
80
+
81
+ return (
82
+ <InfoViewer dots={true} info={info} className={b('groups-stats-popup-content')} size="s" />
83
+ );
84
+ };
85
+
86
+ interface DiskGroupsStatsProps {
87
+ stats: DiskGroupsStats;
88
+ }
89
+
90
+ const DiskGroupsStatsBars = ({stats}: DiskGroupsStatsProps) => {
91
+ return (
92
+ <div className={b('storage-groups-stats')}>
93
+ {Object.values(stats).map((erasureStats) => (
94
+ <ContentWithPopup
95
+ placement={['right']}
96
+ key={erasureStats.erasure}
97
+ content={<GroupsStatsPopupContent stats={erasureStats} />}
98
+ >
99
+ <ProgressViewer
100
+ className={b('groups-stats-bar')}
101
+ value={erasureStats.createdGroups}
102
+ capacity={erasureStats.totalGroups}
103
+ />
104
+ </ContentWithPopup>
105
+ ))}
106
+ </div>
107
+ );
108
+ };
109
+
110
+ const getGroupsStatsFields = (groupsStats: ClusterGroupsStats) => {
111
+ return Object.keys(groupsStats).map((diskType) => {
112
+ return {
113
+ label: i18n('storage-groups', {diskType}),
114
+ value: <DiskGroupsStatsBars stats={groupsStats[diskType]} />,
115
+ };
116
+ });
117
+ };
118
+
36
119
  const getInfo = (
37
120
  cluster: TClusterInfo,
38
121
  versionsValues: VersionValue[],
122
+ groupsStats: ClusterGroupsStats,
39
123
  additionalInfo: InfoViewerItem[],
40
124
  links: ClusterLink[],
41
125
  ) => {
@@ -43,14 +127,14 @@ const getInfo = (
43
127
 
44
128
  if (cluster.DataCenters) {
45
129
  info.push({
46
- label: 'DC',
130
+ label: i18n('dc'),
47
131
  value: <Tags tags={cluster.DataCenters} />,
48
132
  });
49
133
  }
50
134
 
51
135
  if (cluster.SystemTablets) {
52
136
  info.push({
53
- label: 'Tablets',
137
+ label: i18n('tablets'),
54
138
  value: (
55
139
  <div className={b('system-tablets')}>
56
140
  {cluster.SystemTablets.sort(compareTablets).map((tablet, tabletIndex) => (
@@ -63,46 +147,40 @@ const getInfo = (
63
147
 
64
148
  if (cluster.Tenants) {
65
149
  info.push({
66
- label: 'Databases',
150
+ label: i18n('databases'),
67
151
  value: cluster.Tenants,
68
152
  });
69
153
  }
70
154
 
71
155
  info.push(
72
156
  {
73
- label: 'Nodes',
74
- value: (
75
- <ProgressViewer
76
- className={b('metric-field')}
77
- value={cluster?.NodesAlive}
78
- capacity={cluster?.NodesTotal}
79
- />
80
- ),
157
+ label: i18n('nodes'),
158
+ value: <ProgressViewer value={cluster?.NodesAlive} capacity={cluster?.NodesTotal} />,
81
159
  },
82
160
  {
83
- label: 'Load',
84
- value: (
85
- <ProgressViewer
86
- className={b('metric-field')}
87
- value={cluster?.LoadAverage}
88
- capacity={cluster?.NumberOfCpus}
89
- />
90
- ),
161
+ label: i18n('load'),
162
+ value: <ProgressViewer value={cluster?.LoadAverage} capacity={cluster?.NumberOfCpus} />,
91
163
  },
92
164
  {
93
- label: 'Storage',
165
+ label: i18n('storage-size'),
94
166
  value: (
95
167
  <ProgressViewer
96
- className={b('metric-field')}
97
168
  value={cluster?.StorageUsed}
98
169
  capacity={cluster?.StorageTotal}
99
170
  formatValues={formatStorageValues}
100
171
  />
101
172
  ),
102
173
  },
174
+ );
175
+
176
+ if (Object.keys(groupsStats).length) {
177
+ info.push(...getGroupsStatsFields(groupsStats));
178
+ }
179
+
180
+ info.push(
103
181
  ...additionalInfo,
104
182
  {
105
- label: 'Links',
183
+ label: i18n('links'),
106
184
  value: (
107
185
  <div className={b('links')}>
108
186
  {links.map(({title, url}) => (
@@ -112,7 +190,7 @@ const getInfo = (
112
190
  ),
113
191
  },
114
192
  {
115
- label: 'Versions',
193
+ label: i18n('versions'),
116
194
  value: <VersionsBar versionsValues={versionsValues} />,
117
195
  },
118
196
  );
@@ -123,6 +201,7 @@ const getInfo = (
123
201
  interface ClusterInfoProps {
124
202
  cluster?: TClusterInfo;
125
203
  versionsValues?: VersionValue[];
204
+ groupsStats?: ClusterGroupsStats;
126
205
  loading?: boolean;
127
206
  error?: IResponseError;
128
207
  additionalClusterProps?: AdditionalClusterProps;
@@ -131,6 +210,7 @@ interface ClusterInfoProps {
131
210
  export const ClusterInfo = ({
132
211
  cluster = {},
133
212
  versionsValues = [],
213
+ groupsStats = {},
134
214
  loading,
135
215
  error,
136
216
  additionalClusterProps = {},
@@ -151,7 +231,7 @@ export const ClusterInfo = ({
151
231
 
152
232
  const {info = [], links = []} = additionalClusterProps;
153
233
 
154
- const clusterInfo = getInfo(cluster, versionsValues, info, [
234
+ const clusterInfo = getInfo(cluster, versionsValues, groupsStats, info, [
155
235
  {title: DEVELOPER_UI_TITLE, url: internalLink},
156
236
  ...links,
157
237
  ]);
@@ -18,7 +18,7 @@ interface ClusterInfoSkeletonProps {
18
18
  rows?: number;
19
19
  }
20
20
 
21
- export const ClusterInfoSkeleton = ({rows = 7, className}: ClusterInfoSkeletonProps) => (
21
+ export const ClusterInfoSkeleton = ({rows = 8, className}: ClusterInfoSkeletonProps) => (
22
22
  <div className={b(null, className)}>
23
23
  {[...new Array(rows)].map((_, index) => (
24
24
  <div className={b('row')} key={`skeleton-row-${index}`}>
@@ -0,0 +1,16 @@
1
+ {
2
+ "disk-type": "Disk Type",
3
+ "erasure": "Erasure",
4
+ "allocated": "Allocated",
5
+ "available": "Available",
6
+ "usage": "Usage",
7
+ "dc": "DC",
8
+ "tablets": "Tablets",
9
+ "databases": "Databases",
10
+ "nodes": "Nodes",
11
+ "load": "Load",
12
+ "storage-size": "Storage size",
13
+ "storage-groups": "Storage groups, {{diskType}}",
14
+ "links": "Links",
15
+ "versions": "Versions"
16
+ }
@@ -0,0 +1,11 @@
1
+ import {i18n, Lang} from '../../../utils/i18n';
2
+
3
+ import en from './en.json';
4
+ import ru from './ru.json';
5
+
6
+ const COMPONENT = 'ydb-cluster';
7
+
8
+ i18n.registerKeyset(Lang.En, COMPONENT, en);
9
+ i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
10
+
11
+ export default i18n.keyset(COMPONENT);
@@ -0,0 +1,16 @@
1
+ {
2
+ "disk-type": "Тип диска",
3
+ "erasure": "Режим",
4
+ "allocated": "Использовано",
5
+ "available": "Доступно",
6
+ "usage": "Потребление",
7
+ "dc": "ДЦ",
8
+ "tablets": "Таблетки",
9
+ "databases": "Базы данных",
10
+ "nodes": "Узлы",
11
+ "load": "Нагрузка",
12
+ "storage-size": "Размер хранилища",
13
+ "storage-groups": "Группы хранения, {{diskType}}",
14
+ "links": "Ссылки",
15
+ "versions": "Версии"
16
+ }
@@ -16,7 +16,10 @@ import {bytesToGB} from '../../../utils/utils';
16
16
  import {formatStorageValuesToGb} from '../../../utils/dataFormatters/dataFormatters';
17
17
  import {getPDiskType} from '../../../utils/pdisk';
18
18
  import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
19
- import {createPDiskDeveloperUILink, createVDiskDeveloperUILink} from '../../../utils/developerUI';
19
+ import {
20
+ createPDiskDeveloperUILink,
21
+ createVDiskDeveloperUILink,
22
+ } from '../../../utils/developerUI/developerUI';
20
23
  import EntityStatus from '../../../components/EntityStatus/EntityStatus';
21
24
  import InfoViewer, {type InfoViewerItem} from '../../../components/InfoViewer/InfoViewer';
22
25
  import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
@@ -28,6 +28,9 @@ const NODES_COLUMNS_IDS = {
28
28
  Tablets: 'Tablets',
29
29
  TopNodesLoadAverage: 'TopNodesLoadAverage',
30
30
  TopNodesMemory: 'TopNodesMemory',
31
+ SharedCacheUsage: 'SharedCacheUsage',
32
+ MemoryUsedInAlloc: 'MemoryUsedInAlloc',
33
+ TotalSessions: 'TotalSessions',
31
34
  };
32
35
 
33
36
  interface GetNodesColumnsProps {
@@ -184,23 +187,61 @@ const topNodesLoadAverageColumn: NodesColumn = {
184
187
 
185
188
  const topNodesMemoryColumn: NodesColumn = {
186
189
  name: NODES_COLUMNS_IDS.TopNodesMemory,
187
- header: 'Memory',
188
- render: ({row}) =>
189
- row.MemoryUsed ? (
190
- <ProgressViewer
191
- value={row.MemoryUsed}
192
- capacity={row.MemoryLimit}
193
- formatValues={formatStorageValuesToGb}
194
- colorizeProgress={true}
195
- />
196
- ) : (
197
- '—'
198
- ),
190
+ header: 'Process',
191
+ render: ({row}) => (
192
+ <ProgressViewer
193
+ value={row.MemoryUsed}
194
+ capacity={row.MemoryLimit}
195
+ formatValues={formatStorageValuesToGb}
196
+ colorizeProgress={true}
197
+ />
198
+ ),
199
+ align: DataTable.LEFT,
200
+ width: 140,
201
+ sortable: false,
202
+ };
203
+
204
+ const sharedCacheUsageColumn: NodesColumn = {
205
+ name: NODES_COLUMNS_IDS.SharedCacheUsage,
206
+ header: 'Tablet Cache',
207
+ render: ({row}) => (
208
+ <ProgressViewer
209
+ value={row.SharedCacheUsed}
210
+ capacity={row.SharedCacheLimit}
211
+ formatValues={formatStorageValuesToGb}
212
+ colorizeProgress={true}
213
+ />
214
+ ),
215
+ align: DataTable.LEFT,
216
+ width: 140,
217
+ sortable: false,
218
+ };
219
+
220
+ const memoryUsedInAllocColumn: NodesColumn = {
221
+ name: NODES_COLUMNS_IDS.MemoryUsedInAlloc,
222
+ header: 'Query Runtime',
223
+ render: ({row}) => (
224
+ <ProgressViewer
225
+ value={row.MemoryUsedInAlloc}
226
+ capacity={row.MemoryLimit}
227
+ formatValues={formatStorageValuesToGb}
228
+ colorizeProgress={true}
229
+ />
230
+ ),
199
231
  align: DataTable.LEFT,
200
232
  width: 140,
201
233
  sortable: false,
202
234
  };
203
235
 
236
+ const sessionsColumn: NodesColumn = {
237
+ name: NODES_COLUMNS_IDS.TotalSessions,
238
+ header: 'Sessions',
239
+ render: ({row}) => row.TotalSessions ?? '—',
240
+ align: DataTable.RIGHT,
241
+ width: 100,
242
+ sortable: false,
243
+ };
244
+
204
245
  export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps): NodesColumn[] {
205
246
  return [
206
247
  nodeIdColumn,
@@ -241,8 +282,11 @@ export function getTopNodesByMemoryColumns({
241
282
  nodeIdColumn,
242
283
  getHostColumn(getNodeRef),
243
284
  uptimeColumn,
244
- topNodesMemoryColumn,
245
285
  topNodesLoadAverageColumn,
286
+ topNodesMemoryColumn,
287
+ sharedCacheUsageColumn,
288
+ memoryUsedInAllocColumn,
289
+ sessionsColumn,
246
290
  getTabletsColumn(tabletsPath),
247
291
  ];
248
292
  }
@@ -18,6 +18,8 @@ import {changeFilter, ProblemFilterValues} from '../../../../store/reducers/sett
18
18
  import {AutoFetcher} from '../../../../utils/autofetcher';
19
19
  import {getDefaultNodePath} from '../../../Node/NodePages';
20
20
 
21
+ import {getConnectedNodesCount} from './utils';
22
+
21
23
  import './Network.scss';
22
24
 
23
25
  const b = cn('network');
@@ -145,11 +147,6 @@ class Network extends React.Component {
145
147
  );
146
148
  };
147
149
 
148
- getConnectedNodesCount = (peers) => {
149
- const res = peers?.reduce((acc, item) => (item.Connected ? acc + 1 : acc), 0);
150
- return res;
151
- };
152
-
153
150
  renderNodes = (nodes, isRight) => {
154
151
  const {showId, showRacks, clickedNode} = this.state;
155
152
  let problemNodesCount = 0;
@@ -171,9 +168,7 @@ class Network extends React.Component {
171
168
  let capacity, connected;
172
169
  if (!isRight && nodeInfo?.Peers) {
173
170
  capacity = Object.keys(nodeInfo?.Peers).length;
174
- connected = this.getConnectedNodesCount(
175
- nodeInfo?.Peers,
176
- );
171
+ connected = getConnectedNodesCount(nodeInfo?.Peers);
177
172
  }
178
173
 
179
174
  if (
@@ -214,7 +209,7 @@ class Network extends React.Component {
214
209
  let capacity, connected;
215
210
  if (!isRight) {
216
211
  capacity = nodeInfo?.Peers?.length;
217
- connected = this.getConnectedNodesCount(nodeInfo?.Peers);
212
+ connected = getConnectedNodesCount(nodeInfo?.Peers);
218
213
  }
219
214
 
220
215
  if (
@@ -234,7 +229,7 @@ class Network extends React.Component {
234
229
  capacity={nodeInfo?.Peers && nodeInfo?.Peers.length}
235
230
  connected={
236
231
  nodeInfo?.Peers &&
237
- this.getConnectedNodesCount(nodeInfo?.Peers)
232
+ getConnectedNodesCount(nodeInfo?.Peers)
238
233
  }
239
234
  onMouseEnter={showTooltip}
240
235
  onMouseLeave={hideTooltip}
@@ -0,0 +1,6 @@
1
+ import type {TNetNodePeerInfo} from '../../../../types/api/netInfo';
2
+
3
+ // determine how many nodes have status Connected "true"
4
+ export const getConnectedNodesCount = (peers: TNetNodePeerInfo[] | undefined) => {
5
+ return peers?.reduce((acc, item) => (item.Connected ? acc + 1 : acc), 0);
6
+ };
@@ -1,16 +1,20 @@
1
1
  import {useDispatch} from 'react-redux';
2
2
  import {useCallback} from 'react';
3
3
 
4
- import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
4
+ import {useAutofetcher, useSearchQuery, useTypedSelector} from '../../../../../utils/hooks';
5
5
  import {
6
6
  getTopNodesByCpu,
7
7
  selectTopNodesByCpu,
8
8
  setDataWasNotLoaded,
9
9
  } from '../../../../../store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu';
10
+ import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
10
11
  import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
11
12
  import {getTopNodesByCpuColumns} from '../../../../Nodes/getNodesColumns';
12
- import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
13
13
 
14
+ import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
15
+
16
+ import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
17
+ import {getSectionTitle} from '../getSectionTitle';
14
18
  import i18n from '../i18n';
15
19
 
16
20
  interface TopNodesByCpuProps {
@@ -21,6 +25,8 @@ interface TopNodesByCpuProps {
21
25
  export function TopNodesByCpu({path, additionalNodesProps}: TopNodesByCpuProps) {
22
26
  const dispatch = useDispatch();
23
27
 
28
+ const query = useSearchQuery();
29
+
24
30
  const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByCpu);
25
31
  const {autorefresh} = useTypedSelector((state) => state.schema);
26
32
  const topNodes = useTypedSelector(selectTopNodesByCpu);
@@ -39,11 +45,20 @@ export function TopNodesByCpu({path, additionalNodesProps}: TopNodesByCpuProps)
39
45
 
40
46
  useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
41
47
 
48
+ const title = getSectionTitle({
49
+ entity: i18n('nodes'),
50
+ postfix: i18n('by-pools-usage'),
51
+ link: getTenantPath({
52
+ ...query,
53
+ [TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.nodes,
54
+ }),
55
+ });
56
+
42
57
  return (
43
58
  <TenantOverviewTableLayout
44
59
  data={topNodes || []}
45
60
  columns={columns}
46
- title="Top nodes by pools usage"
61
+ title={title}
47
62
  loading={loading}
48
63
  wasLoaded={wasLoaded}
49
64
  error={error}