ydb-embedded-ui 4.8.2 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/BasicNodeViewer/BasicNodeViewer.tsx +7 -4
  3. package/dist/components/EntityStatus/EntityStatus.js +3 -1
  4. package/dist/components/FormattedBytes/FormattedBytes.tsx +10 -0
  5. package/dist/components/FormattedBytes/utils.tsx +13 -0
  6. package/dist/components/FullNodeViewer/FullNodeViewer.tsx +73 -0
  7. package/dist/components/InfoViewer/formatters/table.ts +6 -5
  8. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -2
  9. package/dist/components/ProblemFilter/ProblemFilter.tsx +2 -2
  10. package/dist/components/SpeedMultiMeter/SpeedMultiMeter.tsx +4 -4
  11. package/dist/components/TruncatedQuery/{TruncatedQuery.js → TruncatedQuery.tsx} +10 -8
  12. package/dist/containers/AsideNavigation/AsideNavigation.tsx +6 -6
  13. package/dist/containers/Cluster/Cluster.tsx +10 -6
  14. package/dist/containers/Node/Node.tsx +3 -3
  15. package/dist/containers/Nodes/Nodes.tsx +3 -3
  16. package/dist/containers/Nodes/getNodesColumns.tsx +2 -2
  17. package/dist/containers/Storage/PDisk/PDisk.tsx +2 -7
  18. package/dist/containers/Storage/Storage.tsx +240 -0
  19. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +59 -57
  20. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +23 -25
  21. package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +27 -0
  22. package/dist/containers/Storage/StorageVisibleEntityFilter/StorageVisibleEntityFilter.tsx +31 -0
  23. package/dist/containers/Storage/UsageFilter/UsageFilter.scss +1 -0
  24. package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +17 -17
  25. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -3
  26. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -4
  27. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +0 -15
  28. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +10 -3
  29. package/dist/containers/Tenant/{Preview → Query/Preview}/Preview.scss +1 -1
  30. package/dist/containers/Tenant/Query/Preview/Preview.tsx +121 -0
  31. package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +1 -1
  32. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +23 -51
  33. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +20 -15
  34. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.tsx +74 -27
  35. package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.tsx +1 -1
  36. package/dist/containers/Tenant/Query/i18n/en.json +9 -2
  37. package/dist/containers/Tenant/Query/i18n/ru.json +9 -2
  38. package/dist/containers/Tenants/Tenants.tsx +269 -0
  39. package/dist/containers/UserSettings/i18n/en.json +1 -1
  40. package/dist/containers/UserSettings/i18n/ru.json +1 -1
  41. package/dist/services/api.ts +14 -16
  42. package/dist/store/reducers/executeQuery.ts +2 -3
  43. package/dist/store/reducers/explainQuery.ts +2 -2
  44. package/dist/store/reducers/index.ts +2 -2
  45. package/dist/store/reducers/{nodes.ts → nodes/nodes.ts} +33 -32
  46. package/dist/{types/store/nodes.ts → store/reducers/nodes/types.ts} +24 -27
  47. package/dist/store/reducers/partitions/types.ts +3 -3
  48. package/dist/store/reducers/settings/settings.ts +14 -4
  49. package/dist/store/reducers/settings/types.ts +3 -1
  50. package/dist/store/reducers/storage/constants.ts +10 -0
  51. package/dist/store/reducers/storage/selectors.ts +279 -0
  52. package/dist/store/reducers/storage/storage.ts +191 -0
  53. package/dist/store/reducers/storage/types.ts +92 -0
  54. package/dist/store/reducers/tenants/selectors.ts +46 -0
  55. package/dist/store/reducers/tenants/tenants.ts +21 -14
  56. package/dist/store/reducers/tenants/types.ts +20 -5
  57. package/dist/store/reducers/tenants/utils.ts +68 -0
  58. package/dist/types/additionalProps.ts +8 -0
  59. package/dist/types/api/storage.ts +1 -1
  60. package/dist/types/store/query.ts +5 -6
  61. package/dist/types/store/topic.ts +3 -3
  62. package/dist/utils/bytesParsers/__test__/formatBytes.test.ts +38 -0
  63. package/dist/utils/bytesParsers/convertBytesObjectToSpeed.ts +2 -2
  64. package/dist/utils/bytesParsers/formatBytes.ts +132 -0
  65. package/dist/utils/bytesParsers/i18n/en.json +1 -0
  66. package/dist/utils/bytesParsers/i18n/ru.json +1 -0
  67. package/dist/utils/bytesParsers/index.ts +1 -1
  68. package/dist/utils/constants.ts +1 -0
  69. package/dist/utils/index.js +5 -10
  70. package/dist/utils/nodes.ts +2 -2
  71. package/dist/utils/numeral.ts +8 -0
  72. package/dist/utils/query.ts +12 -0
  73. package/package.json +1 -1
  74. package/dist/components/FullNodeViewer/FullNodeViewer.js +0 -89
  75. package/dist/containers/Node/NodeOverview/NodeOverview.scss +0 -0
  76. package/dist/containers/Node/NodeOverview/NodeOverview.tsx +0 -21
  77. package/dist/containers/Storage/Storage.js +0 -372
  78. package/dist/containers/Tenant/Preview/Preview.js +0 -168
  79. package/dist/containers/Tenant/Query/QueryEditorControls/OldQueryEditorControls.tsx +0 -90
  80. package/dist/containers/Tenant/Query/QueryEditorControls/shared.ts +0 -18
  81. package/dist/containers/Tenants/Tenants.js +0 -363
  82. package/dist/store/reducers/storage.js +0 -438
  83. package/dist/utils/bytesParsers/formatBytesCustom.ts +0 -57
