ydb-embedded-ui 4.17.0 → 4.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/components/FullNodeViewer/FullNodeViewer.scss +1 -1
  3. package/dist/components/FullNodeViewer/FullNodeViewer.tsx +15 -6
  4. package/dist/components/InfoViewer/formatters/common.ts +1 -1
  5. package/dist/components/InfoViewer/formatters/pqGroup.ts +1 -1
  6. package/dist/components/InfoViewer/formatters/table.ts +6 -1
  7. package/dist/components/ProgressViewer/ProgressViewer.tsx +105 -0
  8. package/dist/components/TooltipsContent/TabletTooltipContent/TabletTooltipContent.tsx +1 -1
  9. package/dist/containers/AsideNavigation/AsideNavigation.tsx +3 -1
  10. package/dist/containers/Authentication/Authentication.tsx +14 -4
  11. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +2 -2
  12. package/dist/containers/Heatmap/Heatmap.tsx +1 -1
  13. package/dist/containers/Heatmap/Histogram/Histogram.js +1 -1
  14. package/dist/containers/Node/NodeStructure/Pdisk.tsx +2 -2
  15. package/dist/containers/Node/NodeStructure/Vdisk.tsx +5 -2
  16. package/dist/containers/Nodes/getNodesColumns.tsx +3 -2
  17. package/dist/containers/Storage/PDisk/PDisk.tsx +1 -1
  18. package/dist/containers/Storage/PDiskPopup/PDiskPopup.tsx +2 -2
  19. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +3 -232
  20. package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx +278 -0
  21. package/dist/containers/Storage/VDisk/VDisk.tsx +1 -1
  22. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +1 -1
  23. package/dist/containers/Tablet/TabletInfo/TabletInfo.tsx +1 -1
  24. package/dist/containers/Tablet/TabletTable/TabletTable.tsx +1 -1
  25. package/dist/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.tsx +1 -1
  26. package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +1 -1
  27. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +3 -3
  28. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +1 -1
  29. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +1 -1
  30. package/dist/containers/Tenant/Diagnostics/Partitions/columns/columns.tsx +1 -1
  31. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +2 -3
  32. package/dist/containers/Tenant/Diagnostics/TenantOverview/OldTenantOverview.tsx +1 -1
  33. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +22 -6
  34. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.scss +41 -0
  35. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx +68 -0
  36. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +76 -0
  37. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +105 -0
  38. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +2 -0
  39. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +2 -0
  40. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +1 -1
  41. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +1 -1
  42. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +1 -1
  43. package/dist/containers/Tenants/Tenants.tsx +5 -1
  44. package/dist/containers/UserSettings/i18n/en.json +1 -1
  45. package/dist/containers/UserSettings/i18n/ru.json +1 -1
  46. package/dist/containers/UserSettings/settings.ts +2 -2
  47. package/dist/containers/Versions/NodesTable/NodesTable.tsx +3 -2
  48. package/dist/services/api.ts +1 -1
  49. package/dist/store/reducers/clusterNodes/clusterNodes.tsx +1 -1
  50. package/dist/store/reducers/index.ts +4 -0
  51. package/dist/store/reducers/node/selectors.ts +1 -1
  52. package/dist/store/reducers/nodes/selectors.ts +1 -1
  53. package/dist/store/reducers/nodes/types.ts +1 -1
  54. package/dist/store/reducers/nodes/utils.ts +1 -1
  55. package/dist/store/reducers/settings/settings.ts +4 -4
  56. package/dist/store/reducers/storage/types.ts +1 -1
  57. package/dist/store/reducers/storage/utils.ts +21 -12
  58. package/dist/store/reducers/tenantOverview/executeTopTables/executeTopTables.ts +93 -0
  59. package/dist/store/reducers/tenantOverview/executeTopTables/types.ts +14 -0
  60. package/dist/store/reducers/tenantOverview/topStorageGroups/topStorageGroups.ts +98 -0
  61. package/dist/store/reducers/tenantOverview/topStorageGroups/types.ts +29 -0
  62. package/dist/store/reducers/tenantOverview/topStorageGroups/utils.ts +20 -0
  63. package/dist/store/reducers/tenants/utils.ts +30 -20
  64. package/dist/styles/constants.scss +4 -0
  65. package/dist/types/additionalProps.ts +1 -1
  66. package/dist/types/api/storage.ts +1 -1
  67. package/dist/types/api/tenant.ts +21 -8
  68. package/dist/types/api/vdisk.ts +1 -1
  69. package/dist/utils/bytesParsers/__test__/formatBytes.test.ts +10 -1
  70. package/dist/utils/bytesParsers/formatBytes.ts +3 -3
  71. package/dist/utils/constants.ts +10 -1
  72. package/dist/utils/dataFormatters/__test__/roundToSignificant.test.ts +22 -0
  73. package/dist/utils/dataFormatters/dataFormatters.ts +150 -0
  74. package/dist/utils/dataFormatters/i18n/en.json +3 -0
  75. package/dist/utils/dataFormatters/i18n/ru.json +3 -0
  76. package/dist/utils/index.js +0 -102
  77. package/package.json +1 -1
  78. package/dist/components/ProgressViewer/ProgressViewer.js +0 -92
  79. package/dist/utils/formatCPU/formatCPU.ts +0 -20
  80. package/dist/utils/formatCPU/i18n/en.json +0 -3
  81. package/dist/utils/formatCPU/i18n/ru.json +0 -3
  82. /package/dist/utils/{formatCPU → dataFormatters}/i18n/index.ts +0 -0
