ydb-embedded-ui 4.13.0 → 4.15.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 (71) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/components/Tablet/Tablet.scss +1 -16
  3. package/dist/components/Tablet/Tablet.tsx +5 -5
  4. package/dist/components/TabletIcon/TabletIcon.scss +17 -0
  5. package/dist/components/TabletIcon/TabletIcon.tsx +18 -0
  6. package/dist/containers/App/App.js +1 -1
  7. package/dist/containers/AsideNavigation/AsideNavigation.tsx +1 -1
  8. package/dist/containers/Authentication/Authentication.tsx +1 -1
  9. package/dist/containers/Header/Header.scss +2 -0
  10. package/dist/containers/Header/Header.tsx +2 -7
  11. package/dist/containers/Header/{breadcrumbs.ts → breadcrumbs.tsx} +19 -8
  12. package/dist/containers/Nodes/Nodes.tsx +53 -16
  13. package/dist/containers/Nodes/getNodesColumns.tsx +31 -13
  14. package/dist/containers/Storage/Storage.tsx +64 -32
  15. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +56 -73
  16. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +33 -43
  17. package/dist/containers/Storage/utils/index.ts +3 -3
  18. package/dist/containers/Tablet/Tablet.tsx +9 -3
  19. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.scss +8 -0
  20. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.tsx +13 -1
  21. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +3 -1
  22. package/dist/containers/Tenant/Query/i18n/en.json +6 -4
  23. package/dist/containers/Tenant/Query/i18n/ru.json +6 -4
  24. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +4 -0
  25. package/dist/containers/Tenant/i18n/en.json +3 -0
  26. package/dist/containers/Tenant/i18n/ru.json +3 -0
  27. package/dist/containers/Tenant/utils/queryTemplates.ts +89 -0
  28. package/dist/containers/Tenant/utils/schema.ts +1 -1
  29. package/dist/containers/Tenant/utils/schemaActions.ts +30 -54
  30. package/dist/containers/Tenant/utils/schemaControls.tsx +69 -0
  31. package/dist/containers/UserSettings/i18n/en.json +3 -0
  32. package/dist/containers/UserSettings/i18n/ru.json +3 -0
  33. package/dist/containers/UserSettings/settings.ts +12 -1
  34. package/dist/{reportWebVitals.js → reportWebVitals.ts} +3 -1
  35. package/dist/services/api.ts +30 -16
  36. package/dist/store/reducers/{authentication.js → authentication/authentication.ts} +14 -7
  37. package/dist/store/reducers/authentication/types.ts +15 -0
  38. package/dist/store/reducers/describe.ts +1 -16
  39. package/dist/store/reducers/header/types.ts +2 -0
  40. package/dist/store/reducers/index.ts +1 -1
  41. package/dist/store/reducers/nodes/nodes.ts +23 -6
  42. package/dist/store/reducers/nodes/selectors.ts +2 -2
  43. package/dist/store/reducers/nodes/types.ts +15 -5
  44. package/dist/store/reducers/settings/settings.ts +5 -0
  45. package/dist/store/reducers/storage/selectors.ts +50 -150
  46. package/dist/store/reducers/storage/storage.ts +73 -25
  47. package/dist/store/reducers/storage/types.ts +49 -17
  48. package/dist/store/reducers/storage/utils.ts +207 -0
  49. package/dist/store/utils.ts +1 -1
  50. package/dist/types/api/compute.ts +0 -12
  51. package/dist/types/api/error.ts +4 -0
  52. package/dist/types/api/nodes.ts +0 -12
  53. package/dist/types/api/storage.ts +32 -4
  54. package/dist/types/window.d.ts +1 -0
  55. package/dist/utils/constants.ts +3 -0
  56. package/dist/utils/filters.ts +23 -0
  57. package/dist/utils/hooks/index.ts +4 -0
  58. package/dist/utils/hooks/useNodesRequestParams.ts +46 -0
  59. package/dist/utils/hooks/useStorageRequestParams.ts +28 -0
  60. package/dist/utils/hooks/useTableSort.ts +37 -0
  61. package/dist/utils/nodes.ts +25 -0
  62. package/dist/utils/storage.ts +31 -3
  63. package/package.json +2 -6
  64. package/dist/HOCS/WithSearch/WithSearch.js +0 -26
  65. package/dist/HOCS/index.js +0 -1
  66. package/dist/components/Hotkey/Hotkey.js +0 -102
  67. package/dist/components/Pagination/Pagination.js +0 -63
  68. package/dist/components/Pagination/Pagination.scss +0 -28
  69. package/dist/types/store/storage.ts +0 -12
  70. /package/dist/{index.js → index.tsx} +0 -0
  71. /package/dist/utils/{monaco.js → monaco.ts} +0 -0
