ydb-embedded-ui 4.0.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/components/ClusterInfo/ClusterInfo.tsx +3 -3
  3. package/dist/components/LabelWithPopover/LabelWithPopover.tsx +10 -4
  4. package/dist/{containers/Nodes/NodesTable.scss → components/NodeHostWrapper/NodeHostWrapper.scss} +4 -6
  5. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +60 -0
  6. package/dist/components/TabletsStatistic/TabletsStatistic.scss +1 -1
  7. package/dist/containers/App/App.scss +7 -4
  8. package/dist/containers/AsideNavigation/AsideNavigation.tsx +1 -11
  9. package/dist/containers/Header/Header.tsx +1 -1
  10. package/dist/containers/Nodes/getNodesColumns.tsx +7 -46
  11. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +3 -12
  12. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +0 -24
  13. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +2 -39
  14. package/dist/containers/Storage/VDisk/VDisk.tsx +4 -11
  15. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +13 -16
  16. package/dist/containers/Storage/utils/types.ts +2 -1
  17. package/dist/containers/Tablet/Tablet.scss +4 -0
  18. package/dist/containers/Tablet/TabletTable/TabletTable.tsx +28 -6
  19. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +1 -1
  20. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +4 -3
  21. package/dist/containers/Tenant/QueryEditor/Issues/Issues.scss +1 -1
  22. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +1 -1
  23. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +1 -1
  24. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +12 -0
  25. package/dist/containers/Tenants/Tenants.js +1 -1
  26. package/dist/containers/UserSettings/UserSettings.tsx +19 -17
  27. package/dist/services/api.ts +383 -0
  28. package/dist/store/reducers/{cluster.js → cluster/cluster.ts} +9 -14
  29. package/dist/store/reducers/cluster/types.ts +13 -0
  30. package/dist/store/reducers/executeTopQueries.ts +2 -2
  31. package/dist/store/reducers/index.ts +5 -4
  32. package/dist/store/reducers/node.js +5 -1
  33. package/dist/store/reducers/nodesList.ts +2 -7
  34. package/dist/store/reducers/settings.js +1 -14
  35. package/dist/store/reducers/storage.js +12 -0
  36. package/dist/store/reducers/tablet.ts +16 -2
  37. package/dist/store/reducers/{tenants.js → tenants/tenants.ts} +14 -9
  38. package/dist/store/reducers/tenants/types.ts +17 -0
  39. package/dist/store/utils.ts +3 -2
  40. package/dist/types/api/acl.ts +25 -0
  41. package/dist/types/api/cluster.ts +3 -0
  42. package/dist/types/api/compute.ts +5 -3
  43. package/dist/types/api/netInfo.ts +48 -0
  44. package/dist/types/api/nodes.ts +5 -3
  45. package/dist/types/api/pdisk.ts +11 -2
  46. package/dist/types/api/storage.ts +5 -3
  47. package/dist/types/api/tenant.ts +18 -3
  48. package/dist/types/api/vdisk.ts +10 -2
  49. package/dist/types/api/whoami.ts +19 -0
  50. package/dist/types/store/tablet.ts +1 -0
  51. package/dist/types/window.d.ts +5 -0
  52. package/dist/utils/createToast.tsx +2 -2
  53. package/dist/utils/hooks/useTypedSelector.ts +2 -2
  54. package/dist/utils/nodes.ts +14 -1
  55. package/package.json +4 -4
  56. package/dist/services/api.d.ts +0 -87
  57. package/dist/services/api.js +0 -278
@@ -86,9 +86,10 @@ const prepareTableGeneralInfo = (PartitionConfig: TPartitionConfig, TTLSettings?
86
86
 
87
87
  const generalTableInfo: InfoViewerItem[] = [];
88
88
 
89
- const partitioningBySize = PartitioningPolicy.SizeToSplit
90
- ? `Enabled, split size: ${formatBytes(PartitioningPolicy.SizeToSplit)}`
91
- : 'Disabled';
89
+ const partitioningBySize =
90
+ PartitioningPolicy.SizeToSplit && Number(PartitioningPolicy.SizeToSplit) > 0
91
+ ? `Enabled, split size: ${formatBytes(PartitioningPolicy.SizeToSplit)}`
92
+ : 'Disabled';
92
93
 
93
94
  const partitioningByLoad = PartitioningPolicy.SplitByLoadSettings?.Enabled
94
95
  ? 'Enabled'
@@ -106,7 +106,7 @@
106
106
  }