@@ -1,25 +1,12 @@
1
- import cn from 'bem-cn-lite';
2
-
3
1
  import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
4
- import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
5
2
 
6
- import type {ValueOf} from '../../../types/common';
7
3
  import type {NodesMap} from '../../../types/store/nodesList';
8
4
  import type {PreparedStorageGroup, VisibleEntities} from '../../../store/reducers/storage/types';
9
5
  import type {HandleSort} from '../../../utils/hooks/useTableSort';
10
-
11
6
  import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
12
- import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
13
- import {stringifyVdiskId} from '../../../utils';
14
- import {getUsage, isFullVDiskData, isSortableStorageProperty} from '../../../utils/storage';
15
-
16
- import shieldIcon from '../../../assets/icons/shield.svg';
17
- import {Stack} from '../../../components/Stack/Stack';
18
- import EntityStatus from '../../../components/EntityStatus/EntityStatus';
19
-
7
+ import {isSortableStorageProperty} from '../../../utils/storage';
20
8
  import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
21
- import {VDisk} from '../VDisk';
22
- import {getDegradedSeverity, getUsageSeverityForStorageGroup} from '../utils';
9
+ import {getStorageGroupsColumns} from './getStorageGroupsColumns';
23
10
 
24
11
  import i18n from './i18n';
25
12
  import './StorageGroups.scss';
@@ -39,8 +26,6 @@ const TableColumnsIds = {
39
26
  Degraded: 'Degraded',
40
27
  } as const;
41
28
 