@@ -1,4 +1,5 @@
1
1
  import type {ClusterTab} from '../../../containers/Cluster/utils';
2
+ import type {EType} from '../../../types/api/tablet';
2
3
 
3
4
  import {setHeaderBreadcrumbs} from './header';
4
5
 
@@ -23,6 +24,7 @@ export interface TabletsBreadcrumbsOptions extends TenantBreadcrumbsOptions {
23
24
 
24
25
  export interface TabletBreadcrumbsOptions extends TabletsBreadcrumbsOptions {
25
26
  tabletId?: string;
27
+ tabletType?: EType;
26
28
  }
27
29
 
28
30
  export type BreadcrumbsOptions =
@@ -30,7 +30,7 @@ import healthcheckInfo from './healthcheckInfo';
30
30
  import shardsWorkload from './shardsWorkload';
31
31
  import hotKeys from './hotKeys';
32
32
  import olapStats from './olapStats';
33
- import authentication from './authentication';
33
+ import authentication from './authentication/authentication';
34
34
  import header from './header/header';
35
35
  import saveQuery from './saveQuery';
36
36
  import fullscreen from './fullscreen';
@@ -10,6 +10,7 @@ import type {
10
10
  ComputeApiRequestParams,
11
11
  NodesAction,
12
12
  NodesApiRequestParams,
13
+ NodesSortParams,
13
14
  NodesState,
14
15
  } from './types';
15
16
  import {prepareComputeNodesData, prepareNodesData} from './utils';
@@ -20,6 +21,7 @@ const RESET_NODES_STATE = 'nodes/RESET_NODES_STATE';
20
21
  const SET_NODES_UPTIME_FILTER = 'nodes/SET_NODES_UPTIME_FILTER';
21
22
  const SET_DATA_WAS_NOT_LOADED = 'nodes/SET_DATA_WAS_NOT_LOADED';
22
23
  const SET_SEARCH_VALUE = 'nodes/SET_SEARCH_VALUE';
24
+ const SET_SORT = 'nodes/SET_SORT';
23
25
 
24
26
  const initialState = {
25
27
  loading: false,
@@ -47,6 +49,10 @@ const nodes: Reducer<NodesState, NodesAction> = (state = initialState, action) =
47
49
  };
48
50
  }
49
51
  case FETCH_NODES.FAILURE: {
52
+ if (action.error?.isCancelled) {
53
+ return state;
54
+ }
55
+
50
56
  return {
51
57
  ...state,
52
58
  error: action.error,
@@ -74,7 +80,13 @@ const nodes: Reducer<NodesState, NodesAction> = (state = initialState, action) =
74
80
  searchValue: action.data,
75
81
  };
76
82
  }
77
-
83
+ case SET_SORT: {
84
+ return {
85
+ ...state,
86
+ sortValue: action.data.sortValue,
87
+ sortOrder: action.data.sortOrder,
88
+ };
89
+ }
78
90
  case SET_DATA_WAS_NOT_LOADED: {
79
91
  return {
80
92
  ...state,
@@ -85,13 +97,11 @@ const nodes: Reducer<NodesState, NodesAction> = (state = initialState, action) =
85
97
  return state;
86
98
  }
87
99
  };
100
+ const concurrentId = 'getNodes';
88
101
 
