ydb-embedded-ui 4.14.0 → 4.15.1

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 (42) hide show
  1. package/CHANGELOG.md +16 -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 +113 -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);