42
- type TableColumnId = ValueOf<typeof TableColumnsIds>;
43
-
44
29
  interface StorageGroupsProps {
45
30
  data: PreparedStorageGroup[];
46
31
  nodes?: NodesMap;
@@ -51,23 +36,6 @@ interface StorageGroupsProps {
51
36
  handleSort?: HandleSort;
52
37
  }
53
38
 
54
- const tableColumnsNames: Record<TableColumnId, string> = {
55
- PoolName: 'Pool Name',
56
- Kind: 'Type',
57
- Erasure: 'Erasure',
58
- GroupId: 'Group ID',
59
- Used: 'Used',
60
- Limit: 'Limit',
61
- UsedSpaceFlag: 'Space',
62
- Usage: 'Usage',
63
- Read: 'Read',
64
- Write: 'Write',
65
- VDisks: 'VDisks',
66
- Degraded: 'Degraded',
67
- };
68
-
69
- const b = cn('global-storage-groups');
70
-
71
39
  export function StorageGroups({
72
40
  data,
73
41
  tableSettings,
@@ -77,204 +45,7 @@ export function StorageGroups({
77
45
  sort,
78
46
  handleSort,
79
47
  }: StorageGroupsProps) {
80
- const rawColumns: Column<PreparedStorageGroup>[] = [
81
- {
82
- name: TableColumnsIds.PoolName,
83
- header: tableColumnsNames[TableColumnsIds.PoolName],
84
- width: 250,
85
- render: ({row}) => {
86
- const splitted = row.PoolName?.split('/');
87
- return (
88
- <div className={b('pool-name-wrapper')}>
89
- {splitted && (
90
- <Popover
91
- content={row.PoolName}
92
- placement={['right']}
93
- behavior={PopoverBehavior.Immediate}
94
- >
95
- <span className={b('pool-name')}>
96
- {splitted[splitted.length - 1]}
97
- </span>
98
- </Popover>
99
- )}
100
- </div>
101
- );
102
- },
103
- align: DataTable.LEFT,
104
- },
105
- {
106
- name: TableColumnsIds.Kind,
107
- header: tableColumnsNames[TableColumnsIds.Kind],
108
- // prettier-ignore
109
- render: ({row}) => (
110
- <>
111
- <Label>{row.Kind || '—'}</Label>
112
- {' '}
113
- {row.Encryption && (
114
- <Popover
115
- content={i18n('encrypted')}
116
- placement="right"
117
- behavior={PopoverBehavior.Immediate}
118
- >
119
- <Label>
120
- <Icon data={shieldIcon} />
121
- </Label>
122
- </Popover>
123
- )}
124
- </>
125
- ),
126
- },
127
- {
128
- name: TableColumnsIds.Erasure,
129
- header: tableColumnsNames[TableColumnsIds.Erasure],
130
- render: ({row}) => (row.ErasureSpecies ? row.ErasureSpecies : '-'),
131
- align: DataTable.LEFT,
132
- },
133
- {
134
- name: TableColumnsIds.Degraded,
135
- header: tableColumnsNames[TableColumnsIds.Degraded],
136
- width: 100,
137
- render: ({row}) =>
138
- row.Degraded ? (
139
- <Label theme={getDegradedSeverity(row)}>Degraded: {row.Degraded}</Label>
140
- ) : (
141
- '-'
142
- ),
143
- align: DataTable.LEFT,
144
- defaultOrder: DataTable.DESCENDING,
145
- },
146
- {
147
- name: TableColumnsIds.Usage,
148
- header: tableColumnsNames[TableColumnsIds.Usage],
149
- width: 100,
150
- render: ({row}) => {
151
- // without a limit the usage can be evaluated as 0,
152
- // but the absence of a value is more clear
153
- return row.Limit ? (
154
- <Label
155
- theme={getUsageSeverityForStorageGroup(row.Usage)}
156
- className={b('usage-label', {overload: row.Usage >= 90})}
157
- >
158
- {row.Usage}%
159
- </Label>
160
- ) : (
161
- '-'
162
- );
163
- },
164
- // without a limit exclude usage from sort to display at the bottom
165
- sortAccessor: (row) => (row.Limit ? getUsage(row) : null),
166
- align: DataTable.LEFT,
167
- },
168
- {
169
- name: TableColumnsIds.GroupId,
170
- header: tableColumnsNames[TableColumnsIds.GroupId],
171
- width: 130,
172
- render: ({row}) => {
173
- return <span className={b('group-id')}>{row.GroupID}</span>;
174
- },
175
- sortAccessor: (row) => Number(row.GroupID),
176
- align: DataTable.RIGHT,
177
- },
178
- {
179
- name: TableColumnsIds.Used,
180
- header: tableColumnsNames[TableColumnsIds.Used],
181
- width: 100,
182
- render: ({row}) => {
183
- return bytesToGB(row.Used, true);
184
- },
185
- align: DataTable.RIGHT,
186
- },
187
- {
188
- name: TableColumnsIds.Limit,
189
- header: tableColumnsNames[TableColumnsIds.Limit],
190
- width: 100,
191
- render: ({row}) => {
192
- return bytesToGB(row.Limit);
193
- },
194
- align: DataTable.RIGHT,
195
- },
196
- {
197
- name: TableColumnsIds.UsedSpaceFlag,
198
- header: tableColumnsNames[TableColumnsIds.UsedSpaceFlag],
199
- width: 110,
200
- render: ({row}) => {
201
- const value = row.UsedSpaceFlag;
202
-
203
- let color = 'Red';
204
-
205
- if (value < 100) {
206
- color = 'Green';
207
- } else if (value < 10000) {
208
- color = 'Yellow';
209
- } else if (value < 1000000) {
210
- color = 'Orange';
211
- }
212
- return <EntityStatus status={color} />;
213
- },
214
- align: DataTable.CENTER,
215
- },
216
-
217
- {
218
- name: TableColumnsIds.Read,
219
- header: tableColumnsNames[TableColumnsIds.Read],
220
- width: 100,
221
- render: ({row}) => {
222
- return row.Read ? bytesToSpeed(row.Read) : '-';
223
- },
224
- align: DataTable.RIGHT,
225
- },
226
- {
227
- name: TableColumnsIds.Write,
228
- header: tableColumnsNames[TableColumnsIds.Write],
229
- width: 100,
230
- render: ({row}) => {
231
- return row.Write ? bytesToSpeed(row.Write) : '-';
232
- },
233
- align: DataTable.RIGHT,
234
- },
235
- {
236
- name: TableColumnsIds.VDisks,
237
- className: b('vdisks-column'),
238
- header: tableColumnsNames[TableColumnsIds.VDisks],
239
- render: ({row}) => (
240
- <div className={b('vdisks-wrapper')}>
241
- {row.VDisks?.map((vDisk) => {
242
- const donors = vDisk.Donors;
243
-
244
- return donors && donors.length > 0 ? (
245
- <Stack
246
- className={b('vdisks-item')}
247
- key={stringifyVdiskId(vDisk.VDiskId)}
248
- >
249
- <VDisk data={vDisk} nodes={nodes} />
250
- {donors.map((donor) => {
251
- const isFullData = isFullVDiskData(donor);
252
-
253
- return (
254
- <VDisk
255
- data={isFullData ? donor : {...donor, DonorMode: true}}
256
- // donor and acceptor are always in the same group
257
- nodes={nodes}
258
- key={stringifyVdiskId(
259
- isFullData ? donor.VDiskId : donor,
260
- )}
261
- />
262
- );
263
- })}
264
- </Stack>
265
- ) : (
266
- <div className={b('vdisks-item')} key={stringifyVdiskId(vDisk.VDiskId)}>
267
- <VDisk data={vDisk} nodes={nodes} />
268
- </div>
269
- );
270
- })}
271
- </div>
272
- ),
273
- align: DataTable.CENTER,
274
- sortable: false,
275
- width: 900,
276
- },
277
- ];
48
+ const rawColumns: Column<PreparedStorageGroup>[] = getStorageGroupsColumns(nodes);
278
49
 
279
50
  let columns = rawColumns.map((column) => ({
280
51
  ...column,
@@ -0,0 +1,278 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import DataTable, {type Column} from '@gravity-ui/react-data-table';
4
+ import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
5
+
6
+ import shieldIcon from '../../../assets/icons/shield.svg';
7
+ import type {ValueOf} from '../../../types/common';
8
+ import type {NodesMap} from '../../../types/store/nodesList';
9
+ import type {PreparedStorageGroup} from '../../../store/reducers/storage/types';
10
+ import {getUsage, isFullVDiskData} from '../../../utils/storage';
11
+ import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
12
+ import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
13
+ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
14
+ import {Stack} from '../../../components/Stack/Stack';
15
+ import {VDisk} from '../VDisk';
16
+ import {getDegradedSeverity, getUsageSeverityForStorageGroup} from '../utils';
17
+ import i18n from './i18n';
18
+ import './StorageGroups.scss';
19
+
20
+ const b = cn('global-storage-groups');
21
+
22
+ const GROUPS_COLUMNS_IDS = {
23
+ PoolName: 'PoolName',
24
+ Kind: 'Kind',
25
+ Erasure: 'Erasure',
26
+ GroupId: 'GroupId',
27
+ Used: 'Used',
28
+ Limit: 'Limit',
29
+ Usage: 'Usage',
30
+ UsedSpaceFlag: 'UsedSpaceFlag',
31
+ Read: 'Read',
32
+ Write: 'Write',
33
+ VDisks: 'VDisks',
34
+ Degraded: 'Degraded',
35
+ } as const;
36
+
37
+ type GroupsColumns = ValueOf<typeof GROUPS_COLUMNS_IDS>;
38
+
39
+ const tableColumnsNames: Record<GroupsColumns, string> = {
40
+ PoolName: 'Pool Name',
41
+ Kind: 'Type',
42
+ Erasure: 'Erasure',
43
+ GroupId: 'Group ID',
44
+ Used: 'Used',
45
+ Limit: 'Limit',
46
+ UsedSpaceFlag: 'Space',
47
+ Usage: 'Usage',
48
+ Read: 'Read',
49
+ Write: 'Write',
50
+ VDisks: 'VDisks',
51
+ Degraded: 'Degraded',
52
+ };
53
+
54
+ const poolNameColumn: Column<PreparedStorageGroup> = {
55
+ name: GROUPS_COLUMNS_IDS.PoolName,
56
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.PoolName],
57
+ width: 250,
58
+ render: ({row}) => {
59
+ const splitted = row.PoolName?.split('/');
60
+ return (
61
+ <div className={b('pool-name-wrapper')}>
62
+ {splitted && (
63
+ <Popover
64
+ content={row.PoolName}
65
+ placement={['right']}
66
+ behavior={PopoverBehavior.Immediate}
67
+ >
68
+ <span className={b('pool-name')}>{splitted[splitted.length - 1]}</span>
69
+ </Popover>
70
+ )}
71
+ </div>
72
+ );
73
+ },
74
+ align: DataTable.LEFT,
75
+ };
76
+
77
+ const kindColumn: Column<PreparedStorageGroup> = {
78
+ name: GROUPS_COLUMNS_IDS.Kind,
79
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.Kind],
80
+ // prettier-ignore
81
+ render: ({row}) => (
82
+ <>
83
+ <Label>{row.Kind || '—'}</Label>
84
+ {' '}
85
+ {row.Encryption && (
86
+ <Popover
87
+ content={i18n('encrypted')}
88
+ placement="right"
89
+ behavior={PopoverBehavior.Immediate}
90
+ >
91
+ <Label>
92
+ <Icon data={shieldIcon} />
93
+ </Label>
94
+ </Popover>
95
+ )}
96
+ </>
97
+ ),
98
+ sortable: false,
99
+ };
100
+
101
+ const erasureColumn: Column<PreparedStorageGroup> = {
102
+ name: GROUPS_COLUMNS_IDS.Erasure,
103
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.Erasure],
104
+ render: ({row}) => (row.ErasureSpecies ? row.ErasureSpecies : '-'),
105
+ align: DataTable.LEFT,
106
+ sortable: false,
107
+ };
108
+
109
+ const degradedColumn: Column<PreparedStorageGroup> = {
110
+ name: GROUPS_COLUMNS_IDS.Degraded,
111
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.Degraded],
112
+ width: 100,
113
+ render: ({row}) =>
114
+ row.Degraded ? (
115
+ <Label theme={getDegradedSeverity(row)}>Degraded: {row.Degraded}</Label>
116
+ ) : (
117
+ '-'
118
+ ),
119
+ align: DataTable.LEFT,
120
+ defaultOrder: DataTable.DESCENDING,
121
+ };
122
+
123
+ const usageColumn: Column<PreparedStorageGroup> = {
124
+ name: GROUPS_COLUMNS_IDS.Usage,
125
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.Usage],
126
+ width: 100,
127
+ render: ({row}) => {
128
+ // without a limit the usage can be evaluated as 0,
129
+ // but the absence of a value is more clear
130
+ return row.Limit ? (
131
+ <Label
132
+ theme={getUsageSeverityForStorageGroup(row.Usage)}
133
+ className={b('usage-label', {overload: row.Usage >= 90})}
134
+ >
135
+ {row.Usage}%
136
+ </Label>
137
+ ) : (
138
+ '-'
139
+ );
140
+ },
141
+ // without a limit exclude usage from sort to display at the bottom
142
+ sortAccessor: (row) => (row.Limit ? getUsage(row) : null),
143
+ align: DataTable.LEFT,
144
+ sortable: false,
145
+ };
146
+
147
+ const groupIdColumn: Column<PreparedStorageGroup> = {
148
+ name: GROUPS_COLUMNS_IDS.GroupId,
149
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.GroupId],
150
+ width: 130,
151
+ render: ({row}) => {
152
+ return <span className={b('group-id')}>{row.GroupID}</span>;
153
+ },
154
+ sortAccessor: (row) => Number(row.GroupID),
155
+ align: DataTable.RIGHT,
156
+ sortable: false,
157
+ };
158
+
159
+ const usedColumn: Column<PreparedStorageGroup> = {
160
+ name: GROUPS_COLUMNS_IDS.Used,
161
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.Used],
162
+ width: 100,
163
+ render: ({row}) => {
164
+ return bytesToGB(row.Used, true);
165
+ },
166
+ align: DataTable.RIGHT,
167
+ sortable: false,
168
+ };
169
+
170
+ const limitColumn: Column<PreparedStorageGroup> = {
171
+ name: GROUPS_COLUMNS_IDS.Limit,
172
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.Limit],
173
+ width: 100,
174
+ render: ({row}) => {
175
+ return bytesToGB(row.Limit);
176
+ },
177
+ align: DataTable.RIGHT,
178
+ sortable: false,
179
+ };
180
+
181
+ const usedSpaceFlagColumn: Column<PreparedStorageGroup> = {
182
+ name: GROUPS_COLUMNS_IDS.UsedSpaceFlag,
183
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.UsedSpaceFlag],
184
+ width: 110,
185
+ render: ({row}) => {
186
+ const value = row.UsedSpaceFlag;
187
+
188
+ let color = 'Red';
189
+
190
+ if (value < 100) {
191
+ color = 'Green';
192
+ } else if (value < 10000) {
193
+ color = 'Yellow';
194
+ } else if (value < 1000000) {
195
+ color = 'Orange';
196
+ }
197
+ return <EntityStatus status={color} />;
198
+ },
199
+ align: DataTable.CENTER,
200
+ };
201
+
202
+ const readColumn: Column<PreparedStorageGroup> = {
203
+ name: GROUPS_COLUMNS_IDS.Read,
204
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.Read],
205
+ width: 100,
206
+ render: ({row}) => {
207
+ return row.Read ? bytesToSpeed(row.Read) : '-';
208
+ },
209
+ align: DataTable.RIGHT,
210
+ };
211
+
212
+ const writeColumn: Column<PreparedStorageGroup> = {
213
+ name: GROUPS_COLUMNS_IDS.Write,
214
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.Write],
215
+ width: 100,
216
+ render: ({row}) => {
217
+ return row.Write ? bytesToSpeed(row.Write) : '-';
218
+ },
219
+ align: DataTable.RIGHT,
220
+ };
221
+
222
+ const getVdiscksColumn = (nodes?: NodesMap): Column<PreparedStorageGroup> => ({
223
+ name: GROUPS_COLUMNS_IDS.VDisks,
224
+ className: b('vdisks-column'),
225
+ header: tableColumnsNames[GROUPS_COLUMNS_IDS.VDisks],
226
+ render: ({row}) => (
227
+ <div className={b('vdisks-wrapper')}>
228
+ {row.VDisks?.map((vDisk) => {
229
+ const donors = vDisk.Donors;
230
+
231
+ return donors && donors.length > 0 ? (
232
+ <Stack className={b('vdisks-item')} key={stringifyVdiskId(vDisk.VDiskId)}>
233
+ <VDisk data={vDisk} nodes={nodes} />
234
+ {donors.map((donor) => {
235
+ const isFullData = isFullVDiskData(donor);
236
+
237
+ return (
238
+ <VDisk
239
+ data={isFullData ? donor : {...donor, DonorMode: true}}
240
+ // donor and acceptor are always in the same group
241
+ nodes={nodes}
242
+ key={stringifyVdiskId(isFullData ? donor.VDiskId : donor)}
243
+ />
244
+ );
245
+ })}
246
+ </Stack>
247
+ ) : (
248
+ <div className={b('vdisks-item')} key={stringifyVdiskId(vDisk.VDiskId)}>
249
+ <VDisk data={vDisk} nodes={nodes} />
250
+ </div>
251
+ );
252
+ })}
253
+ </div>
254
+ ),
255
+ align: DataTable.CENTER,
256
+ width: 900,
257
+ });
258
+
259
+ export const getStorageTopGroupsColumns = (): Column<PreparedStorageGroup>[] => {
260
+ return [groupIdColumn, kindColumn, erasureColumn, usageColumn, usedColumn, limitColumn];
261
+ };
262
+
263
+ export const getStorageGroupsColumns = (nodes?: NodesMap): Column<PreparedStorageGroup>[] => {
264
+ return [
265
+ poolNameColumn,
266
+ kindColumn,
267
+ erasureColumn,
268
+ degradedColumn,
269
+ usageColumn,
270
+ groupIdColumn,
271
+ usedColumn,
272
+ limitColumn,
273
+ usedSpaceFlagColumn,
274
+ readColumn,
275
+ writeColumn,
276
+ getVdiscksColumn(nodes),
277
+ ];
278
+ };
@@ -8,7 +8,7 @@ import {InternalLink} from '../../../components/InternalLink';
8
8
  import routes, {createHref} from '../../../routes';