89
102
  export function getNodes({type = 'any', ...params}: NodesApiRequestParams) {
90
103
  return createApiRequest({
91
- request: window.api.getNodes({
92
- type,
93
- ...params,
94
- }),
104
+ request: window.api.getNodes({type, ...params}, {concurrentId}),
95
105
  actions: FETCH_NODES,
96
106
  dataHandler: prepareNodesData,
97
107
  });
@@ -99,7 +109,7 @@ export function getNodes({type = 'any', ...params}: NodesApiRequestParams) {
99
109
 
100
110
  export function getComputeNodes({version = EVersion.v2, ...params}: ComputeApiRequestParams) {
101
111
  return createApiRequest({
102
- request: window.api.getCompute({version, ...params}),
112
+ request: window.api.getCompute({version, ...params}, {concurrentId}),
103
113
  actions: FETCH_NODES,
104
114
  dataHandler: prepareComputeNodesData,
105
115
  });
@@ -130,4 +140,11 @@ export const setSearchValue = (value: string) => {
130
140
  } as const;
131
141
  };
132
142
 
143
+ export const setSort = (sortParams: NodesSortParams) => {
144
+ return {
145
+ type: SET_SORT,
146
+ data: sortParams,
147
+ } as const;
148
+ };
149
+
133
150
  export default nodes;
@@ -1,10 +1,10 @@
1
1
  import {Selector, createSelector} from 'reselect';
2
- import {escapeRegExp} from 'lodash';
3
2
 
4
3
  import {EFlag} from '../../../types/api/enums';
5
4
  import {calcUptimeInSeconds} from '../../../utils';
6
5
  import {HOUR_IN_SECONDS} from '../../../utils/constants';
7
6
  import {NodesUptimeFilterValues} from '../../../utils/nodes';
7
+ import {prepareSearchValue} from '../../../utils/filters';
8
8
 
9
9
  import type {ProblemFilterValue} from '../settings/types';
10
10
  import type {NodesPreparedEntity, NodesStateSlice} from './types';
@@ -41,7 +41,7 @@ const filterNodesBySearchValue = (nodesList: NodesPreparedEntity[] = [], searchV
41
41
  if (!searchValue) {
42
42
  return nodesList;
43
43
  }
44
- const re = new RegExp(escapeRegExp(searchValue), 'i');
44
+ const re = prepareSearchValue(searchValue);
45
45
 
46
46
  return nodesList.filter((node) => {
47
47
  return node.Host ? re.test(node.Host) || re.test(String(node.NodeId)) : true;
@@ -1,3 +1,5 @@
1
+ import type {OrderType} from '@gravity-ui/react-data-table';
2
+
1
3
  import type {IResponseError} from '../../../types/api/error';
2
4
  import type {TEndpoint, TPoolStats} from '../../../types/api/nodes';
3
5
  import type {
@@ -9,13 +11,14 @@ import type {EFlag} from '../../../types/api/enums';
9
11
  import type {ApiRequestAction} from '../../utils';
10
12
  import type {VisibleEntities} from '../storage/types';
11
13
 
12
- import {NodesUptimeFilterValues} from '../../../utils/nodes';
14
+ import type {NodesSortValue, NodesUptimeFilterValues} from '../../../utils/nodes';
13
15
  import {
14
16
  FETCH_NODES,
15
17
  resetNodesState,
16
18
  setDataWasNotLoaded,
17
19
  setNodesUptimeFilter,
18
20
  setSearchValue,
21
+ setSort,
19
22
  } from './nodes';
20
23
 
21
24
  // Since nodes from different endpoints can have different types,
@@ -42,6 +45,8 @@ export interface NodesState {
42
45
  wasLoaded: boolean;
43
46
  nodesUptimeFilter: NodesUptimeFilterValues;
44
47
  searchValue: string;
48
+ sortValue?: NodesSortValue;
49
+ sortOrder?: OrderType;
45
50
  data?: NodesPreparedEntity[];
46
51
  totalNodes?: number;
47
52
  error?: IResponseError;
@@ -49,17 +54,21 @@ export interface NodesState {
49
54
 
50
55
  export type NodeType = 'static' | 'dynamic' | 'any';
51
56
 
52
- interface RequestParams {
57
+ export interface NodesSortParams {
58
+ sortOrder?: OrderType;
59
+ sortValue?: NodesSortValue;
60
+ }
61
+
62
+ export interface NodesGeneralRequestParams extends NodesSortParams {
53
63
  filter?: string; // NodeId or Host
54
64
  uptime?: number; // return nodes with less uptime in seconds
55
65
  problems_only?: boolean; // return nodes with SystemState !== EFlag.Green
56
- sort?: string; // Sort by one of ESort params (may differ for /nodes and /compute)
57
66
 
58
67
  offser?: number;
59
68
  limit?: number;
60
69
  }
61
70
 
62
- export interface NodesApiRequestParams extends RequestParams {
71
+ export interface NodesApiRequestParams extends NodesGeneralRequestParams {
63
72
  tenant?: string;
64
73
  type?: NodeType;
65
74
  visibleEntities?: VisibleEntities; // "with" param
@@ -67,7 +76,7 @@ export interface NodesApiRequestParams extends RequestParams {
67
76
  tablets?: boolean;
68
77
  }
69
78
 
70
- export interface ComputeApiRequestParams extends RequestParams {
79
+ export interface ComputeApiRequestParams extends NodesGeneralRequestParams {
71
80
  path: string;
72
81
  version?: EVersion; // only v2 works with filters
73
82
  }
@@ -90,6 +99,7 @@ export type NodesAction =
90
99
  | ReturnType<typeof setDataWasNotLoaded>
91
100
  | ReturnType<typeof setNodesUptimeFilter>
92
101
  | ReturnType<typeof setSearchValue>
102
+ | ReturnType<typeof setSort>
93
103
  | ReturnType<typeof resetNodesState>
94
104
  );
95
105
 
@@ -13,6 +13,7 @@ import {
13
13
  ENABLE_ADDITIONAL_QUERY_MODES,
14
14
  CLUSTER_INFO_HIDDEN_KEY,
15
15
  LAST_USED_QUERY_ACTION_KEY,
16
+ USE_BACKEND_PARAMS_FOR_TABLES_KEY,
16
17
  } from '../../../utils/constants';
17
18
  import '../../../services/api';
18
19
  import {getValueFromLS, parseJson} from '../../../utils/utils';
@@ -76,6 +77,10 @@ export const initialState = {
76
77
  [ASIDE_HEADER_COMPACT_KEY]: readSavedSettingsValue(ASIDE_HEADER_COMPACT_KEY, 'true'),
77
78
  [PARTITIONS_HIDDEN_COLUMNS_KEY]: readSavedSettingsValue(PARTITIONS_HIDDEN_COLUMNS_KEY),
78
79
  [CLUSTER_INFO_HIDDEN_KEY]: readSavedSettingsValue(CLUSTER_INFO_HIDDEN_KEY, 'true'),
80
+ [USE_BACKEND_PARAMS_FOR_TABLES_KEY]: readSavedSettingsValue(
81
+ USE_BACKEND_PARAMS_FOR_TABLES_KEY,
82
+ 'false',
83
+ ),
79
84
  },
80
85
  systemSettings,
81
86
  };
@@ -1,128 +1,20 @@
1
1
  import {Selector, createSelector} from 'reselect';
2
- import {getUsage} from '../../../utils/storage';
3
2
 
4
- import type {TNodeInfo} from '../../../types/api/nodes';
5
- import {TPDiskState} from '../../../types/api/pdisk';
6
- import {EVDiskState, TVDiskStateInfo} from '../../../types/api/vdisk';
7
- import {EFlag} from '../../../types/api/enums';
8
- import {getPDiskType} from '../../../utils/pdisk';
9
- import {calcUptime} from '../../../utils';
3
+ import type {OrderType} from '@gravity-ui/react-data-table';
4
+ import {ASCENDING, DESCENDING} from '@gravity-ui/react-data-table/build/esm/lib/constants';
10
5
 
6
+ import type {TVDiskStateInfo} from '../../../types/api/vdisk';
7
+ import {NODES_SORT_VALUES, type NodesSortValue} from '../../../utils/nodes';
8
+ import {STORAGE_SORT_VALUES, type StorageSortValue, getUsage} from '../../../utils/storage';
9
+
10
+ import {filterNodesByUptime} from '../nodes/selectors';
11
11
  import type {
12
12
  PreparedStorageGroup,
13
13
  PreparedStorageNode,
14
- RawStorageGroup,
15
14
  StorageStateSlice,
16
15
  UsageFilter,
17
16
  } from './types';
18
- import {filterNodesByUptime} from '../nodes/selectors';
19
-
20
- // ==== Prepare data ====
21
- const FLAGS_POINTS = {
22
- [EFlag.Green]: 1,
23
- [EFlag.Yellow]: 100,
24
- [EFlag.Orange]: 10_000,
25
- [EFlag.Red]: 1_000_000,
26
- };
27
-
28
- const prepareStorageGroupData = (
29
- group: RawStorageGroup,
30
- poolName?: string,
31
- ): PreparedStorageGroup => {
32
- let missing = 0;
33
- let usedSpaceFlag = 0;
34
- let usedSpaceBytes = 0;
35
- let limitSizeBytes = 0;
36
- let readSpeedBytesPerSec = 0;
37
- let writeSpeedBytesPerSec = 0;
38
- let mediaType = '';
39
-
40
- if (group.VDisks) {
41
- for (const vDisk of group.VDisks) {
42
- const {
43
- Replicated,
44
- VDiskState,
45
- AvailableSize,
46
- AllocatedSize,
47
- PDisk,
48
- DiskSpace,
49
- ReadThroughput,
50
- WriteThroughput,
51
- } = vDisk;
52
-
53
- if (
54
- !Replicated ||
55
- PDisk?.State !== TPDiskState.Normal ||
56
- VDiskState !== EVDiskState.OK
57
- ) {
58
- missing += 1;
59
- }
60
-
61
- if (DiskSpace && DiskSpace !== EFlag.Grey) {
62
- usedSpaceFlag += FLAGS_POINTS[DiskSpace];
63
- }
64
-
65
- const available = Number(AvailableSize ?? PDisk?.AvailableSize) || 0;
66
- const allocated = Number(AllocatedSize) || 0;
67
-
68
- usedSpaceBytes += allocated;
69
- limitSizeBytes += available + allocated;
70
-
71
- readSpeedBytesPerSec += Number(ReadThroughput) || 0;
72
- writeSpeedBytesPerSec += Number(WriteThroughput) || 0;
73
-
74
- const currentType = getPDiskType(PDisk || {});
75
- mediaType =
76
- currentType && (currentType === mediaType || mediaType === '')
77
- ? currentType
78
- : 'Mixed';
79
- }
80
- }
81
-
82
- // VDisk doesn't have its own StoragePoolName when located inside StoragePool data
83
- const vDisks = group.VDisks?.map((vdisk) => ({
84
- ...vdisk,
85
- StoragePoolName: poolName,
86
- Donors: vdisk.Donors?.map((donor) => ({
87
- ...donor,
88
- StoragePoolName: poolName,
89
- })),
90
- }));
91
-
92
- return {
93
- ...group,
94
- VDisks: vDisks,
95
- Read: readSpeedBytesPerSec,
96
- Write: writeSpeedBytesPerSec,
97
- PoolName: poolName,
98
- Used: usedSpaceBytes,
99
- Limit: limitSizeBytes,
100
- Missing: missing,
101
- UsedSpaceFlag: usedSpaceFlag,
102
- Type: mediaType || null,
103
- };
104
- };
105
-
106
- const prepareStorageNodeData = (node: TNodeInfo): PreparedStorageNode => {
107
- const systemState = node.SystemState ?? {};
108
- const missing =
109
- node.PDisks?.filter((pDisk) => {
110
- return pDisk.State !== TPDiskState.Normal;
111
- }).length || 0;
112
-
113
- return {
114
- NodeId: node.NodeId,
115
- SystemState: systemState.SystemState,
116
- DataCenter: systemState.DataCenter,
117
- Rack: systemState.Rack,
118
- Host: systemState.Host,
119
- Endpoints: systemState.Endpoints,
120
- Uptime: calcUptime(systemState.StartTime),
121
- StartTime: systemState.StartTime,
122
- PDisks: node.PDisks,
123
- Missing: missing,
124
- };
125
- };
17
+ import {VISIBLE_ENTITIES} from './constants';
126
18
 
127
19
  // ==== Filters ====
128
20
 
@@ -163,24 +55,21 @@ const filterGroupsByUsage = (entities: PreparedStorageGroup[], usage?: string[])
163
55
  }
164
56
 
165
57
  return entities.filter((entity) => {
166
- const entityUsage = getUsage(entity, 5);
58
+ const entityUsage = entity.Usage;
167
59
  return usage.some((val) => Number(val) <= entityUsage && entityUsage < Number(val) + 5);
168
60
  });
169
61
  };
170
62
 
171
63
  // ==== Simple selectors ====
172
64
 
173
- export const selectStoragePools = (state: StorageStateSlice) => state.storage.groups?.StoragePools;
174
- export const selectStorageGroupsCount = (state: StorageStateSlice) => ({
175
- total: state.storage.groups?.TotalGroups || 0,
176
- found: state.storage.groups?.FoundGroups || 0,
177
- });
178
- export const selectStorageNodes = (state: StorageStateSlice) => state.storage.nodes?.Nodes;
179
- export const selectStorageNodesCount = (state: StorageStateSlice) => ({
180
- total: state.storage.nodes?.TotalNodes || 0,
181
- found: state.storage.nodes?.FoundNodes || 0,
65
+ export const selectEntitiesCount = (state: StorageStateSlice) => ({
66
+ total: state.storage.total,
67
+ found: state.storage.found,
182
68
  });
183
69
 
70
+ export const selectStorageGroups = (state: StorageStateSlice) => state.storage.groups;
71
+ export const selectStorageNodes = (state: StorageStateSlice) => state.storage.nodes;
72
+
184
73
  export const selectStorageFilter = (state: StorageStateSlice) => state.storage.filter;
185
74
  export const selectUsageFilter = (state: StorageStateSlice) => state.storage.usageFilter;
186
75
  export const selectVisibleEntities = (state: StorageStateSlice) => state.storage.visible;
@@ -188,29 +77,39 @@ export const selectNodesUptimeFilter = (state: StorageStateSlice) =>
188
77
  state.storage.nodesUptimeFilter;
189
78
  export const selectStorageType = (state: StorageStateSlice) => state.storage.type;
190
79
 
191
- // ==== Complex selectors ====
80
+ // ==== Sort params selectors ====
81
+ export const selectNodesSortParams = (state: StorageStateSlice) => {
82
+ const defaultSortValue: NodesSortValue = NODES_SORT_VALUES.NodeId;
83
+ const defaultSortOrder: OrderType = ASCENDING;
84
+
85
+ return {
86
+ sortValue: state.storage.nodesSortValue || defaultSortValue,
87
+ sortOrder: state.storage.nodesSortOrder || defaultSortOrder,
88
+ };
89
+ };
192
90
 
193
- const selectPreparedStorageNodes: Selector<StorageStateSlice, PreparedStorageNode[]> =
194
- createSelector(selectStorageNodes, (storageNodes) => {
195
- if (!storageNodes) {
196
- return [];
197
- }
91
+ export const selectGroupsSortParams = (state: StorageStateSlice) => {
92
+ const visibleEntities = state.storage.visible;
198
93
 
199
- return storageNodes.map(prepareStorageNodeData);
200
- });
94
+ let defaultSortValue: StorageSortValue = STORAGE_SORT_VALUES.PoolName;
95
+ let defaultSortOrder: OrderType = ASCENDING;
201
96
 
202
- export const selectPreparedStorageGroups: Selector<StorageStateSlice, PreparedStorageGroup[]> =
203
- createSelector(selectStoragePools, (storagePools) => {
204
- const preparedGroups: PreparedStorageGroup[] = [];
97
+ if (visibleEntities === VISIBLE_ENTITIES.missing) {
98
+ defaultSortValue = STORAGE_SORT_VALUES.Degraded;
99
+ defaultSortOrder = DESCENDING;
100
+ }
205
101
 
206
- storagePools?.forEach((pool) => {
207
- pool.Groups?.forEach((group) => {
208
- preparedGroups.push(prepareStorageGroupData(group, pool.Name));
209
- });
210
- });
102
+ if (visibleEntities === VISIBLE_ENTITIES.space) {
103
+ defaultSortValue = STORAGE_SORT_VALUES.Usage;
104
+ defaultSortOrder = DESCENDING;
105
+ }
211
106
 
212
- return preparedGroups;
213
- });
107
+ return {
108
+ sortValue: state.storage.groupsSortValue || defaultSortValue,
109
+ sortOrder: state.storage.groupsSortOrder || defaultSortOrder,
110
+ };
111
+ };
112
+ // ==== Complex selectors ====
214
113
 
215
114
  export const selectVDisksForPDisk: Selector<
216
115
  StorageStateSlice,
@@ -232,11 +131,12 @@ export const selectVDisksForPDisk: Selector<
232
131
  );
233
132
 
234
133
  export const selectUsageFilterOptions: Selector<StorageStateSlice, UsageFilter[]> = createSelector(
235
- selectPreparedStorageGroups,
134
+ selectStorageGroups,
236
135
  (groups) => {
237
136
  const items: Record<number, number> = {};
238
137
 
239
- groups.forEach((group) => {
138
+ groups?.forEach((group) => {
139
+ // Get groups usage with step 5
240
140
  const usage = getUsage(group, 5);
241
141
 
242
142
  if (!Object.prototype.hasOwnProperty.call(items, usage)) {
@@ -256,9 +156,9 @@ export const selectUsageFilterOptions: Selector<StorageStateSlice, UsageFilter[]
256
156
 
257
157
  export const selectFilteredNodes: Selector<StorageStateSlice, PreparedStorageNode[]> =
258
158
  createSelector(
259
- [selectPreparedStorageNodes, selectStorageFilter, selectNodesUptimeFilter],
159
+ [selectStorageNodes, selectStorageFilter, selectNodesUptimeFilter],
260
160
  (storageNodes, textFilter, uptimeFilter) => {
261
- let result = storageNodes;
161
+ let result = storageNodes || [];
262
162
  result = filterNodesByText(result, textFilter);
263
163
  result = filterNodesByUptime(result, uptimeFilter);
264
164
 
@@ -268,9 +168,9 @@ export const selectFilteredNodes: Selector<StorageStateSlice, PreparedStorageNod
268
168
 
269
169
  export const selectFilteredGroups: Selector<StorageStateSlice, PreparedStorageGroup[]> =
270
170
  createSelector(
271
- [selectPreparedStorageGroups, selectStorageFilter, selectUsageFilter],
171
+ [selectStorageGroups, selectStorageFilter, selectUsageFilter],
272
172
  (storageGroups, textFilter, usageFilter) => {
273
- let result = storageGroups;
173
+ let result = storageGroups || [];
274
174
  result = filterGroupsByText(result, textFilter);
275
175
  result = filterGroupsByUsage(result, usageFilter);
276
176
 
@@ -1,13 +1,23 @@
1
1
  import type {Reducer} from 'redux';
2
2
  import _ from 'lodash';
3
3
 
4
+ import {EVersion} from '../../../types/api/storage';
4
5
  import {NodesUptimeFilterValues} from '../../../utils/nodes';
5
6
  import '../../../services/api';
6
7
 
7
8
  import {createRequestActionTypes, createApiRequest} from '../../utils';
8
9
 
9
- import type {StorageAction, StorageState, StorageType, VisibleEntities} from './types';
10
+ import type {NodesApiRequestParams, NodesSortParams} from '../nodes/types';
11
+ import type {
12
+ StorageAction,
13
+ StorageApiRequestParams,
14
+ StorageSortParams,
15
+ StorageState,
16
+ StorageType,
17
+ VisibleEntities,
18
+ } from './types';
10
19
  import {VISIBLE_ENTITIES, STORAGE_TYPES} from './constants';
20
+ import {prepareStorageGroupsResponse, prepareStorageNodesResponse} from './utils';
11
21
 
12
22
  export const FETCH_STORAGE = createRequestActionTypes('storage', 'FETCH_STORAGE');
13
23
 
@@ -18,6 +28,8 @@ const SET_VISIBLE_GROUPS = 'storage/SET_VISIBLE_GROUPS';
18
28
  const SET_STORAGE_TYPE = 'storage/SET_STORAGE_TYPE';
19
29
  const SET_NODES_UPTIME_FILTER = 'storage/SET_NODES_UPTIME_FILTER';
20
30
  const SET_DATA_WAS_NOT_LOADED = 'storage/SET_DATA_WAS_NOT_LOADED';
31
+ const SET_NODES_SORT_PARAMS = 'storage/SET_NODES_SORT_PARAMS';
32
+ const SET_GROUPS_SORT_PARAMS = 'storage/SET_GROUPS_SORT_PARAMS';
21
33
 
22
34
  const initialState = {
23
35
  loading: true,
@@ -42,6 +54,8 @@ const storage: Reducer<StorageState, StorageAction> = (state = initialState, act
42
54
  ...state,
43
55
  nodes: action.data.nodes,
44
56
  groups: action.data.groups,
57
+ total: action.data.total,
58
+ found: action.data.found,
45
59
  loading: false,
46
60
  wasLoaded: true,
47
61
  error: undefined,
@@ -80,6 +94,7 @@ const storage: Reducer<StorageState, StorageAction> = (state = initialState, act
80
94
  return {
81
95
  ...state,
82
96
  visible: action.data,
97
+ usageFilter: [],
83
98
  wasLoaded: false,
84
99
  error: undefined,
85
100
  };
@@ -107,39 +122,58 @@ const storage: Reducer<StorageState, StorageAction> = (state = initialState, act
107
122
  wasLoaded: false,
108
123
  };
109
124
  }
125
+ case SET_NODES_SORT_PARAMS: {
126
+ return {
127
+ ...state,
128
+ nodesSortValue: action.data.sortValue,
129
+ nodesSortOrder: action.data.sortOrder,
130
+ };
131
+ }
132
+ case SET_GROUPS_SORT_PARAMS: {
133
+ return {
134
+ ...state,
135
+ groupsSortValue: action.data.sortValue,
136
+ groupsSortOrder: action.data.sortOrder,
137
+ };
138
+ }
110
139
  default:
111
140
  return state;
112
141
  }
113
142
  };
114
143
 
115
- export function getStorageInfo(
116
- {
117
- tenant,
118
- visibleEntities,
119
- nodeId,
120
- type,
121
- }: {
122
- tenant?: string;
123
- visibleEntities?: VisibleEntities;
124
- nodeId?: string;
125
- type?: StorageType;
126
- },
127
- {concurrentId}: {concurrentId?: string} = {},
128
- ) {
129
- if (type === STORAGE_TYPES.nodes) {
130
- return createApiRequest({
131
- request: window.api.getNodes({tenant, visibleEntities, type: 'static'}, {concurrentId}),
132
- actions: FETCH_STORAGE,
133
- dataHandler: (data) => ({nodes: data}),
134
- });
135
- }
144
+ const concurrentId = 'getStorageInfo';
136
145
 
146
+ export const getStorageNodesInfo = ({
147
+ tenant,
148
+ visibleEntities,
149
+ ...params
150
+ }: Omit<NodesApiRequestParams, 'type'>) => {
137
151
  return createApiRequest({
138
- request: window.api.getStorageInfo({tenant, visibleEntities, nodeId}, {concurrentId}),
152
+ request: window.api.getNodes(
153
+ {tenant, visibleEntities, type: 'static', ...params},
154
+ {concurrentId},
155
+ ),
139
156
  actions: FETCH_STORAGE,
140
- dataHandler: (data) => ({groups: data}),
157
+ dataHandler: prepareStorageNodesResponse,
141
158
  });
142
- }
159
+ };
160
+
161
+ export const getStorageGroupsInfo = ({
162
+ tenant,
163
+ visibleEntities,
164
+ nodeId,
165
+ version = EVersion.v1,
166
+ ...params
167
+ }: StorageApiRequestParams) => {
168
+ return createApiRequest({
169
+ request: window.api.getStorageInfo(
170
+ {tenant, visibleEntities, nodeId, version, ...params},
171
+ {concurrentId},
172
+ ),
173
+ actions: FETCH_STORAGE,
174
+ dataHandler: prepareStorageGroupsResponse,
175
+ });
176
+ };
143
177
 
144
178
  export function setInitialState() {
145
179
  return {
@@ -188,4 +222,18 @@ export const setDataWasNotLoaded = () => {
188
222
  } as const;
189
223
  };
190
224
 
225
+ export const setNodesSortParams = (sortParams: NodesSortParams) => {
226
+ return {
227
+ type: SET_NODES_SORT_PARAMS,
228
+ data: sortParams,
229
+ } as const;
230
+ };
231
+
232
+ export const setGroupsSortParams = (sortParams: StorageSortParams) => {
233
+ return {
234
+ type: SET_GROUPS_SORT_PARAMS,
235
+ data: sortParams,
236
+ } as const;
237
+ };
238
+
191
239
  export default storage;