ydb-embedded-ui 4.14.0 → 4.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/containers/App/App.js +1 -1
  3. package/dist/containers/AsideNavigation/AsideNavigation.tsx +1 -1
  4. package/dist/containers/Authentication/Authentication.tsx +1 -1
  5. package/dist/containers/Storage/Storage.tsx +64 -32
  6. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +56 -73
  7. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +33 -43
  8. package/dist/containers/Storage/utils/index.ts +3 -3
  9. package/dist/containers/Tenant/i18n/en.json +3 -0
  10. package/dist/containers/Tenant/i18n/ru.json +3 -0
  11. package/dist/containers/Tenant/utils/queryTemplates.ts +89 -0
  12. package/dist/containers/Tenant/utils/schema.ts +1 -1
  13. package/dist/containers/Tenant/utils/schemaActions.ts +27 -44
  14. package/dist/containers/UserSettings/i18n/en.json +1 -1
  15. package/dist/containers/UserSettings/i18n/ru.json +1 -1
  16. package/dist/{reportWebVitals.js → reportWebVitals.ts} +3 -1
  17. package/dist/services/api.ts +6 -4
  18. package/dist/store/reducers/{authentication.js → authentication/authentication.ts} +14 -7
  19. package/dist/store/reducers/authentication/types.ts +15 -0
  20. package/dist/store/reducers/describe.ts +1 -16
  21. package/dist/store/reducers/index.ts +1 -1
  22. package/dist/store/reducers/storage/selectors.ts +50 -150
  23. package/dist/store/reducers/storage/storage.ts +73 -25
  24. package/dist/store/reducers/storage/types.ts +49 -17
  25. package/dist/store/reducers/storage/utils.ts +207 -0
  26. package/dist/store/utils.ts +1 -1
  27. package/dist/types/api/error.ts +4 -0
  28. package/dist/types/api/storage.ts +32 -4
  29. package/dist/types/window.d.ts +1 -0
  30. package/dist/utils/hooks/index.ts +1 -0
  31. package/dist/utils/hooks/useStorageRequestParams.ts +28 -0
  32. package/dist/utils/hooks/useTableSort.ts +1 -1
  33. package/dist/utils/storage.ts +31 -3
  34. package/package.json +1 -5
  35. package/dist/HOCS/WithSearch/WithSearch.js +0 -26
  36. package/dist/HOCS/index.js +0 -1
  37. package/dist/components/Hotkey/Hotkey.js +0 -102
  38. package/dist/components/Pagination/Pagination.js +0 -63
  39. package/dist/components/Pagination/Pagination.scss +0 -28
  40. package/dist/types/store/storage.ts +0 -12
  41. /package/dist/{index.js → index.tsx} +0 -0
  42. /package/dist/utils/{monaco.js → monaco.ts} +0 -0
@@ -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;
@@ -1,20 +1,22 @@
1
+ import type {OrderType} from '@gravity-ui/react-data-table';
2
+
1
3
  import type {IResponseError} from '../../../types/api/error';
2
- import type {TNodesInfo, TSystemStateInfo} from '../../../types/api/nodes';
4
+ import type {TSystemStateInfo} from '../../../types/api/nodes';
3
5
  import type {TPDiskStateInfo} from '../../../types/api/pdisk';
4
- import type {
5
- TBSGroupStateInfo,
6
- THiveStorageGroupStats,
7
- TStorageInfo,
8
- } from '../../../types/api/storage';
6
+ import type {EVersion, TStorageGroupInfo} from '../../../types/api/storage';
7
+ import type {TVDiskStateInfo} from '../../../types/api/vdisk';
9
8
  import type {ValueOf} from '../../../types/common';
10
- import type {NodesUptimeFilterValues} from '../../../utils/nodes';
9
+ import type {NodesSortValue, NodesUptimeFilterValues} from '../../../utils/nodes';
10
+ import type {StorageSortValue} from '../../../utils/storage';
11
11
  import type {ApiRequestAction} from '../../utils';
12
12
 
13
13
  import {STORAGE_TYPES, VISIBLE_ENTITIES} from './constants';
