ydb-embedded-ui 4.9.0 → 4.10.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 (64) hide show
  1. package/CHANGELOG.md +12 -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/ProblemFilter/ProblemFilter.tsx +2 -2
  9. package/dist/components/SpeedMultiMeter/SpeedMultiMeter.tsx +4 -4
  10. package/dist/components/TruncatedQuery/{TruncatedQuery.js → TruncatedQuery.tsx} +10 -8
  11. package/dist/containers/AsideNavigation/AsideNavigation.tsx +6 -6
  12. package/dist/containers/Cluster/Cluster.tsx +10 -6
  13. package/dist/containers/Node/Node.tsx +3 -3
  14. package/dist/containers/Nodes/Nodes.tsx +2 -2
  15. package/dist/containers/Storage/PDisk/PDisk.tsx +2 -7
  16. package/dist/containers/Storage/Storage.tsx +240 -0
  17. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +45 -40
  18. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +12 -16
  19. package/dist/containers/Storage/UsageFilter/UsageFilter.scss +1 -0
  20. package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +17 -17
  21. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -3
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -4
  23. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +0 -15
  24. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +10 -3
  25. package/dist/containers/Tenant/{Preview → Query/Preview}/Preview.scss +1 -1
  26. package/dist/containers/Tenant/Query/Preview/Preview.tsx +121 -0
  27. package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +1 -1
  28. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +6 -8
  29. package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.tsx +1 -1
  30. package/dist/containers/Tenant/Query/i18n/en.json +8 -1
  31. package/dist/containers/Tenant/Query/i18n/ru.json +8 -1
  32. package/dist/containers/Tenants/Tenants.tsx +269 -0
  33. package/dist/services/api.ts +8 -3
  34. package/dist/store/reducers/nodes/nodes.ts +4 -4
  35. package/dist/store/reducers/partitions/types.ts +3 -3
  36. package/dist/store/reducers/settings/settings.ts +4 -2
  37. package/dist/store/reducers/settings/types.ts +3 -1
  38. package/dist/store/reducers/storage/selectors.ts +279 -0
  39. package/dist/store/reducers/storage/storage.ts +191 -0
  40. package/dist/store/reducers/storage/types.ts +80 -0
  41. package/dist/store/reducers/tenants/selectors.ts +46 -0
  42. package/dist/store/reducers/tenants/tenants.ts +21 -14
  43. package/dist/store/reducers/tenants/types.ts +20 -5
  44. package/dist/store/reducers/tenants/utils.ts +68 -0
  45. package/dist/types/additionalProps.ts +8 -0
  46. package/dist/types/api/storage.ts +1 -1
  47. package/dist/types/store/topic.ts +3 -3
  48. package/dist/utils/bytesParsers/__test__/formatBytes.test.ts +38 -0
  49. package/dist/utils/bytesParsers/convertBytesObjectToSpeed.ts +2 -2
  50. package/dist/utils/bytesParsers/formatBytes.ts +132 -0
  51. package/dist/utils/bytesParsers/i18n/en.json +1 -0
  52. package/dist/utils/bytesParsers/i18n/ru.json +1 -0
  53. package/dist/utils/bytesParsers/index.ts +1 -1
  54. package/dist/utils/index.js +5 -10
  55. package/dist/utils/numeral.ts +8 -0
  56. package/package.json +1 -1
  57. package/dist/components/FullNodeViewer/FullNodeViewer.js +0 -89
  58. package/dist/containers/Node/NodeOverview/NodeOverview.scss +0 -0
  59. package/dist/containers/Node/NodeOverview/NodeOverview.tsx +0 -21
  60. package/dist/containers/Storage/Storage.js +0 -350
  61. package/dist/containers/Tenant/Preview/Preview.js +0 -168
  62. package/dist/containers/Tenants/Tenants.js +0 -363
  63. package/dist/store/reducers/storage/storage.js +0 -404
  64. 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,12 +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
  import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
6
5
 
7
6
  import type {NodesMap} from '../../../types/store/nodesList';
8
- import type {TVDiskStateInfo} from '../../../types/api/vdisk';
9
- import type {VisibleEntities} from '../../../store/reducers/storage/types';
7
+ import type {PreparedStorageGroup, VisibleEntities} from '../../../store/reducers/storage/types';
10
8
 
11
9
  import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
12
10
  import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