9
9
  import {EFlag} from '../../../types/api/enums';
10
10
  import {EVDiskState, TVDiskStateInfo} from '../../../types/api/vdisk';
11
- import {stringifyVdiskId} from '../../../utils';
11
+ import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
12
12
  import {isFullVDiskData} from '../../../utils/storage';
13
13
 
14
14
  import {STRUCTURE} from '../../Node/NodePages';
@@ -9,7 +9,7 @@ import {InfoViewer, InfoViewerItem} from '../../../components/InfoViewer';
9
9
 
10
10
  import {EFlag} from '../../../types/api/enums';
11
11
  import type {TVDiskStateInfo} from '../../../types/api/vdisk';
12
- import {stringifyVdiskId} from '../../../utils';
12
+ import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
13
13
  import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
14
14
  import {isFullVDiskData} from '../../../utils/storage';
15
15
 
@@ -5,7 +5,7 @@ import {Link as UIKitLink} from '@gravity-ui/uikit';
5
5
  import {ETabletState, TTabletStateInfo} from '../../../types/api/tablet';
6
6
  import {InfoViewer, InfoViewerItem} from '../../../components/InfoViewer';
7
7
  import routes, {createHref} from '../../../routes';
8
- import {calcUptime} from '../../../utils';
8
+ import {calcUptime} from '../../../utils/dataFormatters/dataFormatters';
9
9
  import {getDefaultNodePath} from '../../Node/NodePages';