@@ -0,0 +1,240 @@
1
+ import {useCallback, useEffect} from 'react';
2
+ import {useDispatch} from 'react-redux';
3
+ import cn from 'bem-cn-lite';
4
+
5
+ import DataTable, {Settings} from '@gravity-ui/react-data-table';
6
+
7
+ import {Search} from '../../components/Search';
8
+ import {TableSkeleton} from '../../components/TableSkeleton/TableSkeleton';
9
+ import {UptimeFilter} from '../../components/UptimeFIlter';
10
+ import {AccessDenied} from '../../components/Errors/403';
11
+ import {EntitiesCount} from '../../components/EntitiesCount';
12
+
13
+ import type {StorageType, VisibleEntities} from '../../store/reducers/storage/types';
14
+ import {
15
+ getStorageInfo,
16
+ setInitialState,
17
+ setVisibleEntities,
18
+ setStorageTextFilter,
19
+ setUsageFilter,
20
+ setStorageType,
21
+ setNodesUptimeFilter,
22
+ setDataWasNotLoaded,
23
+ } from '../../store/reducers/storage/storage';
24
+ import {
25
+ selectFilteredGroups,
26
+ selectFilteredNodes,
27
+ selectStorageNodesCount,
28
+ selectStorageGroupsCount,
29
+ selectUsageFilterOptions,
30
+ } from '../../store/reducers/storage/selectors';
31
+ import {VISIBLE_ENTITIES, STORAGE_TYPES} from '../../store/reducers/storage/constants';
32
+ import {getNodesList, selectNodesMap} from '../../store/reducers/nodesList';
33
+ import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
34
+ import {AdditionalNodesInfo, NodesUptimeFilterValues} from '../../utils/nodes';
35
+ import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
36
+
37
+ import {StorageGroups} from './StorageGroups/StorageGroups';
38
+ import {StorageNodes} from './StorageNodes/StorageNodes';
39
+ import {StorageTypeFilter} from './StorageTypeFilter/StorageTypeFilter';
40
+ import {StorageVisibleEntityFilter} from './StorageVisibleEntityFilter/StorageVisibleEntityFilter';
41
+ import {UsageFilter} from './UsageFilter';
42
+
43
+ import './Storage.scss';
44
+
45
+ const b = cn('global-storage');
46
+
47
+ const tableSettings: Settings = {
48
+ ...DEFAULT_TABLE_SETTINGS,
49
+ defaultOrder: DataTable.DESCENDING,
50
+ };
51
+
52
+ interface StorageProps {
53
+ additionalNodesInfo?: AdditionalNodesInfo;
54
+ tenant?: string;
55
+ nodeId?: string;
56
+ }
57
+
58
+ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) => {
59
+ const dispatch = useDispatch();
60
+
61
+ const {autorefresh} = useTypedSelector((state) => state.schema);
62
+ const {
63
+ loading,
64
+ wasLoaded,
65
+ error,
66
+ type: storageType,
67
+ visible: visibleEntities,
68
+ filter,
69
+ usageFilter,
70
+ nodesUptimeFilter,
71
+ } = useTypedSelector((state) => state.storage);
72
+ const storageNodes = useTypedSelector(selectFilteredNodes);
73
+ const storageGroups = useTypedSelector(selectFilteredGroups);
74
+ const nodesCount = useTypedSelector(selectStorageNodesCount);
75
+ const groupsCount = useTypedSelector(selectStorageGroupsCount);
76
+ const nodesMap = useTypedSelector(selectNodesMap);
77
+ const usageFilterOptions = useTypedSelector(selectUsageFilterOptions);
78
+
79
+ useEffect(() => {
80
+ dispatch(getNodesList());
81
+
82
+ return () => {
83
+ // Clean data on component unmount
84
+ dispatch(setInitialState());
85
+ };
86
+ }, [dispatch]);
87
+
88
+ const fetchData = useCallback(
89
+ (isBackground: boolean) => {
90
+ if (!isBackground) {
91
+ dispatch(setDataWasNotLoaded());
92
+ }
93
+
94
+ dispatch(
95
+ getStorageInfo(
96
+ {
97
+ tenant,
98
+ nodeId,
99
+ visibleEntities,
100
+ type: storageType,
101
+ },
102
+ {
103
+ concurrentId: 'getStorageInfo',
104
+ },
105
+ ),
106
+ );
107
+ },
108
+ [dispatch, tenant, nodeId, visibleEntities, storageType],
109
+ );
110
+
111
+ const autorefreshEnabled = tenant ? autorefresh : true;
112
+
113
+ useAutofetcher(fetchData, [fetchData], autorefreshEnabled);
114
+
115
+ const handleUsageFilterChange = (value: string[]) => {
116
+ dispatch(setUsageFilter(value));
117
+ };
118
+
119
+ const handleTextFilterChange = (value: string) => {
120
+ dispatch(setStorageTextFilter(value));
121
+ };
122
+
123
+ const handleGroupVisibilityChange = (value: string) => {
124
+ dispatch(setVisibleEntities(value as VisibleEntities));
125
+ };
126
+
127
+ const handleStorageTypeChange = (value: string) => {
128
+ dispatch(setStorageType(value as StorageType));
129
+ };
130
+
131
+ const handleUptimeFilterChange = (value: string) => {
132
+ dispatch(setNodesUptimeFilter(value as NodesUptimeFilterValues));
133
+ };
134
+
135
+ const handleShowAllNodes = () => {
136
+ handleGroupVisibilityChange(VISIBLE_ENTITIES.all);
137
+ handleUptimeFilterChange(NodesUptimeFilterValues.All);
138
+ };
139
+
140
+ const renderLoader = () => {
141
+ return <TableSkeleton className={b('loader')} />;
142
+ };
143
+
144
+ const renderDataTable = () => {
145
+ return (
146
+ <div className={b('table-wrapper')}>
147
+ {storageType === STORAGE_TYPES.groups && (
148
+ <StorageGroups
149
+ visibleEntities={visibleEntities}
150
+ data={storageGroups}
151
+ tableSettings={tableSettings}
152
+ nodes={nodesMap}
153
+ onShowAll={() => handleGroupVisibilityChange(VISIBLE_ENTITIES.all)}
154
+ />
155
+ )}
156
+ {storageType === STORAGE_TYPES.nodes && (
157
+ <StorageNodes
158
+ visibleEntities={visibleEntities}
159
+ nodesUptimeFilter={nodesUptimeFilter}
160
+ data={storageNodes}
161
+ tableSettings={tableSettings}
162
+ onShowAll={handleShowAllNodes}
163
+ additionalNodesInfo={additionalNodesInfo}
164
+ />
165
+ )}
166
+ </div>
167
+ );
168
+ };
169
+
170
+ const renderEntitiesCount = () => {
171
+ const entityName = storageType === STORAGE_TYPES.groups ? 'Groups' : 'Nodes';
172
+ const count = storageType === STORAGE_TYPES.groups ? groupsCount : nodesCount;
173
+ const current =
174
+ storageType === STORAGE_TYPES.groups ? storageGroups.length : storageNodes.length;
175
+
176
+ return (
177
+ <EntitiesCount
178
+ label={entityName}
179
+ loading={loading && !wasLoaded}
180
+ total={count.total}
181
+ current={current}
182
+ />
183
+ );
184
+ };
185
+
186
+ const renderControls = () => {
187
+ return (
188
+ <div className={b('controls')}>
189
+ <div className={b('search')}>
190
+ <Search
191
+ placeholder={
192
+ storageType === STORAGE_TYPES.groups
193
+ ? 'Group ID, Pool name'
194
+ : 'Node ID, FQDN'
195
+ }
196
+ onChange={handleTextFilterChange}
197
+ value={filter}
198
+ />
199
+ </div>
200
+
201
+ <StorageTypeFilter value={storageType} onChange={handleStorageTypeChange} />
202
+ <StorageVisibleEntityFilter
203
+ value={visibleEntities}
204
+ onChange={handleGroupVisibilityChange}
205
+ />
206
+
207
+ {storageType === STORAGE_TYPES.nodes && (
208
+ <UptimeFilter value={nodesUptimeFilter} onChange={handleUptimeFilterChange} />
209
+ )}
210
+
211
+ {storageType === STORAGE_TYPES.groups && (
212
+ <UsageFilter
213
+ value={usageFilter}
214
+ onChange={handleUsageFilterChange}
215
+ groups={usageFilterOptions}
216
+ disabled={usageFilterOptions.length === 0}
217
+ />
218
+ )}
219
+ {renderEntitiesCount()}
220
+ </div>
221
+ );
222
+ };
223
+
224
+ const showLoader = loading && !wasLoaded;
225
+
226
+ if (error) {
227
+ if (error.status === 403) {
228
+ return <AccessDenied />;
229
+ }
230
+
231
+ return <div className={b()}>{error.statusText}</div>;
232
+ }
233
+
234
+ return (
235
+ <div className={b()}>
236
+ {renderControls()}
237
+ {showLoader ? renderLoader() : renderDataTable()}
238
+ </div>
239
+ );
240
+ };
@@ -1,25 +1,20 @@
1
- import _ from 'lodash';
2
1
  import cn from 'bem-cn-lite';