107
107
 
108
108
  &_severity_warning &__icon {
109
- color: var(--yc-color-text-warning-medium);
109
+ color: var(--yc-color-text-warning);
110
110
  }
111
111
 
112
112
  &_severity_info &__icon {
@@ -48,7 +48,7 @@ export const OldQueryEditorControls = ({
48
48
  </Button>
49
49
  <DropdownMenu
50
50
  items={runModeSelectorMenuItems}
51
- popupClassName={b('select-query-action-popup')}
51
+ popupProps={{className: b('select-query-action-popup')}}
52
52
  switcher={
53
53
  <Button
54
54
  view="action"
@@ -61,7 +61,7 @@ export const QueryEditorControls = ({
61
61
  </Button>
62
62
  <DropdownMenu
63
63
  items={querySelectorMenuItems}
64
- popupClassName={b('mode-selector__popup')}
64
+ popupProps={{className: b('mode-selector__popup')}}
65
65
  switcher={
66
66
  <Button className={b('mode-selector__button')}>
67
67
  <span className={b('mode-selector__button-content')}>
@@ -16,6 +16,7 @@ const SchemaViewerColumns = {
16
16
  name: 'Name',
17
17
  key: 'Key',
18
18
  type: 'Type',
19
+ notNull: 'NotNull',
19
20
  };
20
21
 
21
22
  class SchemaViewer extends React.Component {
@@ -59,6 +60,17 @@ class SchemaViewer extends React.Component {
59
60
  name: SchemaViewerColumns.type,
60
61
  width: 100,
61
62
  },
63
+ {
64
+ name: SchemaViewerColumns.notNull,
65
+ width: 100,
66
+ render: ({row}) => {
67
+ if (row.NotNull) {
68
+ return '\u2713';
69
+ }
70
+
71
+ return undefined;
72
+ },
73
+ },
62
74
  ];
63
75
 
64
76
  const tableData = [...keyColumns, ...restColumns];
@@ -20,7 +20,7 @@ import {formatCPU, formatBytesToGigabyte, formatNumber} from '../../utils';
20
20
  import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
21
21
  import {withSearch} from '../../HOCS';
22
22
  import {ALL, DEFAULT_TABLE_SETTINGS, TENANT_INITIAL_TAB_KEY} from '../../utils/constants';
23
- import {getTenantsInfo} from '../../store/reducers/tenants';
23
+ import {getTenantsInfo} from '../../store/reducers/tenants/tenants';
24
24
  import {changeFilter, getSettingValue} from '../../store/reducers/settings';
25
25
  import {setHeader} from '../../store/reducers/header';
26
26
 
@@ -2,12 +2,14 @@ import {ReactNode} from 'react';
2
2
  import {connect} from 'react-redux';
3
3
  import cn from 'bem-cn-lite';
4
4
 
5
- import {RadioButton, Switch, HelpPopover} from '@gravity-ui/uikit';
5
+ import {RadioButton, Switch} from '@gravity-ui/uikit';
6
6
  import {Settings} from '@gravity-ui/navigation';
7
7
 
8
8
  import favoriteFilledIcon from '../../assets/icons/star.svg';
9
9
  import flaskIcon from '../../assets/icons/flask.svg';
10
10
 
11
+ import {LabelWithPopover} from '../../components/LabelWithPopover/LabelWithPopover';
12
+
11
13
  import {
12
14
  ENABLE_QUERY_MODES_FOR_EXPLAIN,
13
15
  INVERTED_DISKS_KEY,
@@ -46,27 +48,27 @@ function UserSettings(props: any) {
46
48
 
47
49
  const renderBreakNodesSettingsItem = (title: ReactNode) => {
48
50
  return (
49
- <div className={b('item-with-popup')}>
50
- {title}
51
- <HelpPopover
52
- content="Use /viewer/json/nodes endpoint for Nodes Tab in diagnostics. It returns incorrect data on older versions"
53
- contentClassName={b('popup')}
54
- hasArrow={true}
55
- />
56
- </div>
51
+ <LabelWithPopover
52
+ className={b('item-with-popup')}
53
+ contentClassName={b('popup')}
54
+ text={title}
55
+ popoverContent={
56
+ 'Use /viewer/json/nodes endpoint for Nodes Tab in diagnostics. It returns incorrect data on older versions'
57
+ }
58
+ />
57
59
  );
58
60
  };
59
61
 
60
62
  const renderEnableExplainQueryModesItem = (title: ReactNode) => {
61
63
  return (
62
- <div className={b('item-with-popup')}>
63
- {title}
64
- <HelpPopover
65
- content="Enable script | scan query mode selector for both run and explain. May not work on some versions"
66
- contentClassName={b('popup')}
67
- hasArrow={true}
68
- />
69
- </div>
64
+ <LabelWithPopover
65
+ className={b('item-with-popup')}
66
+ contentClassName={b('popup')}
67
+ text={title}
68
+ popoverContent={
69
+ 'Enable script | scan query mode selector for both run and explain. May not work on some versions'
70
+ }
71
+ />
70
72
  );
71
73
  };
72
74
 
@@ -0,0 +1,383 @@
1
+ import AxiosWrapper from '@gravity-ui/axios-wrapper';
2
+
3
+ import type {
4
+ Actions,
5
+ ExplainActions,
6
+ ExplainResponse,
7
+ QueryAPIResponse,
8
+ Schemas,
9
+ } from '../types/api/query';
10
+ import type {
11
+ TDomainKey,
12
+ TEvTabletStateResponse,
13
+ UnmergedTEvTabletStateResponse,
14
+ } from '../types/api/tablet';
15
+ import type {TMetaInfo} from '../types/api/acl';
16
+ import type {TClusterInfo} from '../types/api/cluster';
17
+ import type {TComputeInfo} from '../types/api/compute';
18
+ import type {DescribeConsumerResult} from '../types/api/consumer';
19
+ import type {HealthCheckAPIResponse} from '../types/api/healthcheck';
20
+ import type {TNetInfo} from '../types/api/netInfo';
21
+ import type {TNodesInfo} from '../types/api/nodes';
22
+ import type {TEvNodesInfo} from '../types/api/nodesList';
23
+ import type {TEvDescribeSchemeResult} from '../types/api/schema';
24
+ import type {TStorageInfo} from '../types/api/storage';
25
+ import type {TEvSystemStateResponse} from '../types/api/systemState';
26
+ import type {TTenantInfo, TTenants} from '../types/api/tenant';
27
+ import type {DescribeTopicResult} from '../types/api/topic';
28
+ import type {TEvPDiskStateResponse} from '../types/api/pdisk';
29
+ import type {TEvVDiskStateResponse} from '../types/api/vdisk';
30
+ import type {TUserToken} from '../types/api/whoami';
31
+ import type {INodesApiRequestParams} from '../types/store/nodes';
32
+
33
+ import {backend as BACKEND} from '../store';
34
+
35
+ const config = {withCredentials: !window.custom_backend};
36
+
37
+ const settingsApi = window.web_version ? window.systemSettings?.settingsApi : undefined;
38
+
39
+ type AxiosOptions = {
40
+ concurrentId?: string;
41
+ };
42
+
43
+ export class YdbEmbeddedAPI extends AxiosWrapper {
44
+ getPath(path: string) {
45
+ return `${BACKEND}${path}`;
46
+ }
47
+ getClusterInfo(clusterName?: string) {
48
+ return this.get<TClusterInfo>(this.getPath('/viewer/json/cluster'), {
49
+ name: clusterName,
50
+ tablets: true,
51
+ });
52
+ }
53
+ getNodeInfo(id?: string) {
54
+ return this.get<TEvSystemStateResponse>(this.getPath('/viewer/json/sysinfo?enums=true'), {
55
+ node_id: id,
56
+ });
57
+ }
58
+ getTenants(clusterName?: string) {
59
+ return this.get<TTenantInfo>(this.getPath('/viewer/json/tenantinfo'), {
60
+ tablets: 1,
61
+ storage: 1,
62
+ cluster_name: clusterName,
63
+ });
64
+ }
65
+ getTenantInfo({path}: {path: string}) {
66
+ return this.get<TTenantInfo>(this.getPath('/viewer/json/tenantinfo'), {
67
+ path,
68
+ tablets: true,
69
+ storage: true,
70
+ });
71
+ }
72
+ getNodes(
73
+ {tenant, filter, storage, type = 'any', tablets = true}: INodesApiRequestParams,
74
+ {concurrentId}: AxiosOptions = {},
75
+ ) {
76
+ return this.get<TNodesInfo>(
77
+ this.getPath('/viewer/json/nodes?enums=true'),
78
+ {
79
+ tenant,
80
+ with: filter,
81
+ storage,
82
+ type,
83
+ tablets,
84
+ },
85
+ {
86
+ concurrentId,
87
+ },
88
+ );
89
+ }
90
+ getCompute(path: string) {
91
+ return this.get<TComputeInfo>(this.getPath('/viewer/json/compute?enums=true'), {path});
92
+ }
93
+ getStorageInfo(
94
+ {
95
+ tenant,
96
+ filter,
97
+ nodeId,
98
+ }: {
99
+ tenant: string;
100
+ filter: string;
101
+ nodeId: string;
102
+ },
103
+ {concurrentId}: AxiosOptions = {},
104
+ ) {
105
+ return this.get<TStorageInfo>(
106
+ this.getPath(`/viewer/json/storage?enums=true`),
107
+ {
108
+ tenant,
109
+ node_id: nodeId,
110
+ with: filter,
111
+ },
112
+ {
113
+ concurrentId,
114
+ },
115
+ );
116
+ }
117
+ getPdiskInfo(nodeId: string | number, pdiskId: string | number) {
118
+ return this.get<TEvPDiskStateResponse>(this.getPath('/viewer/json/pdiskinfo?enums=true'), {
119
+ filter: `(NodeId=${nodeId}${pdiskId ? `;PDiskId=${pdiskId}` : ''})`,
120
+ });
121
+ }
122
+ getVdiskInfo({
123
+ vdiskId,
124
+ pdiskId,
125
+ nodeId,
126
+ }: {
127
+ vdiskId: string | number;
128
+ pdiskId: string | number;
129
+ nodeId: string | number;
130
+ }) {
131
+ return this.get<TEvVDiskStateResponse>(this.getPath('/viewer/json/vdiskinfo?enums=true'), {
132
+ filter: `(VDiskId=${vdiskId ?? ''};PDiskId=${pdiskId ?? ''};NodeId=${nodeId ?? ''})`,
133
+ });
134
+ }
135
+ getGroupInfo(groupId: string | number) {
136
+ return this.get<TStorageInfo>(this.getPath('/viewer/json/storage?enums=true'), {
137
+ group_id: groupId,
138
+ });
139
+ }
140
+ getHostInfo() {
141
+ return this.get<TEvSystemStateResponse>(
142
+ this.getPath('/viewer/json/sysinfo?node_id=.&enums=true'),
143
+ {},
144
+ );
145
+ }
146
+ getTabletsInfo({nodes = [], path}: {nodes?: string[]; path?: string}) {
147
+ const filter = nodes.length > 0 && `(NodeId=[${nodes.join(',')}])`;
148
+ return this.get<TEvTabletStateResponse>(this.getPath('/viewer/json/tabletinfo'), {
149
+ filter,
150
+ path,
151
+ enums: true,
152
+ });
153
+ }
154
+ getSchema({path}: {path: string}, {concurrentId}: AxiosOptions = {}) {
155
+ return this.get<TEvDescribeSchemeResult>(
156
+ this.getPath('/viewer/json/describe'),
157
+ {
158
+ path,
159
+ enums: true,
160
+ backup: false,
161
+ private: true,
162
+ partition_config: true,
163
+ partition_stats: true,
164
+ partitioning_info: true,
165
+ subs: 1,
166
+ },
167
+ {concurrentId: concurrentId || `getSchema|${path}`},
168
+ );
169
+ }
170
+ getDescribe({path}: {path: string}, {concurrentId}: AxiosOptions = {}) {
171
+ return this.get<TEvDescribeSchemeResult>(
172
+ this.getPath('/viewer/json/describe'),
173
+ {
174
+ path,
175
+ enums: true,
176
+ partition_stats: true,
177
+ subs: 0,
178
+ },
179
+ {concurrentId: concurrentId || `getDescribe|${path}`},
180
+ );
181
+ }
182
+ getSchemaAcl({path}: {path: string}) {
183
+ return this.get<TMetaInfo>(
184
+ this.getPath('/viewer/json/acl'),
185
+ {
186
+ path,
187
+ },
188
+ {concurrentId: `getSchemaAcl|${path}`},
189
+ );
190
+ }
191
+ getHeatmapData({path}: {path: string}) {
192
+ return this.get<TEvDescribeSchemeResult>(this.getPath('/viewer/json/describe'), {
193
+ path,
194
+ enums: true,
195
+ backup: false,
196
+ children: false,
197
+ partition_config: false,
198
+ partition_stats: true,
199
+ });
200
+ }
201
+ getNetwork(path: string) {
202
+ return this.get<TNetInfo>(this.getPath('/viewer/json/netinfo'), {
203
+ enums: true,
204
+ path,
205
+ });
206
+ }
207
+ getTopic({path}: {path?: string}, {concurrentId}: AxiosOptions = {}) {
208
+ return this.get<DescribeTopicResult>(
209
+ this.getPath('/viewer/json/describe_topic'),
210
+ {
211
+ enums: true,
212
+ include_stats: true,
213
+ path,
214
+ },
215
+ {concurrentId: concurrentId || 'getTopic'},
216
+ );
217
+ }
218
+ getConsumer(
219
+ {path, consumer}: {path?: string; consumer?: string},
220
+ {concurrentId}: AxiosOptions = {},
221
+ ) {
222
+ return this.get<DescribeConsumerResult>(
223
+ this.getPath('/viewer/json/describe_consumer'),
224
+ {
225
+ enums: true,
226
+ include_stats: true,
227
+ path,
228
+ consumer,
229
+ },
230
+ {concurrentId: concurrentId || 'getConsumer'},
231
+ );
232
+ }
233
+ getPoolInfo(poolName: string) {
234
+ return this.get<TStorageInfo>(this.getPath('/viewer/json/storage'), {
235
+ pool: poolName,
236
+ enums: true,
237
+ });
238
+ }
239
+ getTablet({id}: {id?: string}) {
240
+ return this.get<TEvTabletStateResponse>(
241
+ this.getPath(`/viewer/json/tabletinfo?filter=(TabletId=${id})`),
242
+ {
243
+ enums: true,
244
+ },
245
+ );
246
+ }
247
+ getTabletHistory({id}: {id?: string}) {
248
+ return this.get<UnmergedTEvTabletStateResponse>(
249
+ this.getPath(`/viewer/json/tabletinfo?filter=(TabletId=${id})`),
250
+ {
251
+ enums: true,
252
+ merge: false,
253
+ },
254
+ );
255
+ }
256
+ getNodesList() {
257
+ return this.get<TEvNodesInfo>(this.getPath('/viewer/json/nodelist'), {enums: true});
258
+ }
259
+ getTenantsList() {
260
+ return this.get<TTenants>(this.getPath('/viewer/json/tenants'), {
261
+ enums: true,
262
+ state: 0,
263
+ });
264
+ }
265
+ sendQuery<Action extends Actions, Schema extends Schemas = undefined>(
266
+ {
267
+ query,
268
+ database,
269
+ action,
270
+ stats,
271
+ schema,
272
+ }: {
273
+ query?: string;
274
+ database?: string;
275
+ action?: Action;
276
+ stats?: string;
277
+ schema?: Schema;
278
+ },
279
+ {concurrentId}: AxiosOptions = {},
280
+ ) {
281
+ return this.post<QueryAPIResponse<Action, Schema>>(
282
+ this.getPath(`/viewer/json/query${schema ? `?schema=${schema}` : ''}`),
283
+ {
284
+ query,
285
+ database,
286
+ action,
287
+ stats,
288
+ timeout: 600000,
289
+ },
290
+ {},
291
+ {
292
+ concurrentId,
293
+ timeout: 9 * 60 * 1000,
294
+ },
295
+ );
296
+ }
297
+ getExplainQuery<Action extends ExplainActions>(
298
+ query: string,
299
+ database: string,
300
+ action: Action,
301
+ ) {
302
+ return this.post<ExplainResponse<Action>>(
303
+ this.getPath('/viewer/json/query'),
304
+ {
305
+ query,
306
+ database,
307
+ action: action || 'explain',
308
+ timeout: 600000,
309
+ },
310
+ {},
311
+ );
312
+ }
313
+ getExplainQueryAst(query: string, database: string) {
314
+ return this.post<ExplainResponse<'explain-ast'>>(
315
+ this.getPath('/viewer/json/query'),
316
+ {
317
+ query,
318
+ database,
319
+ action: 'explain-ast',
320
+ timeout: 600000,
321
+ },
322
+ {},
323
+ );
324
+ }
325
+ getHotKeys(path: string, enableSampling: boolean) {
326
+ return this.get(this.getPath('/viewer/json/hotkeys'), {
327
+ path,
328
+ enable_sampling: enableSampling,
329
+ });
330
+ }
331
+ getHealthcheckInfo(database: string) {
332
+ return this.get<HealthCheckAPIResponse>(this.getPath('/viewer/json/healthcheck'), {
333
+ tenant: database,
334
+ });
335
+ }
336
+ killTablet(id?: string) {
337
+ return this.get<string>(this.getPath(`/tablets?KillTabletID=${id}`), {});
338
+ }
339
+ stopTablet(id?: string, hiveId?: string) {
340
+ return this.get<string>(
341
+ this.getPath(`/tablets/app?TabletID=${hiveId}&page=StopTablet&tablet=${id}`),
342
+ {},
343
+ );
344
+ }
345
+ resumeTablet(id?: string, hiveId?: string) {
346
+ return this.get<string>(
347
+ this.getPath(`/tablets/app?TabletID=${hiveId}&page=ResumeTablet&tablet=${id}`),
348
+ {},
349
+ );
350
+ }
351
+ getTabletDescribe(tenantId: TDomainKey) {
352
+ return this.get<TEvDescribeSchemeResult>(this.getPath('/viewer/json/describe'), {
353
+ schemeshard_id: tenantId?.SchemeShard,
354
+ path_id: tenantId?.PathId,
355
+ });
356
+ }
357
+ postSetting(name: string, value: string) {
358
+ return this.request({
359
+ method: 'PATCH',
360
+ url: settingsApi || '',
361
+ data: {[name]: value},
362
+ });
363
+ }
364
+ authenticate(user: string, password: string) {
365
+ return this.post(
366
+ this.getPath('/login'),
367
+ {
368
+ user,
369
+ password,
370
+ },
371
+ {},
372
+ );
373
+ }
374
+ logout() {
375
+ return this.post(this.getPath('/logout'), {}, {});
376
+ }
377
+ whoami() {
378
+ return this.get<TUserToken>(this.getPath('/viewer/json/whoami'), {});
379
+ }
380
+ }
381
+
382
+ const api = new YdbEmbeddedAPI({config: config});
383
+ window.api = api;
@@ -1,11 +1,14 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
2
- import '../../services/api';
1
+ import type {Reducer} from 'redux';
3
2
 
4
- const FETCH_CLUSTER = createRequestActionTypes('cluster', 'FETCH_CLUSTER');
3
+ import '../../../services/api';
4
+ import {createRequestActionTypes, createApiRequest} from '../../utils';
5
+ import type {ClusterAction, ClusterState} from './types';
6
+
7
+ export const FETCH_CLUSTER = createRequestActionTypes('cluster', 'FETCH_CLUSTER');
5
8
 
6
9
  const initialState = {loading: true, wasLoaded: false};
7
10
 
8
- const cluster = function (state = initialState, action) {
11
+ const cluster: Reducer<ClusterState, ClusterAction> = (state = initialState, action) => {
9
12
  switch (action.type) {
10
13
  case FETCH_CLUSTER.REQUEST: {
11
14
  return {
@@ -14,17 +17,9 @@ const cluster = function (state = initialState, action) {
14
17
  };
15
18
  }
16
19
  case FETCH_CLUSTER.SUCCESS: {
17
- const {data} = action;
18
- const clusterInfo = data.cluster ? data.cluster.cluster : data;
19
- const clusterName = data.cluster?.title || data.Name;
20
20
  return {
21
21
  ...state,
22
- data: {
23
- ...clusterInfo,
24
- balancer: data.cluster?.balancer,
25
- solomon: data.cluster?.solomon,
26
- Name: clusterName,
27
- },
22
+ data: action.data,
28
23
  loading: false,
29
24
  wasLoaded: true,
30
25
  error: undefined,
@@ -42,7 +37,7 @@ const cluster = function (state = initialState, action) {
42
37
  }
43
38
  };
44
39
 
45
- export function getClusterInfo(clusterName) {
40
+ export function getClusterInfo(clusterName?: string) {
46
41
  return createApiRequest({
47
42
  request: window.api.getClusterInfo(clusterName),
48
43
  actions: FETCH_CLUSTER,
@@ -0,0 +1,13 @@
1
+ import {FETCH_CLUSTER} from './cluster';
2
+
3
+ import type {TClusterInfo} from '../../../types/api/cluster';
4
+ import type {ApiRequestAction} from '../../utils';
5
+
6
+ export interface ClusterState {
7
+ loading: boolean;
8
+ wasLoaded: boolean;
9
+ data?: TClusterInfo;
10
+ error?: unknown;
11
+ }
12
+
13
+ export type ClusterAction = ApiRequestAction<typeof FETCH_CLUSTER, TClusterInfo, unknown>;
@@ -13,7 +13,7 @@ import {parseQueryAPIExecuteResponse} from '../../utils/query';
13
13
 
14
14
  import {createRequestActionTypes, createApiRequest} from '../utils';
15
15
 
16
- import type {IRootState} from '.';
16
+ import type {RootState} from '.';
17
17
 
18
18
  export const FETCH_TOP_QUERIES = createRequestActionTypes('top-queries', 'FETCH_TOP_QUERIES');
19
19
  const SET_TOP_QUERIES_STATE = 'top-queries/SET_TOP_QUERIES_STATE';
@@ -126,7 +126,7 @@ const executeTopQueries: Reducer<ITopQueriesState, ITopQueriesAction> = (
126
126
  type FetchTopQueries = (params: {
127
127
  database: string;
128
128
  filters?: ITopQueriesFilters;
129
- }) => ThunkAction<Promise<IQueryResult | undefined>, IRootState, unknown, AnyAction>;
129
+ }) => ThunkAction<Promise<IQueryResult | undefined>, RootState, unknown, AnyAction>;
130
130
 
131
131
  export const fetchTopQueries: FetchTopQueries =
132
132
  ({database, filters}) =>
@@ -1,7 +1,7 @@
1
1
  import {combineReducers} from 'redux';
2
2
 
3
3
  import nodes from './nodes';
4
- import cluster from './cluster';
4
+ import cluster from './cluster/cluster';
5
5
  import tenant from './tenant';
6
6
  import storage from './storage';
7
7
  import node from './node';
@@ -15,7 +15,7 @@ import schema from './schema';
15
15
  import host from './host';
16
16
  import network from './network';
17
17
  import pool from './pool';
18
- import tenants from './tenants';
18
+ import tenants from './tenants/tenants';
19
19
  import tablet from './tablet';
20
20
  import topic from './topic';
21
21
  import consumer from './consumer';
@@ -82,7 +82,8 @@ const combinedReducer = combineReducers({
82
82
  ...rootReducer,
83
83
  });
84
84
 
85
- export type IRootReducer = typeof combinedReducer;
86
- export type IRootState = ReturnType<IRootReducer>;
85
+ export type RootReducer = typeof combinedReducer;
86
+ export type RootState = ReturnType<RootReducer>;
87
+ export type GetState = () => RootState;
87
88
 
88
89
  export default combinedReducer;
@@ -116,7 +116,11 @@ export const selectNodeStructure = createSelector(
116
116
  if (!structure[String(pDiskId)]) {
117
117
  structure[String(pDiskId)] = {vDisks: {}, ...vd.PDisk};
118
118
  }
119
- structure[String(pDiskId)].vDisks[vDiskId] = vd;
119
+ structure[String(pDiskId)].vDisks[vDiskId] = {
120
+ ...vd,
121
+ // VDisk doesn't have its own StoragePoolName when located inside StoragePool data
122
+ StoragePoolName: pool.Name,
123
+ };
120
124
  });
121
125
  });
122
126
  });
@@ -4,10 +4,10 @@ import type {
4
4
  NodesListState,
5
5
  NodesListAction,
6
6
  NodesListRootStateSlice,
7
- NodesMap,
8
7
  } from '../../types/store/nodesList';
9
8
  import '../../services/api';
10
9
  import {createRequestActionTypes, createApiRequest} from '../utils';
10
+ import {prepareNodesMap} from '../../utils/nodes';
11
11
 
12
12
  export const FETCH_NODES_LIST = createRequestActionTypes('nodesList', 'FETCH_NODES_LIST');
13
13
 
@@ -50,11 +50,6 @@ export function getNodesList() {
50
50
  }
51
51
 
52
52
  export const selectNodesMap = (state: NodesListRootStateSlice) =>
53
- state.nodesList.data?.reduce<NodesMap>((nodesMap, node) => {
54
- if (node.Id && node.Host) {
55
- nodesMap.set(node.Id, node.Host);
56
- }
57
- return nodesMap;
58
- }, new Map());
53
+ prepareNodesMap(state.nodesList.data);
59
54
 
60
55
  export default nodesList;