14
14
  import {
15
15
  FETCH_STORAGE,
16
16
  setDataWasNotLoaded,
17
+ setGroupsSortParams,
17
18
  setInitialState,
19
+ setNodesSortParams,
18
20
  setNodesUptimeFilter,
19
21
  setStorageTextFilter,
20
22
  setStorageType,
@@ -28,23 +30,24 @@ export type StorageType = ValueOf<typeof STORAGE_TYPES>;
28
30
  export interface PreparedStorageNode extends TSystemStateInfo {
29
31
  NodeId: number;
30
32
  PDisks: TPDiskStateInfo[] | undefined;
33
+ VDisks: TVDiskStateInfo[] | undefined;
31
34
 
32
35
  Missing: number;
33
36
  Uptime: string;
34
37
  }
35
38
 
36
- export type RawStorageGroup = TBSGroupStateInfo & THiveStorageGroupStats;
37
-
38
- export interface PreparedStorageGroup extends RawStorageGroup {
39
+ export interface PreparedStorageGroup extends TStorageGroupInfo {
39
40
  PoolName: string | undefined;
40
41
 
42
+ Usage: number;
41
43
  Read: number;
42
44
  Write: number;
43
45
  Used: number;
44
46
  Limit: number;
45
- Missing: number;
47
+ Degraded: number;
48
+ Kind: string | undefined;
49
+
46
50
  UsedSpaceFlag: number;
47
- Type: string | null;
48
51
  }
49
52
 
50
53
  export interface UsageFilter {
@@ -52,10 +55,24 @@ export interface UsageFilter {
52
55
  count: number;
53
56
  }
54
57
 
55
- export interface StorageApiRequestParams {
58
+ export interface StorageSortParams {
59
+ sortOrder?: OrderType;
60
+ sortValue?: StorageSortValue;
61
+ }
62
+
63
+ export interface StorageSortAndFilterParams extends StorageSortParams {
64
+ filter?: string; // PoolName or GroupId
65
+
66
+ offser?: number;
67
+ limit?: number;
68
+ }
69
+
70
+ export interface StorageApiRequestParams extends StorageSortAndFilterParams {
56
71
  tenant?: string;
57
72
  nodeId?: string;
58
73
  visibleEntities?: VisibleEntities;
74
+
75
+ version?: EVersion;
59
76
  }
60
77
 
61
78
  export interface StorageState {
@@ -65,15 +82,28 @@ export interface StorageState {
65
82
  usageFilter: string[];
66
83
  visible: VisibleEntities;
67
84
  nodesUptimeFilter: NodesUptimeFilterValues;
85
+ groupsSortValue?: StorageSortValue;
86
+ groupsSortOrder?: OrderType;
87
+ nodesSortValue?: NodesSortValue;
88
+ nodesSortOrder?: OrderType;
68
89
  type: StorageType;
69
- nodes?: TNodesInfo;
70
- groups?: TStorageInfo;
90
+ nodes?: PreparedStorageNode[];
91
+ groups?: PreparedStorageGroup[];
92
+ found?: number;
93
+ total?: number;
71
94
  error?: IResponseError;
72
95
  }
73
96
 
97
+ export interface PreparedStorageResponse {
98
+ nodes?: PreparedStorageNode[];
99
+ groups?: PreparedStorageGroup[];
100
+ found: number | undefined;
101
+ total: number | undefined;
102
+ }
103
+
74
104
  type GetStorageInfoApiRequestAction = ApiRequestAction<
75
105
  typeof FETCH_STORAGE,
76
- {nodes?: TNodesInfo; groups?: TStorageInfo},
106
+ PreparedStorageResponse,
77
107
  IResponseError
78
108
  >;
79
109
 
@@ -85,7 +115,9 @@ export type StorageAction =
85
115
  | ReturnType<typeof setUsageFilter>
86
116
  | ReturnType<typeof setVisibleEntities>
87
117
  | ReturnType<typeof setNodesUptimeFilter>
88
- | ReturnType<typeof setDataWasNotLoaded>;
118
+ | ReturnType<typeof setDataWasNotLoaded>
119
+ | ReturnType<typeof setNodesSortParams>
120
+ | ReturnType<typeof setGroupsSortParams>;
89
121
 
90
122
  export interface StorageStateSlice {
91
123
  storage: StorageState;
@@ -0,0 +1,207 @@
1
+ import type {TNodeInfo, TNodesInfo} from '../../../types/api/nodes';
2
+ import type {
3
+ TStorageGroupInfo,
4
+ TStorageGroupInfoV2,
5
+ TStorageInfo,
6
+ } from '../../../types/api/storage';
7
+ import {EVDiskState, type TVDiskStateInfo} from '../../../types/api/vdisk';
8
+ import {TPDiskState} from '../../../types/api/pdisk';
9
+ import {EFlag} from '../../../types/api/enums';
10
+ import {getPDiskType} from '../../../utils/pdisk';
11
+ import {getUsage} from '../../../utils/storage';
12
+ import {calcUptime} from '../../../utils';
13
+
14
+ import type {PreparedStorageGroup, PreparedStorageNode, PreparedStorageResponse} from './types';
15
+
16
+ // ==== Constants ====
17
+
18
+ const FLAGS_POINTS = {
19
+ [EFlag.Green]: 1,
20
+ [EFlag.Yellow]: 100,
21
+ [EFlag.Orange]: 10_000,
22
+ [EFlag.Red]: 1_000_000,
23
+ };
24
+
25
+ // ==== Prepare groups ====
26
+
27
+ const prepareVDisk = (vDisk: TVDiskStateInfo, poolName: string | undefined) => {
28
+ // VDisk doesn't have its own StoragePoolName when located inside StoragePool data
29
+ return {
30
+ ...vDisk,
31
+ StoragePoolName: poolName,
32
+ Donors: vDisk.Donors?.map((donor) => ({
33
+ ...donor,
34
+ StoragePoolName: poolName,
35
+ })),
36
+ };
37
+ };
38
+
39
+ const prepareStorageGroupData = (
40
+ group: TStorageGroupInfo,
41
+ poolName?: string,
42
+ ): PreparedStorageGroup => {
43
+ let missing = 0;
44
+ let usedSpaceFlag = 0;
45
+ let usedSpaceBytes = 0;
46
+ let limitSizeBytes = 0;
47
+ let readSpeedBytesPerSec = 0;
48
+ let writeSpeedBytesPerSec = 0;
49
+ let mediaType = '';
50
+
51
+ if (group.VDisks) {
52
+ for (const vDisk of group.VDisks) {
53
+ const {
54
+ Replicated,
55
+ VDiskState,
56
+ AvailableSize,
57
+ AllocatedSize,
58
+ PDisk,
59
+ DiskSpace,
60
+ ReadThroughput,
61
+ WriteThroughput,
62
+ } = vDisk;
63
+
64
+ if (
65
+ !Replicated ||
66
+ PDisk?.State !== TPDiskState.Normal ||
67
+ VDiskState !== EVDiskState.OK
68
+ ) {
69
+ missing += 1;
70
+ }
71
+
72
+ if (DiskSpace && DiskSpace !== EFlag.Grey) {
73
+ usedSpaceFlag += FLAGS_POINTS[DiskSpace];
74
+ }
75
+
76
+ const available = Number(AvailableSize ?? PDisk?.AvailableSize) || 0;
77
+ const allocated = Number(AllocatedSize) || 0;
78
+
79
+ usedSpaceBytes += allocated;
80
+ limitSizeBytes += available + allocated;
81
+
82
+ readSpeedBytesPerSec += Number(ReadThroughput) || 0;
83
+ writeSpeedBytesPerSec += Number(WriteThroughput) || 0;
84
+
85
+ const currentType = getPDiskType(PDisk || {});
86
+ mediaType =
87
+ currentType && (currentType === mediaType || mediaType === '')
88
+ ? currentType
89
+ : 'Mixed';
90
+ }
91
+ }
92
+
93
+ const vDisks = group.VDisks?.map((vdisk) => prepareVDisk(vdisk, poolName));
94
+ const usage = getUsage({Used: usedSpaceBytes, Limit: limitSizeBytes}, 5);
95
+
96
+ return {
97
+ ...group,
98
+ VDisks: vDisks,
99
+ Usage: usage,
100
+ Read: readSpeedBytesPerSec,
101
+ Write: writeSpeedBytesPerSec,
102
+ PoolName: poolName,
103
+ Used: usedSpaceBytes,
104
+ Limit: limitSizeBytes,
105
+ Degraded: missing,
106
+ UsedSpaceFlag: usedSpaceFlag,
107
+ Kind: mediaType || undefined,
108
+ };
109
+ };
110
+
111
+ const prepareStorageGroupDataV2 = (group: TStorageGroupInfoV2): PreparedStorageGroup => {
112
+ const {
113
+ VDisks = [],
114
+ PoolName,
115
+ Usage = 0,
116
+ Read = 0,
117
+ Write = 0,
118
+ Used = 0,
119
+ Limit = 0,
120
+ Degraded = 0,
121
+ Kind,
122
+ } = group;
123
+
124
+ const UsedSpaceFlag = VDisks.reduce((acc, {DiskSpace}) => {
125
+ if (DiskSpace && DiskSpace !== EFlag.Grey) {
126
+ return acc + FLAGS_POINTS[DiskSpace];
127
+ }
128
+ return acc;
129
+ }, 0);
130
+
131
+ const vDisks = VDisks.map((vdisk) => prepareVDisk(vdisk, PoolName));
132
+ const usage = Math.floor(Number(Usage) * 100);
133
+
134
+ return {
135
+ ...group,
136
+ UsedSpaceFlag,
137
+ PoolName,
138
+ Kind,
139
+ VDisks: vDisks,
140
+ Usage: usage,
141
+ Read: Number(Read),
142
+ Write: Number(Write),
143
+ Used: Number(Used),
144
+ Limit: Number(Limit),
145
+ Degraded: Number(Degraded),
146
+ };
147
+ };
148
+
149
+ // ==== Prepare nodes ====
150
+
151
+ const prepareStorageNodeData = (node: TNodeInfo): PreparedStorageNode => {
152
+ const systemState = node.SystemState ?? {};
153
+ const missing =
154
+ node.PDisks?.filter((pDisk) => {
155
+ return pDisk.State !== TPDiskState.Normal;
156
+ }).length || 0;
157
+
158
+ return {
159
+ NodeId: node.NodeId,
160
+ SystemState: systemState.SystemState,
161
+ DataCenter: systemState.DataCenter,
162
+ Rack: systemState.Rack,
163
+ Host: systemState.Host,
164
+ Endpoints: systemState.Endpoints,
165
+ Uptime: calcUptime(systemState.StartTime),
166
+ StartTime: systemState.StartTime,
167
+ PDisks: node.PDisks,
168
+ VDisks: node.VDisks,
169
+ Missing: missing,
170
+ };
171
+ };
172
+
173
+ // ==== Prepare responses ====
174
+
175
+ export const prepareStorageNodesResponse = (data: TNodesInfo): PreparedStorageResponse => {
176
+ const {Nodes, TotalNodes, FoundNodes} = data;
177
+
178
+ const preparedNodes = Nodes?.map(prepareStorageNodeData);
179
+
180
+ return {
181
+ nodes: preparedNodes,
182
+ total: Number(TotalNodes) || preparedNodes?.length,
183
+ found: Number(FoundNodes),
184
+ };
185
+ };
186
+
187
+ export const prepareStorageGroupsResponse = (data: TStorageInfo): PreparedStorageResponse => {
188
+ const {StoragePools, StorageGroups, TotalGroups, FoundGroups} = data;
189
+
190
+ let preparedGroups: PreparedStorageGroup[] = [];
191
+
192
+ if (StorageGroups) {
193
+ preparedGroups = StorageGroups.map(prepareStorageGroupDataV2);
194
+ } else {
195
+ StoragePools?.forEach((pool) => {
196
+ pool.Groups?.forEach((group) => {
197
+ preparedGroups.push(prepareStorageGroupData(group, pool.Name));
198
+ });
199
+ });
200
+ }
201
+
202
+ return {
203
+ groups: preparedGroups,
204
+ total: Number(TotalGroups) || preparedGroups.length,
205
+ found: Number(FoundGroups),
206
+ };
207
+ };
@@ -3,7 +3,7 @@ import {AxiosResponse} from 'axios';
3
3
 
4
4
  import createToast from '../utils/createToast';
5
5
 
6
- import {SET_UNAUTHENTICATED} from './reducers/authentication';
6
+ import {SET_UNAUTHENTICATED} from './reducers/authentication/authentication';
7
7
  import type {GetState} from './reducers';
8
8
 
9
9
  export const nop = (result: any) => result;
@@ -18,3 +18,7 @@ export interface NetworkError {
18
18
  number?: unknown;
19
19
  stack?: string;
20
20
  }
21
+
22
+ export type AuthErrorResponse = IResponseError<{
23
+ error?: string;
24
+ }>;
@@ -8,7 +8,8 @@ import {TVDiskStateInfo} from './vdisk';
8
8
  */
9
9
  export interface TStorageInfo {
10
10
  Overall?: EFlag;
11
- StoragePools?: TStoragePoolInfo[];
11
+ StoragePools?: TStoragePoolInfo[]; // v1
12
+ StorageGroups?: TStorageGroupInfoV2[]; // v2
12
13
  /** uint64 */
13
14
  TotalGroups?: string;
14
15
  /** uint64 */
@@ -19,7 +20,7 @@ interface TStoragePoolInfo {
19
20
  Overall?: EFlag;
20
21
  Name?: string;
21
22
  Kind?: string;
22
- Groups?: (TBSGroupStateInfo & THiveStorageGroupStats)[];
23
+ Groups?: TStorageGroupInfo[];
23
24
  /** uint64 */
24
25
  AcquiredUnits?: string;
25
26
  AcquiredIOPS?: number;
@@ -34,7 +35,29 @@ interface TStoragePoolInfo {
34
35
  MaximumSize?: string;
35
36
  }
36
37
 
37
- export interface TBSGroupStateInfo {
38
+ export interface TStorageGroupInfoV2 extends TStorageGroupInfo {
39
+ PoolName?: string;
40
+ Kind?: string;
41
+
42
+ /** uint64 */
43
+ Degraded?: string;
44
+
45
+ /** uint64 */
46
+ Used: string;
47
+ /** uint64 */
48
+ Limit: string;
49
+ /** uint64 */
50
+ Read: string;
51
+ /** uint64 */
52
+ Write: string;
53
+
54
+ /** uint64 */
55
+ Usage?: string;
56
+ }
57
+
58
+ export type TStorageGroupInfo = TBSGroupStateInfo & THiveStorageGroupStats;
59
+
60
+ interface TBSGroupStateInfo {
38
61
  GroupID?: number;
39
62
  ErasureSpecies?: string;
40
63
  VDisks?: TVDiskStateInfo[];
@@ -57,7 +80,7 @@ export interface TBSGroupStateInfo {
57
80
  Encryption?: boolean;
58
81
  }
59
82
 
60
- export interface THiveStorageGroupStats {
83
+ interface THiveStorageGroupStats {
61
84
  GroupID?: number;
62
85
  /** uint64 */
63
86
  AcquiredUnits?: string;
@@ -76,3 +99,8 @@ export interface THiveStorageGroupStats {
76
99
  /** uint64 */
77
100
  AvailableSize?: string;
78
101
  }
102
+
103
+ export enum EVersion {
104
+ v1 = 'v1',
105
+ v2 = 'v2', // only this versions works with sorting
106
+ }
@@ -37,6 +37,7 @@ interface Window {
37
37
  custom_backend?: string;
38
38
 
39
39
  __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof import('redux').compose;
40
+ store?: import('redux').Store;
40
41
 
41
42
  userSettings?: Record<string, string | undefined>;
42
43
  systemSettings?: Record<string, string | undefined>;
@@ -5,3 +5,4 @@ export * from './useQueryModes';
5
5
  export * from './useTableSort';
6
6
 
7
7
  export * from './useNodesRequestParams';
8
+ export * from './useStorageRequestParams';
@@ -0,0 +1,28 @@
1
+ import {useMemo} from 'react';
2
+
3
+ import type {StorageSortAndFilterParams} from '../../store/reducers/storage/types';
4
+ import {EVersion} from '../../types/api/storage';
5
+ import {USE_BACKEND_PARAMS_FOR_TABLES_KEY} from '../constants';
6
+ import {useSetting} from './useSetting';
7
+
8
+ export const useStorageRequestParams = ({
9
+ filter,
10
+ sortOrder,
11
+ sortValue,
12
+ }: StorageSortAndFilterParams) => {
13
+ const [useBackendParamsForTables] = useSetting<boolean>(USE_BACKEND_PARAMS_FOR_TABLES_KEY);
14
+
15
+ // If backend params are enabled, update params value to use them in fetch request
16
+ // Otherwise no params will be updated, no hooks that depend on requestParams will be triggered
17
+ return useMemo(() => {
18
+ if (useBackendParamsForTables) {
19
+ return {
20
+ version: EVersion.v2,
21
+ filter,
22
+ sortOrder,
23
+ sortValue,
24
+ };
25
+ }
26
+ return undefined;
27
+ }, [useBackendParamsForTables, filter, sortOrder, sortValue]);
28
+ };
@@ -8,7 +8,7 @@ interface SortParams {
8
8
  sortOrder: OrderType | undefined;
9
9
  }
10
10
 
11
- type HandleSort = (rawValue: SortOrder | SortOrder[] | undefined) => void;
11
+ export type HandleSort = (rawValue: SortOrder | SortOrder[] | undefined) => void;
12
12
 
13
13
  export const useTableSort = (
14
14
  {sortValue, sortOrder = DESCENDING}: SortParams,
@@ -1,12 +1,40 @@
1
1
  import type {TVSlotId, TVDiskStateInfo} from '../types/api/vdisk';
2
- import type {IStoragePoolGroup} from '../types/store/storage';
2
+ import type {ValueOf} from '../types/common';
3
3
 
4
4
  export const isFullVDiskData = (disk: TVDiskStateInfo | TVSlotId): disk is TVDiskStateInfo =>
5
5
  'VDiskId' in disk;
6
6
 
7
- export const getUsage = (data: IStoragePoolGroup, step = 1) => {
7
+ interface EntityWithUsage {
8
+ Used: number;
9
+ Limit: number;
10
+ }
11
+
12
+ export const getUsage = <T extends EntityWithUsage>(data: T, step = 1) => {
8
13
  // if limit is 0, display 0
9
- const usage = Math.round((data.Used * 100) / data.Limit) || 0;
14
+ const usage = data.Limit ? (data.Used * 100) / data.Limit : 0;
10
15
 
11
16
  return Math.floor(usage / step) * step;
12
17
  };
18
+
19
+ /**
20
+ * Values to sort /storage v2 response
21
+ *
22
+ * Source: https://github.com/ydb-platform/ydb/blob/main/ydb/core/viewer/json_storage.h
23
+ */
24
+ export const STORAGE_SORT_VALUES = {
25
+ PoolName: 'PoolName',
26
+ Kind: 'Kind',
27
+ Erasure: 'Erasure',
28
+ Degraded: 'Degraded',
29
+ Usage: 'Usage',
30
+ GroupId: 'GroupId',
31
+ Used: 'Used',
32
+ Limit: 'Limit',
33
+ Read: 'Read',
34
+ Write: 'Write',
35
+ } as const;
36
+
37
+ export type StorageSortValue = ValueOf<typeof STORAGE_SORT_VALUES>;
38
+
39
+ export const isSortableStorageProperty = (value: string): value is StorageSortValue =>
40
+ Object.values(STORAGE_SORT_VALUES).includes(value as StorageSortValue);