2
+
3
3
  import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
4
4
  import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
5
5
 
6
6
  import type {NodesMap} from '../../../types/store/nodesList';
7
+ import type {PreparedStorageGroup, VisibleEntities} from '../../../store/reducers/storage/types';
7
8
 
8
- import shieldIcon from '../../../assets/icons/shield.svg';
9
-
10
- import {Stack} from '../../../components/Stack/Stack';
11
- //@ts-ignore
12
- import EntityStatus from '../../../components/EntityStatus/EntityStatus';
13
-
14
- import {TVDiskStateInfo} from '../../../types/api/vdisk';
15
- //@ts-ignore
16
- import {VisibleEntities} from '../../../store/reducers/storage';
17
- //@ts-ignore
9
+ import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
18
10
  import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
19
- //@ts-ignore
20
11
  import {stringifyVdiskId} from '../../../utils';
21
12
  import {getUsage, isFullVDiskData} from '../../../utils/storage';
22
13
 
14
+ import shieldIcon from '../../../assets/icons/shield.svg';
15
+ import {Stack} from '../../../components/Stack/Stack';
16
+ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
17
+
23
18
  import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
24
19
  import {VDisk} from '../VDisk';
25
20
  import {getDegradedSeverity, getUsageSeverityForStorageGroup} from '../utils';