10
10
 
11
11
  import {b} from '../Tablet';
@@ -4,7 +4,7 @@ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
4
4
  import {InternalLink} from '../../../components/InternalLink/InternalLink';
5
5
 
6
6
  import type {ITabletPreparedHistoryItem} from '../../../types/store/tablet';
7
- import {calcUptime} from '../../../utils';
7
+ import {calcUptime} from '../../../utils/dataFormatters/dataFormatters';
8
8
  import {getDefaultNodePath} from '../../Node/NodePages';
9
9
 
10
10
  import {b} from '../Tablet';
@@ -1,7 +1,7 @@
1
1
  import block from 'bem-cn-lite';
2
2
 
3
3
  import type {IPreparedTopicStats} from '../../../../../types/store/topic';
4
- import {formatMsToUptime} from '../../../../../utils';
4
+ import {formatMsToUptime} from '../../../../../utils/dataFormatters/dataFormatters';
5
5
  import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
6
6
 
7
7
  import './ConsumersTopicStats.scss';
@@ -6,7 +6,7 @@ import type {IPreparedConsumerData} from '../../../../../types/store/topic';
6
6
  import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
7
7
  import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
8
8
  import {InternalLink} from '../../../../../components/InternalLink';
9
- import {formatMsToUptime} from '../../../../../utils';
9
+ import {formatMsToUptime} from '../../../../../utils/dataFormatters/dataFormatters';
10
10
  import routes, {createHref} from '../../../../../routes';
