ydb-embedded-ui 4.8.1 → 4.9.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 (39) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -2
  3. package/dist/components/Tablet/Tablet.tsx +2 -13
  4. package/dist/containers/Header/breadcrumbs.ts +22 -6
  5. package/dist/containers/Nodes/Nodes.tsx +1 -1
  6. package/dist/containers/Nodes/getNodesColumns.tsx +2 -2
  7. package/dist/containers/Storage/PDisk/PDisk.tsx +1 -1
  8. package/dist/containers/Storage/Storage.js +26 -48
  9. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +16 -19
  10. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +12 -10
  11. package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +27 -0
  12. package/dist/containers/Storage/StorageVisibleEntityFilter/StorageVisibleEntityFilter.tsx +31 -0
  13. package/dist/containers/Tablet/Tablet.tsx +2 -11
  14. package/dist/containers/TabletsFilters/TabletsFilters.js +8 -3
  15. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +17 -43
  16. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +20 -15
  17. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.tsx +74 -27
  18. package/dist/containers/Tenant/Query/i18n/en.json +1 -1
  19. package/dist/containers/Tenant/Query/i18n/ru.json +1 -1
  20. package/dist/containers/UserSettings/i18n/en.json +1 -1
  21. package/dist/containers/UserSettings/i18n/ru.json +1 -1
  22. package/dist/services/api.ts +6 -13
  23. package/dist/store/reducers/executeQuery.ts +2 -3
  24. package/dist/store/reducers/explainQuery.ts +2 -2
  25. package/dist/store/reducers/header/types.ts +0 -2
  26. package/dist/store/reducers/index.ts +2 -2
  27. package/dist/store/reducers/{nodes.ts → nodes/nodes.ts} +31 -30
  28. package/dist/{types/store/nodes.ts → store/reducers/nodes/types.ts} +24 -27
  29. package/dist/store/reducers/settings/settings.ts +10 -2
  30. package/dist/store/reducers/storage/constants.ts +10 -0
  31. package/dist/store/reducers/{storage.js → storage/storage.js} +19 -53
  32. package/dist/store/reducers/storage/types.ts +12 -0
  33. package/dist/types/store/query.ts +5 -6
  34. package/dist/utils/constants.ts +1 -0
  35. package/dist/utils/nodes.ts +2 -2
  36. package/dist/utils/query.ts +12 -0
  37. package/package.json +1 -1
  38. package/dist/containers/Tenant/Query/QueryEditorControls/OldQueryEditorControls.tsx +0 -90
  39. package/dist/containers/Tenant/Query/QueryEditorControls/shared.ts +0 -18
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.9.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.8.2...v4.9.0) (2023-06-30)
4
+
5
+
6
+ ### Features
7
+
8
+ * **QueryEditor:** remove old controls, update setting ([#445](https://github.com/ydb-platform/ydb-embedded-ui/issues/445)) ([75efd44](https://github.com/ydb-platform/ydb-embedded-ui/commit/75efd444c8b8ba5213117ec9c33f6b9664855a2c))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **QueryEditor:** color last used query action, run on command ([#436](https://github.com/ydb-platform/ydb-embedded-ui/issues/436)) ([c4d3bb8](https://github.com/ydb-platform/ydb-embedded-ui/commit/c4d3bb81bc1cea8ec3fe2e5e7e18c997d94f5714))
14
+ * **QueryEditor:** rename query modes ([#449](https://github.com/ydb-platform/ydb-embedded-ui/issues/449)) ([c93c9c1](https://github.com/ydb-platform/ydb-embedded-ui/commit/c93c9c17ba26e01c596009657cac02ecc9cc9ab0))
15
+ * **StorageNodes:** sort by uptime ([#447](https://github.com/ydb-platform/ydb-embedded-ui/issues/447)) ([283cb81](https://github.com/ydb-platform/ydb-embedded-ui/commit/283cb81b3f4711ddc2bb991615729a9bda7e893c))
16
+ * **Storage:** remove visible entities filter ([#448](https://github.com/ydb-platform/ydb-embedded-ui/issues/448)) ([b4d9489](https://github.com/ydb-platform/ydb-embedded-ui/commit/b4d948965cd349a54fe833a6b81ea3b087782735))
17
+
18
+ ## [4.8.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.8.1...v4.8.2) (2023-06-27)
19
+
20
+
21
+ ### Bug Fixes
22
+
23
+ * **breadcrumbs:** update tenant and tablet params ([#443](https://github.com/ydb-platform/ydb-embedded-ui/issues/443)) ([b0d31ac](https://github.com/ydb-platform/ydb-embedded-ui/commit/b0d31acce6d6e97d759180c885e6aea3b762a91c))
24
+
3
25
  ## [4.8.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.8.0...v4.8.1) (2023-06-26)
4
26
 
5
27
 
@@ -2,7 +2,7 @@ import block from 'bem-cn-lite';
2
2
 
3
3
  import {Button, Popover, PopoverBehavior} from '@gravity-ui/uikit';
4
4
 
5
- import type {INodesPreparedEntity} from '../../types/store/nodes';
5
+ import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
6
6
  import {getDefaultNodePath} from '../../containers/Node/NodePages';
7
7
  import {isUnavailableNode, NodeAddress} from '../../utils/nodes';
8
8
 
@@ -15,7 +15,7 @@ import './NodeHostWrapper.scss';
15
15
  const b = block('ydb-node-host-wrapper');
16
16
 
17
17
  interface NodeHostWrapperProps {
18
- node: INodesPreparedEntity;
18
+ node: NodesPreparedEntity;
19
19
  getNodeRef?: (node?: NodeAddress) => string | null;
20
20
  }
21
21
 
@@ -18,21 +18,10 @@ interface TabletProps {
18
18
  }
19
19
 
20
20
  export const Tablet = ({tablet = {}, tenantName}: TabletProps) => {
21
- const {TabletId: id, NodeId, Type, State} = tablet;
21
+ const {TabletId: id, NodeId} = tablet;
22
22
  const status = tablet.Overall?.toLowerCase();
23
23
 
24
- const tabletPath =
25
- id &&
26
- createHref(
27
- routes.tablet,
28
- {id},
29
- {
30
- nodeId: NodeId,
31
- type: Type,
32
- state: State,
33
- tenantName,
34
- },
35
- );
24
+ const tabletPath = id && createHref(routes.tablet, {id}, {nodeId: NodeId, tenantName});
36
25
 
37
26
  return (
38
27
  <ContentWithPopup
@@ -10,10 +10,15 @@ import type {
10
10
  TabletsBreadcrumbsOptions,
11
11
  TenantBreadcrumbsOptions,
12
12
  } from '../../store/reducers/header/types';
13
+ import {
14
+ TENANT_DIAGNOSTICS_TABS_IDS,
15
+ TENANT_PAGE,
16
+ TENANT_PAGES_IDS,
17
+ } from '../../store/reducers/tenant/constants';
13
18
  import routes, {createHref} from '../../routes';
14
19
 
15
20
  import {getClusterPath} from '../Cluster/utils';
16
- import {getTenantPath} from '../Tenant/TenantPages';
21
+ import {TenantTabsGroups, getTenantPath} from '../Tenant/TenantPages';
17
22
  import {getDefaultNodePath} from '../Node/NodePages';
18
23
 
19
24
  const prepareTenantName = (tenantName: string) => {
@@ -61,10 +66,16 @@ const getNodeBreadcrumbs = (options: NodeBreadcrumbsOptions, query = {}): RawBre
61
66
  // Compute nodes have tenantName, storage nodes doesn't
62
67
  const isStorageNode = !tenantName;
63
68
 
69
+ const newQuery = {
70
+ ...query,
71
+ [TENANT_PAGE]: TENANT_PAGES_IDS.diagnostics,
72
+ [TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.nodes,
73
+ };
74
+
64
75
  if (isStorageNode) {
65
76
  breadcrumbs = getClusterBreadcrumbs(options, query);
66
77
  } else {
67
- breadcrumbs = getTenantBreadcrumbs(options, query);
78
+ breadcrumbs = getTenantBreadcrumbs(options, newQuery);
68
79
  }
69
80
 
70
81
  const text = nodeId ? `Node ${nodeId}` : 'Node';
@@ -79,21 +90,26 @@ const getTabletsBreadcrubms = (
79
90
  options: TabletsBreadcrumbsOptions,
80
91
  query = {},
81
92
  ): RawBreadcrumbItem[] => {
82
- const {tenantName, nodeIds, state, type} = options;
93
+ const {tenantName, nodeIds} = options;
94
+
95
+ const newQuery = {
96
+ ...query,
97
+ [TENANT_PAGE]: TENANT_PAGES_IDS.diagnostics,
98
+ [TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.tablets,
99
+ };
83
100
 
84
101
  let breadcrumbs: RawBreadcrumbItem[];
85
102
 
86
103
  // Cluster system tablets don't have tenantName
87
104
  if (tenantName) {
88
- breadcrumbs = getTenantBreadcrumbs(options, query);
105
+ breadcrumbs = getTenantBreadcrumbs(options, newQuery);
89
106
  } else {
90
107
  breadcrumbs = getClusterBreadcrumbs(options, query);
91
108
  }
92
109
 
93
110
  const link = createHref(routes.tabletsFilters, undefined, {
111
+ ...query,
94
112
  nodeIds,
95
- state,
96
- type,
97
113
  path: tenantName,
98
114
  });
99
115
 
@@ -26,7 +26,7 @@ import {
26
26
  setSearchValue,
27
27
  resetNodesState,
28
28
  getComputeNodes,
29
- } from '../../store/reducers/nodes';
29
+ } from '../../store/reducers/nodes/nodes';
30
30
  import {changeFilter, ProblemFilterValues} from '../../store/reducers/settings/settings';
31
31
 
32
32
  import {isDatabaseEntityType} from '../Tenant/utils/schema';
@@ -9,7 +9,7 @@ import {NodeHostWrapper} from '../../components/NodeHostWrapper/NodeHostWrapper'
9
9
  import type {NodeAddress} from '../../utils/nodes';
10
10
  import {formatBytesToGigabyte} from '../../utils/index';
11
11
 
12
- import type {INodesPreparedEntity} from '../../types/store/nodes';
12
+ import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
13
13
 
14
14
  interface GetNodesColumnsProps {
15
15
  tabletsPath?: string;
@@ -17,7 +17,7 @@ interface GetNodesColumnsProps {
17
17
  }
18
18
 
19
19
  export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps) {
20
- const columns: Column<INodesPreparedEntity>[] = [
20
+ const columns: Column<NodesPreparedEntity>[] = [
21
21
  {
22
22
  name: 'NodeId',
23
23
  header: '#',
@@ -5,7 +5,7 @@ import {InternalLink} from '../../../components/InternalLink';
5
5
  import {Stack} from '../../../components/Stack/Stack';
6
6
 
7
7
  import routes, {createHref} from '../../../routes';
8
- import {getVDisksForPDisk} from '../../../store/reducers/storage';
8
+ import {getVDisksForPDisk} from '../../../store/reducers/storage/storage';
9
9
  import {TPDiskStateInfo, TPDiskState} from '../../../types/api/pdisk';
10
10
  import {TVDiskStateInfo} from '../../../types/api/vdisk';
11
11
  import {stringifyVdiskId} from '../../../utils';
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
3
3
  import {connect} from 'react-redux';
4
4
  import cn from 'bem-cn-lite';
5
5
  import DataTable from '@gravity-ui/react-data-table';
6
- import {RadioButton} from '@gravity-ui/uikit';
7
6
 
8
7
  import {Search} from '../../components/Search';
9
8
  import {UsageFilter} from './UsageFilter';
@@ -18,33 +17,29 @@ import {
18
17
  getStorageInfo,
19
18
  setInitialState,
20
19
  getFilteredEntities,
21
- VisibleEntities,
22
20
  setVisibleEntities,
23
21
  setStorageFilter,
24
22
  setUsageFilter,
25
- StorageTypes,
26
23
  setStorageType,
27
24
  setNodesUptimeFilter,
28
25
  setDataWasNotLoaded,
29
- VisibleEntitiesTitles,
30
26
  getStoragePoolsGroupsCount,
31
27
  getStorageNodesCount,
32
28
  getUsageFilterOptions,
33
- } from '../../store/reducers/storage';
29
+ } from '../../store/reducers/storage/storage';
30
+ import {VISIBLE_ENTITIES, STORAGE_TYPES} from '../../store/reducers/storage/constants';
34
31
  import {getNodesList, selectNodesMap} from '../../store/reducers/nodesList';
35
32
  import StorageGroups from './StorageGroups/StorageGroups';
36
33
  import StorageNodes from './StorageNodes/StorageNodes';
37
34
  import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
38
35
 
36
+ import {StorageTypeFilter} from './StorageTypeFilter/StorageTypeFilter';
37
+ import {StorageVisibleEntityFilter} from './StorageVisibleEntityFilter/StorageVisibleEntityFilter';
38
+
39
39
  import './Storage.scss';
40
40
 
41
41
  const b = cn('global-storage');
42
42
 
43
- const FILTER_OPTIONS = {
44
- Missing: 'missing',
45
- Space: 'space',
46
- };
47
-
48
43
  const tableSettings = {
49
44
  ...DEFAULT_TABLE_SETTINGS,
50
45
  defaultOrder: DataTable.DESCENDING,
@@ -74,25 +69,23 @@ class Storage extends React.Component {
74
69
  };
75
70
 
76
71
  componentDidMount() {
77
- const {tenant, nodeId, setVisibleEntities, storageType, getNodesList} =
78
- this.props;
72
+ const {tenant, nodeId, setVisibleEntities, storageType, getNodesList} = this.props;
79
73
 
80
74
  this.autofetcher = new AutoFetcher();
81
75
  getNodesList();
82
76
  if (tenant || nodeId) {
83
- setVisibleEntities(VisibleEntities.All);
77
+ setVisibleEntities(VISIBLE_ENTITIES.all);
84
78
  this.getStorageInfo({
85
- filter: FILTER_OPTIONS.All,
86
79
  type: storageType,
87
80
  });
88
81
  } else {
89
82
  this.getStorageInfo({
90
- filter: FILTER_OPTIONS.Missing,
83
+ visibleEntities: VISIBLE_ENTITIES.missing,
91
84
  type: storageType,
92
85
  });
93
86
  this.autofetcher.fetch(() =>
94
87
  this.getStorageInfo({
95
- filter: FILTER_OPTIONS.Missing,
88
+ visibleEntities: VISIBLE_ENTITIES.missing,
96
89
  type: storageType,
97
90
  }),
98
91
  );
@@ -105,7 +98,7 @@ class Storage extends React.Component {
105
98
 
106
99
  const startFetch = () => {
107
100
  this.getStorageInfo({
108
- filter: FILTER_OPTIONS[visibleEntities],
101
+ visibleEntities,
109
102
  type: storageType,
110
103
  });
111
104
  };
@@ -115,7 +108,7 @@ class Storage extends React.Component {
115
108
  this.autofetcher.start();
116
109
  this.autofetcher.fetch(() =>
117
110
  this.getStorageInfo({
118
- filter: FILTER_OPTIONS[visibleEntities],
111
+ visibleEntities,
119
112
  type: storageType,
120
113
  }),
121
114
  );
@@ -183,16 +176,16 @@ class Storage extends React.Component {
183
176
 
184
177
  return (
185
178
  <div className={b('table-wrapper')}>
186
- {storageType === StorageTypes.groups && (
179
+ {storageType === STORAGE_TYPES.groups && (
187
180
  <StorageGroups
188
181
  visibleEntities={visibleEntities}
189
182
  data={flatListStorageEntities}
190
183
  tableSettings={tableSettings}
191
184
  nodes={nodes}
192
- onShowAll={() => this.onGroupVisibilityChange(VisibleEntities.All)}
185
+ onShowAll={() => this.onGroupVisibilityChange(VISIBLE_ENTITIES.all)}
193
186
  />
194
187
  )}
195
- {storageType === StorageTypes.nodes && (
188
+ {storageType === STORAGE_TYPES.nodes && (
196
189
  <StorageNodes
197
190
  visibleEntities={visibleEntities}
198
191
  nodesUptimeFilter={nodesUptimeFilter}
@@ -221,7 +214,7 @@ class Storage extends React.Component {
221
214
  };
222
215
 
223
216
  onShowAllNodes = () => {
224
- this.onGroupVisibilityChange(VisibleEntities.All);
217
+ this.onGroupVisibilityChange(VISIBLE_ENTITIES.all);
225
218
  this.onUptimeFilterChange(NodesUptimeFilterValues.All);
226
219
  };
227
220
 
@@ -229,8 +222,8 @@ class Storage extends React.Component {
229
222
  const {storageType, groupsCount, nodesCount, flatListStorageEntities, loading, wasLoaded} =
230
223
  this.props;
231
224
 
232
- const entityName = storageType === StorageTypes.groups ? 'Groups' : 'Nodes';
233
- const count = storageType === StorageTypes.groups ? groupsCount : nodesCount;
225
+ const entityName = storageType === STORAGE_TYPES.groups ? 'Groups' : 'Nodes';
226
+ const count = storageType === STORAGE_TYPES.groups ? groupsCount : nodesCount;
234
227
 
235
228
  return (
236
229
  <EntitiesCount
@@ -259,7 +252,7 @@ class Storage extends React.Component {
259
252
  <div className={b('search')}>
260
253
  <Search
261
254
  placeholder={
262
- storageType === StorageTypes.groups
255
+ storageType === STORAGE_TYPES.groups
263
256
  ? 'Group ID, Pool name'
264
257
  : 'Node ID, FQDN'
265
258
  }
@@ -268,32 +261,17 @@ class Storage extends React.Component {
268
261
  />
269
262
  </div>
270
263
 
271
- <RadioButton value={storageType} onUpdate={this.onStorageTypeChange}>
272
- <RadioButton.Option value={StorageTypes.groups}>
273
- {StorageTypes.groups}
274
- </RadioButton.Option>
275
- <RadioButton.Option value={StorageTypes.nodes}>
276
- {StorageTypes.nodes}
277
- </RadioButton.Option>
278
- </RadioButton>
279
-
280
- <RadioButton value={visibleEntities} onUpdate={this.onGroupVisibilityChange}>
281
- <RadioButton.Option value={VisibleEntities.Missing}>
282
- {VisibleEntitiesTitles[VisibleEntities.Missing]}
283
- </RadioButton.Option>
284
- <RadioButton.Option value={VisibleEntities.Space}>
285
- {VisibleEntitiesTitles[VisibleEntities.Space]}
286
- </RadioButton.Option>
287
- <RadioButton.Option value={VisibleEntities.All}>
288
- {VisibleEntitiesTitles[VisibleEntities.All]}
289
- </RadioButton.Option>
290
- </RadioButton>
291
-
292
- {storageType === StorageTypes.nodes && (
264
+ <StorageTypeFilter value={storageType} onChange={this.onStorageTypeChange} />
265
+ <StorageVisibleEntityFilter
266
+ value={visibleEntities}
267
+ onChange={this.onGroupVisibilityChange}
268
+ />
269
+
270
+ {storageType === STORAGE_TYPES.nodes && (
293
271
  <UptimeFilter value={nodesUptimeFilter} onChange={this.onUptimeFilterChange} />
294
272
  )}
295
273
 
296
- {storageType === StorageTypes.groups && (
274
+ {storageType === STORAGE_TYPES.groups && (
297
275
  <UsageFilter
298
276
  value={usageFilter}
299
277
  onChange={setUsageFilter}
@@ -1,25 +1,22 @@
1
1
  import _ from 'lodash';
2
2
  import cn from 'bem-cn-lite';
3
+
3
4
  import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
4
5
  import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
5
6
 
6
7
  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
10
 
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
11
+ import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
18
12
  import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
19
- //@ts-ignore
20
13
  import {stringifyVdiskId} from '../../../utils';
21
14
  import {getUsage, isFullVDiskData} from '../../../utils/storage';
22
15
 
16
+ import shieldIcon from '../../../assets/icons/shield.svg';
17
+ import {Stack} from '../../../components/Stack/Stack';
18
+ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
19
+
23
20
  import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
24
21
  import {VDisk} from '../VDisk';
25
22
  import {getDegradedSeverity, getUsageSeverityForStorageGroup} from '../utils';
@@ -49,7 +46,7 @@ interface StorageGroupsProps {
49
46
  data: any;
50
47
  nodes: NodesMap;
51
48
  tableSettings: Settings;
52
- visibleEntities: keyof typeof VisibleEntities;
49
+ visibleEntities: VisibleEntities;
53
50
  onShowAll?: VoidFunction;
54
51
  }
55
52
 
@@ -70,21 +67,21 @@ const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
70
67
 
71
68
  const b = cn('global-storage-groups');
72
69
 
73
- function setSortOrder(visibleEntities: keyof typeof VisibleEntities): SortOrder | undefined {
70
+ function setSortOrder(visibleEntities: VisibleEntities): SortOrder | undefined {
74
71
  switch (visibleEntities) {
75
- case VisibleEntities.All: {
72
+ case VISIBLE_ENTITIES.all: {
76
73
  return {
77
74
  columnId: TableColumnsIds.PoolName,
78
75
  order: DataTable.ASCENDING,
79
76
  };
80
77
  }
81
- case VisibleEntities.Missing: {
78
+ case VISIBLE_ENTITIES.missing: {
82
79
  return {
83
80
  columnId: TableColumnsIds.Missing,
84
81
  order: DataTable.DESCENDING,
85
82
  };
86
83
  }
87
- case VisibleEntities.Space: {
84
+ case VISIBLE_ENTITIES.space: {
88
85
  return {
89
86
  columnId: TableColumnsIds.UsedSpaceFlag,
90
87
  order: DataTable.DESCENDING,
@@ -295,7 +292,7 @@ function StorageGroups({
295
292
 
296
293
  let columns = allColumns;
297
294
 
298
- if (visibleEntities === VisibleEntities.All) {
295
+ if (visibleEntities === VISIBLE_ENTITIES.all) {
299
296
  columns = allColumns.filter((col) => {
300
297
  return (
301
298
  col.name !== TableColumnsIds.Missing && col.name !== TableColumnsIds.UsedSpaceFlag
@@ -303,7 +300,7 @@ function StorageGroups({
303
300
  });
304
301
  }
305
302
 
306
- if (visibleEntities === VisibleEntities.Space) {
303
+ if (visibleEntities === VISIBLE_ENTITIES.space) {
307
304
  columns = allColumns.filter((col) => col.name !== TableColumnsIds.Missing);
308
305
 
309
306
  if (!data.length) {
@@ -317,7 +314,7 @@ function StorageGroups({
317
314
  }
318
315
  }
319
316
 
320
- if (visibleEntities === VisibleEntities.Missing) {
317
+ if (visibleEntities === VISIBLE_ENTITIES.missing) {
321
318
  columns = allColumns.filter((col) => col.name !== TableColumnsIds.UsedSpaceFlag);
322
319
 
323
320
  if (!data.length) {
@@ -3,7 +3,9 @@ import cn from 'bem-cn-lite';
3
3
 
4
4
  import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
5
5
 
6
- import {VisibleEntities} from '../../../store/reducers/storage';
6
+ import type {VisibleEntities} from '../../../store/reducers/storage/types';
7
+
8
+ import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
7
9
  import {
8
10
  AdditionalNodesInfo,
9
11
  isUnavailableNode,
@@ -35,7 +37,7 @@ interface StorageNodesProps {
35
37
  data: any;
36
38
  nodes: any;
37
39
  tableSettings: Settings;
38
- visibleEntities: keyof typeof VisibleEntities;
40
+ visibleEntities: VisibleEntities;
39
41
  nodesUptimeFilter: keyof typeof NodesUptimeFilterValues;
40
42
  onShowAll?: VoidFunction;
41
43
  additionalNodesInfo?: AdditionalNodesInfo;
@@ -53,15 +55,15 @@ const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
53
55
 
54
56
  const b = cn('global-storage-nodes');
55
57
 
56
- function setSortOrder(visibleEntities: keyof typeof VisibleEntities): SortOrder | undefined {
58
+ function setSortOrder(visibleEntities: VisibleEntities): SortOrder | undefined {
57
59
  switch (visibleEntities) {
58
- case VisibleEntities.All: {
60
+ case VISIBLE_ENTITIES.all: {
59
61
  return {
60
62
  columnId: TableColumnsIds.NodeId,
61
63
  order: DataTable.ASCENDING,
62
64
  };
63
65
  }
64
- case VisibleEntities.Missing: {
66
+ case VISIBLE_ENTITIES.missing: {
65
67
  return {
66
68
  columnId: TableColumnsIds.Missing,
67
69
  order: DataTable.DESCENDING,
@@ -115,7 +117,7 @@ function StorageNodes({
115
117
  name: TableColumnsIds.uptime,
116
118
  header: tableColumnsNames[TableColumnsIds.uptime],
117
119
  width: 130,
118
- sortAccessor: ({StartTime}) => -StartTime,
120
+ sortAccessor: ({StartTime}) => (StartTime ? -StartTime : 0),
119
121
  align: DataTable.RIGHT,
120
122
  },
121
123
  {
@@ -146,18 +148,18 @@ function StorageNodes({
146
148
 
147
149
  let columns = allColumns;
148
150
 
149
- if (visibleEntities === VisibleEntities.Space) {
151
+ if (visibleEntities === VISIBLE_ENTITIES.space) {
150
152
  columns = allColumns.filter((col) => col.name !== TableColumnsIds.Missing);
151
153
  }
152
154
 
153
155
  if (!data.length) {
154
156
  let message;
155
157
 
156
- if (visibleEntities === VisibleEntities.Space) {
158
+ if (visibleEntities === VISIBLE_ENTITIES.space) {
157
159
  message = i18n('empty.out_of_space');
158
160
  }
159
161
 
160
- if (visibleEntities === VisibleEntities.Missing) {
162
+ if (visibleEntities === VISIBLE_ENTITIES.missing) {
161
163
  message = i18n('empty.degraded');
162
164
  }
163
165
 
@@ -166,7 +168,7 @@ function StorageNodes({
166
168
  }
167
169
 
168
170
  if (
169
- visibleEntities !== VisibleEntities.All &&
171
+ visibleEntities !== VISIBLE_ENTITIES.all &&
170
172
  nodesUptimeFilter !== NodesUptimeFilterValues.All
171
173
  ) {
172
174
  message = i18n('empty.several_filters');
@@ -0,0 +1,27 @@
1
+ import {RadioButton} from '@gravity-ui/uikit';
2
+
3
+ import type {StorageType} from '../../../store/reducers/storage/types';
4
+ import {STORAGE_TYPES} from '../../../store/reducers/storage/constants';
5
+
6
+ const StorageTypesTitles = {
7
+ [STORAGE_TYPES.groups]: 'Groups',
8
+ [STORAGE_TYPES.nodes]: 'Nodes',
9
+ };
10
+
11
+ interface StorageTypeFilterProps {
12
+ value: StorageType;
13
+ onChange: (value: string) => void;
14
+ }
15
+
16
+ export const StorageTypeFilter = ({value, onChange}: StorageTypeFilterProps) => {
17
+ return (
18
+ <RadioButton value={value} onUpdate={onChange}>
19
+ <RadioButton.Option value={STORAGE_TYPES.groups}>
20
+ {StorageTypesTitles[STORAGE_TYPES.groups]}
21
+ </RadioButton.Option>
22
+ <RadioButton.Option value={STORAGE_TYPES.nodes}>
23
+ {StorageTypesTitles[STORAGE_TYPES.nodes]}
24
+ </RadioButton.Option>
25
+ </RadioButton>
26
+ );
27
+ };
@@ -0,0 +1,31 @@
1
+ import {RadioButton} from '@gravity-ui/uikit';
2
+
3
+ import type {VisibleEntities} from '../../../store/reducers/storage/types';
4
+ import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
5
+
6
+ export const VisibleEntitiesTitles = {
7
+ [VISIBLE_ENTITIES.all]: 'All',
8
+ [VISIBLE_ENTITIES.missing]: 'Degraded',
9
+ [VISIBLE_ENTITIES.space]: 'Out of Space',
10
+ };
11
+
12
+ interface StorageProblemFilterProps {
13
+ value: VisibleEntities;
14
+ onChange: (value: string) => void;
15
+ }
16
+
17
+ export const StorageVisibleEntityFilter = ({value, onChange}: StorageProblemFilterProps) => {
18
+ return (
19
+ <RadioButton value={value} onUpdate={onChange}>
20
+ <RadioButton.Option value={VISIBLE_ENTITIES.missing}>
21
+ {VisibleEntitiesTitles[VISIBLE_ENTITIES.missing]}
22
+ </RadioButton.Option>
23
+ <RadioButton.Option value={VISIBLE_ENTITIES.space}>
24
+ {VisibleEntitiesTitles[VISIBLE_ENTITIES.space]}
25
+ </RadioButton.Option>
26
+ <RadioButton.Option value={VISIBLE_ENTITIES.all}>
27
+ {VisibleEntitiesTitles[VISIBLE_ENTITIES.all]}
28
+ </RadioButton.Option>
29
+ </RadioButton>
30
+ );
31
+ };
@@ -48,16 +48,9 @@ export const Tablet = () => {
48
48
  error,
49
49
  } = useTypedSelector((state) => state.tablet);
50
50
 
51
- const {
52
- nodeId: queryNodeId,
53
- type: queryType,
54
- state: queryState,
55
- tenantName: queryTenantName,
56
- } = parseQuery(location);
51
+ const {nodeId: queryNodeId, tenantName: queryTenantName} = parseQuery(location);
57
52
 
58
53
  const nodeId = tablet.NodeId?.toString() || queryNodeId?.toString();
59
- const tabletState = tablet.State || queryState?.toString();
60
- const tabletType = tablet.Type || queryType?.toString();
61
54
  const tenantName = tenantPath || queryTenantName?.toString();
62
55
 
63
56
  // NOTE: should be reviewed when migrating to React 18
@@ -84,13 +77,11 @@ export const Tablet = () => {
84
77
  dispatch(
85
78
  setHeaderBreadcrumbs('tablet', {
86
79
  nodeIds: nodeId ? [nodeId] : [],
87
- state: tabletState,
88
- type: tabletType,
89
80
  tenantName,
90
81
  tabletId: id,
91
82
  }),
92
83
  );
93
- }, [dispatch, tenantName, id, nodeId, tabletState, tabletType]);
84
+ }, [dispatch, tenantName, id, nodeId]);
94
85
 
95
86
  const renderExternalLinks = (link: {name: string; path: string}, index: number) => {
96
87
  return (
@@ -81,10 +81,15 @@ class TabletsFilters extends React.Component {
81
81
  });
82
82
  const {nodeIds, type, path, state} = queryParams;
83
83
  const nodes = TabletsFilters.parseNodes(nodeIds);
84
- const stateFilter = TabletsFilters.getStateFiltersFromColor(state);
85
84
 
86
- setStateFilter(stateFilter);
87
- setTypeFilter([type]);
85
+ if (state) {
86
+ const stateFilter = TabletsFilters.getStateFiltersFromColor(state);
87
+ setStateFilter(stateFilter);
88
+ }
89
+
90
+ if (type) {
91
+ setTypeFilter([type]);
92
+ }
88
93
 
89
94
  this.setState({nodeFilter: nodes, tenantPath: path}, () => {
90
95
  this.makeRequest();