@@ -43,8 +41,8 @@ type TableColumnsIdsKeys = keyof typeof TableColumnsIds;
43
41
  type TableColumnsIdsValues = typeof TableColumnsIds[TableColumnsIdsKeys];
44
42
 
45
43
  interface StorageGroupsProps {
46
- data: any;
47
- nodes: NodesMap;
44
+ data: PreparedStorageGroup[];
45
+ nodes?: NodesMap;
48
46
  tableSettings: Settings;
49
47
  visibleEntities: VisibleEntities;
50
48
  onShowAll?: VoidFunction;
@@ -93,25 +91,25 @@ function setSortOrder(visibleEntities: VisibleEntities): SortOrder | undefined {
93
91
  }
94
92
  }
95
93
 
96
- function StorageGroups({
94
+ export function StorageGroups({
97
95
  data,
98
96
  tableSettings,
99
97
  visibleEntities,
100
98
  nodes,
101
99
  onShowAll,
102
100
  }: StorageGroupsProps) {
103
- const allColumns: Column<any>[] = [
101
+ const allColumns: Column<PreparedStorageGroup>[] = [
104
102
  {
105
103
  name: TableColumnsIds.PoolName,
106
104
  header: tableColumnsNames[TableColumnsIds.PoolName],
107
105
  width: 250,
108
- render: ({value}) => {
109
- const splitted = (value as string)?.split('/');
106
+ render: ({row}) => {
107
+ const splitted = row.PoolName?.split('/');
110
108
  return (
111
109
  <div className={b('pool-name-wrapper')}>
112
110
  {splitted && (
113
111
  <Popover
114
- content={value as string}
112
+ content={row.PoolName}
115
113
  placement={['right']}
116
114
  behavior={PopoverBehavior.Immediate}
117
115
  >
@@ -129,9 +127,9 @@ function StorageGroups({
129
127
  name: TableColumnsIds.Type,
130
128
  header: tableColumnsNames[TableColumnsIds.Type],
131
129
  // prettier-ignore
132
- render: ({value, row}) => (
130
+ render: ({row}) => (
133
131
  <>
134
- <Label>{(value as string) || '—'}</Label>
132
+ <Label>{row.Type || '—'}</Label>
135
133
  {' '}
136
134
  {row.Encryption && (
137
135
  <Popover
@@ -157,8 +155,12 @@ function StorageGroups({
157
155
  name: TableColumnsIds.Missing,
158
156
  header: tableColumnsNames[TableColumnsIds.Missing],
159
157
  width: 100,
160
- render: ({value, row}) =>
161
- 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
+ ),
162
164
  align: DataTable.LEFT,
163
165
  defaultOrder: DataTable.DESCENDING,
164
166
  },
@@ -189,8 +191,8 @@ function StorageGroups({
189
191
  name: TableColumnsIds.GroupID,
190
192
  header: tableColumnsNames[TableColumnsIds.GroupID],
191
193
  width: 130,
192
- render: ({value}) => {
193
- return <span className={b('group-id')}>{value as number}</span>;
194
+ render: ({row}) => {
195
+ return <span className={b('group-id')}>{row.GroupID}</span>;
194
196
  },
195
197
  align: DataTable.RIGHT,
196
198
  },
@@ -198,8 +200,8 @@ function StorageGroups({
198
200
  name: TableColumnsIds.Used,
199
201
  header: tableColumnsNames[TableColumnsIds.Used],
200
202
  width: 100,
201
- render: ({value}) => {
202
- return bytesToGB(value, true);
203
+ render: ({row}) => {
204
+ return bytesToGB(row.Used, true);
203
205
  },
204
206
  align: DataTable.RIGHT,
205
207
  },
@@ -207,8 +209,8 @@ function StorageGroups({
207
209
  name: TableColumnsIds.Limit,
208
210
  header: tableColumnsNames[TableColumnsIds.Limit],
209
211
  width: 100,
210
- render: ({value}) => {
211
- return bytesToGB(value);
212
+ render: ({row}) => {
213
+ return bytesToGB(row.Limit);
212
214
  },
213
215
  align: DataTable.RIGHT,
214
216
  },
@@ -216,15 +218,17 @@ function StorageGroups({
216
218
  name: TableColumnsIds.UsedSpaceFlag,
217
219
  header: tableColumnsNames[TableColumnsIds.UsedSpaceFlag],
218
220
  width: 110,
219
- render: ({value}) => {
220
- const val = value as number;
221
+ render: ({row}) => {
222
+ const value = row.UsedSpaceFlag;
223
+
221
224
  let color = 'Red';
222
- if (val < 100) {
225
+
226
+ if (value < 100) {
223
227
  color = 'Green';
224
- } else if (val < 10000) {
228
+ } else if (value < 10000) {
225
229
  color = 'Yellow';
226
- } else if (val < 1000000) {
227
- value = 'Orange';
230
+ } else if (value < 1000000) {
231
+ color = 'Orange';
228
232
  }
229
233
  return <EntityStatus status={color} />;
230
234
  },
@@ -235,8 +239,8 @@ function StorageGroups({
235
239
  name: TableColumnsIds.Read,
236
240
  header: tableColumnsNames[TableColumnsIds.Read],
237
241
  width: 100,
238
- render: ({value}) => {
239
- return value ? bytesToSpeed(value) : '-';
242
+ render: ({row}) => {
243
+ return row.Read ? bytesToSpeed(row.Read) : '-';
240
244
  },
241
245
  align: DataTable.RIGHT,
242
246
  },
@@ -244,8 +248,8 @@ function StorageGroups({
244
248
  name: TableColumnsIds.Write,
245
249
  header: tableColumnsNames[TableColumnsIds.Write],
246
250
  width: 100,
247
- render: ({value}) => {
248
- return value ? bytesToSpeed(value) : '-';
251
+ render: ({row}) => {
252
+ return row.Write ? bytesToSpeed(row.Write) : '-';
249
253
  },
250
254
  align: DataTable.RIGHT,
251
255
  },
@@ -253,14 +257,17 @@ function StorageGroups({
253
257
  name: TableColumnsIds.VDisks,
254
258
  className: b('vdisks-column'),
255
259
  header: tableColumnsNames[TableColumnsIds.VDisks],
256
- render: ({value}) => (
260
+ render: ({row}) => (
257
261
  <div className={b('vdisks-wrapper')}>
258
- {_.map(value as TVDiskStateInfo[], (el) => {
259
- const donors = el.Donors;
262
+ {row.VDisks?.map((vDisk) => {
263
+ const donors = vDisk.Donors;
260
264
 
261
265
  return donors && donors.length > 0 ? (
262
- <Stack className={b('vdisks-item')} key={stringifyVdiskId(el.VDiskId)}>
263
- <VDisk data={el} nodes={nodes} />
266
+ <Stack
267
+ className={b('vdisks-item')}
268
+ key={stringifyVdiskId(vDisk.VDiskId)}
269
+ >
270
+ <VDisk data={vDisk} nodes={nodes} />
264
271
  {donors.map((donor) => {
265
272
  const isFullData = isFullVDiskData(donor);
266
273
 
@@ -277,8 +284,8 @@ function StorageGroups({
277
284
  })}
278
285
  </Stack>
279
286
  ) : (
280
- <div className={b('vdisks-item')} key={stringifyVdiskId(el.VDiskId)}>
281
- <VDisk data={el} nodes={nodes} />
287
+ <div className={b('vdisks-item')} key={stringifyVdiskId(vDisk.VDiskId)}>
288
+ <VDisk data={vDisk} nodes={nodes} />
282
289
  </div>
283
290
  );
284
291
  })}
@@ -330,7 +337,7 @@ function StorageGroups({
330
337
 
331
338
  return data ? (
332
339
  <DataTable
333
- key={visibleEntities as string}
340
+ key={visibleEntities}
334
341
  theme="yandex-cloud"
335
342
  data={data}
336
343
  columns={columns}
@@ -340,5 +347,3 @@ function StorageGroups({
340
347
  />
341
348
  ) : null;
342
349
  }
343
-
344
- export default StorageGroups;
@@ -1,9 +1,8 @@
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 type {VisibleEntities} from '../../../store/reducers/storage/types';
5
+ import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types';
7
6
 
8
7
  import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
9
8
  import {
@@ -25,7 +24,7 @@ enum TableColumnsIds {
25
24
  FQDN = 'FQDN',
26
25
  DataCenter = 'DataCenter',
27
26
  Rack = 'Rack',
28
- uptime = 'uptime',
27
+ Uptime = 'Uptime',
29
28
  PDisks = 'PDisks',
30
29
  Missing = 'Missing',
31
30
  }
@@ -34,8 +33,7 @@ type TableColumnsIdsKeys = keyof typeof TableColumnsIds;
34
33
  type TableColumnsIdsValues = typeof TableColumnsIds[TableColumnsIdsKeys];
35
34
 
36
35
  interface StorageNodesProps {
37
- data: any;
38
- nodes: any;
36
+ data: PreparedStorageNode[];
39
37
  tableSettings: Settings;
40
38
  visibleEntities: VisibleEntities;
41
39
  nodesUptimeFilter: keyof typeof NodesUptimeFilterValues;
@@ -48,7 +46,7 @@ const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
48
46
  FQDN: 'FQDN',
49
47
  DataCenter: 'DC',
50
48
  Rack: 'Rack',
51
- uptime: 'Uptime',
49
+ Uptime: 'Uptime',
52
50
  PDisks: 'PDisks',
53
51
  Missing: 'Missing',
54
52
  };
@@ -75,7 +73,7 @@ function setSortOrder(visibleEntities: VisibleEntities): SortOrder | undefined {
75
73
  }
76
74
  }
77
75
 
78
- function StorageNodes({
76
+ export function StorageNodes({
79
77
  data,
80
78
  tableSettings,
81
79
  visibleEntities,
@@ -85,7 +83,7 @@ function StorageNodes({
85
83
  }: StorageNodesProps) {
86
84
  const getNodeRef = additionalNodesInfo?.getNodeRef;
87
85
 
88
- const allColumns: Column<any>[] = [
86
+ const allColumns: Column<PreparedStorageNode>[] = [
89
87
  {
90
88
  name: TableColumnsIds.NodeId,
91
89
  header: tableColumnsNames[TableColumnsIds.NodeId],
@@ -114,8 +112,8 @@ function StorageNodes({
114
112
  align: DataTable.LEFT,
115
113
  },
116
114
  {
117
- name: TableColumnsIds.uptime,
118
- header: tableColumnsNames[TableColumnsIds.uptime],
115
+ name: TableColumnsIds.Uptime,
116
+ header: tableColumnsNames[TableColumnsIds.Uptime],
119
117
  width: 130,
120
118
  sortAccessor: ({StartTime}) => (StartTime ? -StartTime : 0),
121
119
  align: DataTable.RIGHT,
@@ -131,11 +129,11 @@ function StorageNodes({
131
129
  name: TableColumnsIds.PDisks,
132
130
  className: b('pdisks-column'),
133
131
  header: tableColumnsNames[TableColumnsIds.PDisks],
134
- render: ({value, row}) => (
132
+ render: ({row}) => (
135
133
  <div className={b('pdisks-wrapper')}>
136
- {_.map(value as any, (el) => (
137
- <div className={b('pdisks-item')} key={el.PDiskId}>
138
- <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} />
139
137
  </div>
140
138
  ))}
141
139
  </div>
@@ -195,5 +193,3 @@ function StorageNodes({
195
193
  />
196
194
  ) : null;
197
195
  }
198
-
199
- export default StorageNodes;
@@ -13,6 +13,7 @@
13
13
 
14
14
  &-meta {
15
15
  position: relative;
16
+ z-index: 0;
16
17
 
17
18
  padding: 0 5px;
18
19
 
@@ -3,7 +3,7 @@ import cn from 'bem-cn-lite';
3
3
 
4
4
  import {Select, SelectOption} from '@gravity-ui/uikit';
5
5
 
6
- import EntityStatus from "../../../components/EntityStatus/EntityStatus";
6
+ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
7
7
 
8
8
  import {getUsageSeverityForEntityStatus} from '../utils';
9
9
 
@@ -27,14 +27,7 @@ interface UsageFilterProps {
27
27
  const b = cn('usage-filter');
28
28
 
29
29
  export const UsageFilter = (props: UsageFilterProps) => {
30
- const {
31
- className,
32
- value = [],
33
- groups = [],
34
- onChange,
35
- debounce = 200,
36
- disabled,
37
- } = props;
30
+ const {className, value = [], groups = [], onChange, debounce = 200, disabled} = props;
38
31
 
39
32
  const [filterValue, setFilterValue] = useState(value);
40
33
  const timer = useRef<number>();
@@ -50,11 +43,15 @@ export const UsageFilter = (props: UsageFilterProps) => {
50
43
  });
51
44
  }, [value]);
52
45
 
53
- const options = useMemo(() => groups.map(({threshold, count}) => ({
54
- value: String(threshold),
55
- text: `${threshold}%`,
56
- data: {count}
57
- })), [groups]);
46
+ const options = useMemo(
47
+ () =>
48
+ groups.map(({threshold, count}) => ({
49
+ value: String(threshold),
50
+ text: `${threshold}%`,
51
+ data: {count},
52
+ })),
53
+ [groups],
54
+ );
58
55
 
59
56
  const handleUpdate = (newValue: string[]) => {
60
57
  setFilterValue(newValue);
@@ -67,17 +64,20 @@ export const UsageFilter = (props: UsageFilterProps) => {
67
64
 
68
65
  const maxWidth = Math.max(...groups.map(({count}) => count));
69
66
 
70
- const renderOption = ({value, data, text}: SelectOption) => (
67
+ const renderOption = ({value: optionValue, data, text}: SelectOption) => (
71
68
  <div className={b('option')}>
72
69
  <EntityStatus
73
70
  className={b('option-title')}
74
- status={getUsageSeverityForEntityStatus(Number(value))}
71
+ status={getUsageSeverityForEntityStatus(Number(optionValue))}
75
72
  name={text}
76
73
  size="xs"
77
74
  />
78
75
  <div className={b('option-meta')}>
79
76
  {i18n('groups_count', {count: data.count})}
80
- <div className={b('option-bar')} style={{width: `${data.count / maxWidth * 100}%`}} />
77
+ <div
78
+ className={b('option-bar')}
79
+ style={{width: `${(data.count / maxWidth) * 100}%`}}
80
+ />
81
81
  </div>
82
82
  </div>
83
83
  );
@@ -13,14 +13,14 @@ import {useTypedSelector} from '../../../utils/hooks';
13
13
  import routes, {createHref} from '../../../routes';
14
14
  import type {TenantDiagnosticsTab} from '../../../store/reducers/tenant/types';
15
15
  import {enableAutorefresh, disableAutorefresh} from '../../../store/reducers/schema/schema';
16
- import { setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
16
+ import {setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
17
17
  import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
18
18
 
19
19
  import {Loader} from '../../../components/Loader';
20
20
 
21
21
  import {Heatmap} from '../../Heatmap';
22
22
  import {Nodes} from '../../Nodes';
23
- import Storage from '../../Storage/Storage';
23
+ import {Storage} from '../../Storage/Storage';
24
24
  import {Tablets} from '../../Tablets';
25
25
 
26
26
  import Describe from './Describe/Describe';
@@ -130,7 +130,7 @@ function Diagnostics(props: DiagnosticsProps) {
130
130
  return <Tablets path={currentSchemaPath} />;
131
131
  }
132
132
  case TENANT_DIAGNOSTICS_TABS_IDS.storage: {
133
- return <Storage tenant={tenantNameString} database={true} />;
133
+ return <Storage tenant={tenantNameString} />;
134
134
  }
135
135
  case TENANT_DIAGNOSTICS_TABS_IDS.network: {
136
136
  return <Network path={tenantNameString} />;
@@ -27,10 +27,13 @@ const renderName = (tenant) => {
27
27
  const {Name} = tenant;
28
28
  return (
29
29
  <div className={b('tenant-name-wrapper')}>
30
- <EntityStatus status={tenant.State} />
31
- <span className={b('tenant-name-trim')}>
32
- <span className={b('tenant-name')}>{Name}</span>
33
- </span>
30
+ <EntityStatus
31
+ status={tenant.State}
32
+ name={Name}
33
+ withLeftTrim
34
+ hasClipboardButton
35
+ clipboardButtonAlwaysVisible
36
+ />
34
37
  </div>
35
38
  );
36
39
  }
@@ -10,21 +10,6 @@
10
10
  display: flex;
11
11
  overflow: hidden;
12
12
  align-items: center;
13
-
14
- & .yc-link {
15
- display: flex;
16
- }
17
- }
18
- &__tenant-name-trim {
19
- overflow: hidden;
20
-
21
- white-space: nowrap;
22
- text-overflow: ellipsis;
23
- direction: rtl;
24
- }
25
-
26
- &__tenant-name {
27
- unicode-bidi: plaintext;
28
13
  }
29
14
 
30
15
  &__top {