11
11
 
12
12
  import {TenantTabsGroups} from '../../../TenantPages';
@@ -8,7 +8,7 @@ import type {EPathType} from '../../../../types/api/schema';
8
8
  import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
9
9
  import {Icon} from '../../../../components/Icon';
10
10
  import {useSetting} from '../../../../utils/hooks';
11
- import {ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN} from '../../../../utils/constants';
11
+ import {DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS} from '../../../../utils/constants';
12
12
  import Overview from '../Overview/Overview';
13
13
  import {Healthcheck} from '../OldHealthcheck';
14
14
  import {TenantOverview} from '../TenantOverview/TenantOverview';
@@ -32,7 +32,7 @@ function DetailedOverview(props: DetailedOverviewProps) {
32
32
 
33
33
  const {currentSchemaPath} = useSelector((state: any) => state.schema);
34
34
 
35
- const [newTenantDiagnostics] = useSetting(ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN);
35
+ const [displayMetricsCards] = useSetting(DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS);
36
36
 
37
37
  const openModalHandler = () => {
38
38
  setIsModalVisible(true);
@@ -59,7 +59,7 @@ function DetailedOverview(props: DetailedOverviewProps) {
59
59
  };
60
60
 
61
61
  const renderTenantOverview = () => {
62
- if (newTenantDiagnostics) {
62
+ if (displayMetricsCards) {
63
63
  return (
64
64
  <div className={b('section')}>
65
65
  <TenantOverview
@@ -8,7 +8,7 @@ import type {
8
8
  import type {KeyValueRow} from '../../../../../types/api/query';
9
9
  import {EPathType} from '../../../../../types/api/schema';
10
10
  import {isNumeric} from '../../../../../utils/utils';
11
- import {formatBytes, formatNumber} from '../../../../../utils';
11
+ import {formatBytes, formatNumber} from '../../../../../utils/dataFormatters/dataFormatters';
12
12
  import {formatDurationToShortTimeFormat} from '../../../../../utils/timeParsers';
13
13
  import {formatObject, InfoViewerItem} from '../../../../../components/InfoViewer';
14
14
  import {
@@ -11,7 +11,7 @@ import {ResponseError} from '../../../../../components/Errors/ResponseError';
11
11
 
12
12
  import {useTypedSelector} from '../../../../../utils/hooks';
13
13
  import {formatDurationToShortTimeFormat} from '../../../../../utils/timeParsers';
14
- import {formatBps, formatBytes} from '../../../../../utils';
14
+ import {formatBps, formatBytes} from '../../../../../utils/dataFormatters/dataFormatters';
15
15
 
16
16
  import {selectPreparedTopicStats} from '../../../../../store/reducers/topic';
17
17
 
@@ -4,7 +4,7 @@ import block from 'bem-cn-lite';
4
4
  import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
5
5
  import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
6
6
  import {getDefaultNodePath} from '../../../../Node/NodePages';
7
- import {formatBytes, formatMsToUptime} from '../../../../../utils';
7
+ import {formatBytes, formatMsToUptime} from '../../../../../utils/dataFormatters/dataFormatters';
8
8
  import {isNumeric} from '../../../../../utils/utils';
9
9
 
10
10
  import {