@@ -46,10 +41,10 @@ type TableColumnsIdsKeys = keyof typeof TableColumnsIds;
46
41
  type TableColumnsIdsValues = typeof TableColumnsIds[TableColumnsIdsKeys];
47
42
 
48
43
  interface StorageGroupsProps {
49
- data: any;
50
- nodes: NodesMap;
44
+ data: PreparedStorageGroup[];
45
+ nodes?: NodesMap;
51
46
  tableSettings: Settings;
52
- visibleEntities: keyof typeof VisibleEntities;
47
+ visibleEntities: VisibleEntities;
53
48
  onShowAll?: VoidFunction;
54
49
  }
55
50
 
@@ -70,21 +65,21 @@ const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
70
65
 
71
66
  const b = cn('global-storage-groups');
72
67
 
73
- function setSortOrder(visibleEntities: keyof typeof VisibleEntities): SortOrder | undefined {
68
+ function setSortOrder(visibleEntities: VisibleEntities): SortOrder | undefined {
74
69
  switch (visibleEntities) {
75
- case VisibleEntities.All: {
70
+ case VISIBLE_ENTITIES.all: {
76
71
  return {
77
72
  columnId: TableColumnsIds.PoolName,
78
73
  order: DataTable.ASCENDING,
79
74
  };
80
75
  }
81
- case VisibleEntities.Missing: {
76
+ case VISIBLE_ENTITIES.missing: {
82
77
  return {
83
78
  columnId: TableColumnsIds.Missing,
84
79
  order: DataTable.DESCENDING,
85
80
  };
86
81
  }
87
- case VisibleEntities.Space: {
82
+ case VISIBLE_ENTITIES.space: {
88
83
  return {
89
84
  columnId: TableColumnsIds.UsedSpaceFlag,
90
85
  order: DataTable.DESCENDING,
@@ -96,25 +91,25 @@ function setSortOrder(visibleEntities: keyof typeof VisibleEntities): SortOrder
96
91
  }
97
92
  }
98
93
 
99
- function StorageGroups({
94
+ export function StorageGroups({
100
95
  data,
101
96
  tableSettings,
102
97
  visibleEntities,
103
98
  nodes,
104
99
  onShowAll,
105
100
  }: StorageGroupsProps) {
106
- const allColumns: Column<any>[] = [
101
+ const allColumns: Column<PreparedStorageGroup>[] = [
107
102
  {
108
103
  name: TableColumnsIds.PoolName,
109
104
  header: tableColumnsNames[TableColumnsIds.PoolName],
110
105
  width: 250,
111
- render: ({value}) => {
112
- const splitted = (value as string)?.split('/');
106
+ render: ({row}) => {
107
+ const splitted = row.PoolName?.split('/');
113
108
  return (
114
109
  <div className={b('pool-name-wrapper')}>
115
110
  {splitted && (
116
111
  <Popover
117
- content={value as string}
112
+ content={row.PoolName}
118
113
  placement={['right']}
119
114
  behavior={PopoverBehavior.Immediate}
120
115
  >
@@ -132,9 +127,9 @@ function StorageGroups({
132
127
  name: TableColumnsIds.Type,
133
128
  header: tableColumnsNames[TableColumnsIds.Type],
134
129
  // prettier-ignore
135
- render: ({value, row}) => (
130
+ render: ({row}) => (
136
131
  <>
137
- <Label>{(value as string) || '—'}</Label>
132
+ <Label>{row.Type || '—'}</Label>
138
133
  {' '}
139
134
  {row.Encryption && (
140
135
  <Popover
@@ -160,8 +155,12 @@ function StorageGroups({
160
155
  name: TableColumnsIds.Missing,
161
156
  header: tableColumnsNames[TableColumnsIds.Missing],
162
157
  width: 100,
163
- render: ({value, row}) =>
164
- value ? <Label theme={getDegradedSeverity(row)}>Degraded: {value}</Label> : '-',
158
+ render: ({row}) =>
159
+ row.Missing ? (
160
+ <Label theme={getDegradedSeverity(row)}>Degraded: {row.Missing}</Label>
161
+ ) : (
162
+ '-'
163
+ ),
165
164
  align: DataTable.LEFT,
166
165
  defaultOrder: DataTable.DESCENDING,
167
166
  },
@@ -192,8 +191,8 @@ function StorageGroups({
192
191
  name: TableColumnsIds.GroupID,
193
192
  header: tableColumnsNames[TableColumnsIds.GroupID],
194
193
  width: 130,
195
- render: ({value}) => {
196
- return <span className={b('group-id')}>{value as number}</span>;
194
+ render: ({row}) => {
195
+ return <span className={b('group-id')}>{row.GroupID}</span>;
197
196
  },
198
197
  align: DataTable.RIGHT,
199
198
  },
@@ -201,8 +200,8 @@ function StorageGroups({
201
200
  name: TableColumnsIds.Used,
202
201
  header: tableColumnsNames[TableColumnsIds.Used],
203
202
  width: 100,
204
- render: ({value}) => {
205
- return bytesToGB(value, true);
203
+ render: ({row}) => {
204
+ return bytesToGB(row.Used, true);
206
205
  },
207
206
  align: DataTable.RIGHT,
208
207
  },
@@ -210,8 +209,8 @@ function StorageGroups({
210
209
  name: TableColumnsIds.Limit,
211
210
  header: tableColumnsNames[TableColumnsIds.Limit],
212
211
  width: 100,
213
- render: ({value}) => {
214
- return bytesToGB(value);
212
+ render: ({row}) => {
213
+ return bytesToGB(row.Limit);
215
214
  },
216
215
  align: DataTable.RIGHT,
217
216
  },
@@ -219,15 +218,17 @@ function StorageGroups({
219
218
  name: TableColumnsIds.UsedSpaceFlag,
220
219
  header: tableColumnsNames[TableColumnsIds.UsedSpaceFlag],
221
220
  width: 110,
222
- render: ({value}) => {
223
- const val = value as number;
221
+ render: ({row}) => {
222
+ const value = row.UsedSpaceFlag;
223
+
224
224
  let color = 'Red';
225
- if (val < 100) {
225
+
226
+ if (value < 100) {
226
227
  color = 'Green';
227
- } else if (val < 10000) {
228
+ } else if (value < 10000) {
228
229
  color = 'Yellow';
229
- } else if (val < 1000000) {
230
- value = 'Orange';
230
+ } else if (value < 1000000) {
231
+ color = 'Orange';
231
232
  }
232
233
  return <EntityStatus status={color} />;
233
234
  },
@@ -238,8 +239,8 @@ function StorageGroups({
238
239
  name: TableColumnsIds.Read,
239
240
  header: tableColumnsNames[TableColumnsIds.Read],
240
241
  width: 100,
241
- render: ({value}) => {
242
- return value ? bytesToSpeed(value) : '-';
242
+ render: ({row}) => {
243
+ return row.Read ? bytesToSpeed(row.Read) : '-';
243
244
  },
244
245
  align: DataTable.RIGHT,
245
246
  },
@@ -247,8 +248,8 @@ function StorageGroups({
247
248
  name: TableColumnsIds.Write,
248
249
  header: tableColumnsNames[TableColumnsIds.Write],
249
250
  width: 100,
250
- render: ({value}) => {
251
- return value ? bytesToSpeed(value) : '-';
251
+ render: ({row}) => {
252
+ return row.Write ? bytesToSpeed(row.Write) : '-';
252
253
  },
253
254
  align: DataTable.RIGHT,
254
255
  },
@@ -256,14 +257,17 @@ function StorageGroups({
256
257
  name: TableColumnsIds.VDisks,
257
258
  className: b('vdisks-column'),
258
259
  header: tableColumnsNames[TableColumnsIds.VDisks],
259
- render: ({value}) => (
260
+ render: ({row}) => (
260
261
  <div className={b('vdisks-wrapper')}>
261
- {_.map(value as TVDiskStateInfo[], (el) => {
262
- const donors = el.Donors;
262
+ {row.VDisks?.map((vDisk) => {
263
+ const donors = vDisk.Donors;
263
264
 
264
265
  return donors && donors.length > 0 ? (
265
- <Stack className={b('vdisks-item')} key={stringifyVdiskId(el.VDiskId)}>
266
- <VDisk data={el} nodes={nodes} />
266
+ <Stack
267
+ className={b('vdisks-item')}
268
+ key={stringifyVdiskId(vDisk.VDiskId)}
269
+ >
270
+ <VDisk data={vDisk} nodes={nodes} />
267
271
  {donors.map((donor) => {
268
272
  const isFullData = isFullVDiskData(donor);
269
273
 
@@ -280,8 +284,8 @@ function StorageGroups({
280
284
  })}
281
285
  </Stack>
282
286
  ) : (
283
- <div className={b('vdisks-item')} key={stringifyVdiskId(el.VDiskId)}>
284
- <VDisk data={el} nodes={nodes} />
287
+ <div className={b('vdisks-item')} key={stringifyVdiskId(vDisk.VDiskId)}>
288
+ <VDisk data={vDisk} nodes={nodes} />
285
289
  </div>
286
290
  );
287
291
  })}
@@ -295,7 +299,7 @@ function StorageGroups({
295
299
 
296
300
  let columns = allColumns;
297
301
 
298
- if (visibleEntities === VisibleEntities.All) {
302
+ if (visibleEntities === VISIBLE_ENTITIES.all) {
299
303
  columns = allColumns.filter((col) => {
300
304
  return (
301
305
  col.name !== TableColumnsIds.Missing && col.name !== TableColumnsIds.UsedSpaceFlag
@@ -303,7 +307,7 @@ function StorageGroups({
303
307
  });
304
308
  }
305
309
 
306
- if (visibleEntities === VisibleEntities.Space) {
310
+ if (visibleEntities === VISIBLE_ENTITIES.space) {
307
311
  columns = allColumns.filter((col) => col.name !== TableColumnsIds.Missing);
308
312
 
309
313
  if (!data.length) {
@@ -317,7 +321,7 @@ function StorageGroups({
317
321
  }
318
322
  }
319
323
 
320
- if (visibleEntities === VisibleEntities.Missing) {
324
+ if (visibleEntities === VISIBLE_ENTITIES.missing) {
321
325
  columns = allColumns.filter((col) => col.name !== TableColumnsIds.UsedSpaceFlag);
322
326
 
323
327
  if (!data.length) {
@@ -333,7 +337,7 @@ function StorageGroups({
333
337
 
334
338
  return data ? (
335
339
  <DataTable
336
- key={visibleEntities as string}
340
+ key={visibleEntities}
337
341
  theme="yandex-cloud"
338
342
  data={data}
339
343
  columns={columns}
@@ -343,5 +347,3 @@ function StorageGroups({
343
347
  />
344
348
  ) : null;
345
349
  }
346
-
347
- export default StorageGroups;
@@ -1,9 +1,10 @@
1
- import _ from 'lodash';
2
1
  import cn from 'bem-cn-lite';
3
2
 
4
3
  import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
5
4
 
6
- import {VisibleEntities} from '../../../store/reducers/storage';
5
+ import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types';
6
+
7
+ import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
7
8
  import {
8
9
  AdditionalNodesInfo,
9
10
  isUnavailableNode,
@@ -23,7 +24,7 @@ enum TableColumnsIds {
23
24
  FQDN = 'FQDN',
24
25
  DataCenter = 'DataCenter',
25
26
  Rack = 'Rack',
26
- uptime = 'uptime',
27
+ Uptime = 'Uptime',
27
28
  PDisks = 'PDisks',
28
29
  Missing = 'Missing',
29
30
  }
@@ -32,10 +33,9 @@ type TableColumnsIdsKeys = keyof typeof TableColumnsIds;
32
33
  type TableColumnsIdsValues = typeof TableColumnsIds[TableColumnsIdsKeys];
33
34
 
34
35
  interface StorageNodesProps {
35
- data: any;
36
- nodes: any;
36
+ data: PreparedStorageNode[];
37
37
  tableSettings: Settings;
38
- visibleEntities: keyof typeof VisibleEntities;
38
+ visibleEntities: VisibleEntities;
39
39
  nodesUptimeFilter: keyof typeof NodesUptimeFilterValues;
40
40
  onShowAll?: VoidFunction;
41
41
  additionalNodesInfo?: AdditionalNodesInfo;
@@ -46,22 +46,22 @@ const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
46
46
  FQDN: 'FQDN',
47
47
  DataCenter: 'DC',
48
48
  Rack: 'Rack',
49
- uptime: 'Uptime',
49
+ Uptime: 'Uptime',
50
50
  PDisks: 'PDisks',
51
51
  Missing: 'Missing',
52
52
  };
53
53
 
54
54
  const b = cn('global-storage-nodes');
55
55
 
56
- function setSortOrder(visibleEntities: keyof typeof VisibleEntities): SortOrder | undefined {
56
+ function setSortOrder(visibleEntities: VisibleEntities): SortOrder | undefined {
57
57
  switch (visibleEntities) {
58
- case VisibleEntities.All: {
58
+ case VISIBLE_ENTITIES.all: {
59
59
  return {
60
60
  columnId: TableColumnsIds.NodeId,
61
61
  order: DataTable.ASCENDING,
62
62
  };
63
63
  }
64
- case VisibleEntities.Missing: {
64
+ case VISIBLE_ENTITIES.missing: {
65
65
  return {
66
66
  columnId: TableColumnsIds.Missing,
67
67
  order: DataTable.DESCENDING,
@@ -73,7 +73,7 @@ function setSortOrder(visibleEntities: keyof typeof VisibleEntities): SortOrder
73
73
  }
74
74
  }
75
75
 
76
- function StorageNodes({
76
+ export function StorageNodes({
77
77
  data,
78
78
  tableSettings,
79
79
  visibleEntities,
@@ -83,7 +83,7 @@ function StorageNodes({
83
83
  }: StorageNodesProps) {
84
84
  const getNodeRef = additionalNodesInfo?.getNodeRef;
85
85
 
86
- const allColumns: Column<any>[] = [
86
+ const allColumns: Column<PreparedStorageNode>[] = [
87
87
  {
88
88
  name: TableColumnsIds.NodeId,
89
89
  header: tableColumnsNames[TableColumnsIds.NodeId],
@@ -112,10 +112,10 @@ function StorageNodes({
112
112
  align: DataTable.LEFT,
113
113
  },
114
114
  {
115
- name: TableColumnsIds.uptime,
116
- header: tableColumnsNames[TableColumnsIds.uptime],
115
+ name: TableColumnsIds.Uptime,
116
+ header: tableColumnsNames[TableColumnsIds.Uptime],
117
117
  width: 130,
118
- sortAccessor: ({StartTime}) => -StartTime,
118
+ sortAccessor: ({StartTime}) => (StartTime ? -StartTime : 0),
119
119
  align: DataTable.RIGHT,
120
120
  },
121
121
  {
@@ -129,11 +129,11 @@ function StorageNodes({
129
129
  name: TableColumnsIds.PDisks,
130
130
  className: b('pdisks-column'),
131
131
  header: tableColumnsNames[TableColumnsIds.PDisks],
132
- render: ({value, row}) => (
132
+ render: ({row}) => (
133
133
  <div className={b('pdisks-wrapper')}>
134
- {_.map(value as any, (el) => (
135
- <div className={b('pdisks-item')} key={el.PDiskId}>
136
- <PDisk data={el} nodeId={row.NodeId} />
134
+ {row.PDisks?.map((pDisk) => (
135
+ <div className={b('pdisks-item')} key={pDisk.PDiskId}>
136
+ <PDisk data={pDisk} nodeId={row.NodeId} />
137
137
  </div>
138
138
  ))}
139
139
  </div>
@@ -146,18 +146,18 @@ function StorageNodes({
146
146
 
147
147
  let columns = allColumns;
148
148
 
149
- if (visibleEntities === VisibleEntities.Space) {
149
+ if (visibleEntities === VISIBLE_ENTITIES.space) {
150
150
  columns = allColumns.filter((col) => col.name !== TableColumnsIds.Missing);
151
151
  }
152
152
 
153
153
  if (!data.length) {
154
154
  let message;
155
155
 
156
- if (visibleEntities === VisibleEntities.Space) {
156
+ if (visibleEntities === VISIBLE_ENTITIES.space) {
157
157
  message = i18n('empty.out_of_space');
158
158
  }
159
159
 
160
- if (visibleEntities === VisibleEntities.Missing) {
160
+ if (visibleEntities === VISIBLE_ENTITIES.missing) {
161
161
  message = i18n('empty.degraded');
162
162
  }
163
163
 
@@ -166,7 +166,7 @@ function StorageNodes({
166
166
  }
167
167
 
168
168
  if (
169
- visibleEntities !== VisibleEntities.All &&
169
+ visibleEntities !== VISIBLE_ENTITIES.all &&
170
170
  nodesUptimeFilter !== NodesUptimeFilterValues.All
171
171
  ) {
172
172
  message = i18n('empty.several_filters');
@@ -193,5 +193,3 @@ function StorageNodes({
193
193
  />
194
194
  ) : null;
195
195
  }
196
-
197
- export default StorageNodes;