ydb-embedded-ui 4.8.1 → 4.9.0

Sign up to get free protection for your applications and to get access to all the features.
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();