ydb-embedded-ui 4.0.0 → 4.1.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.
- package/CHANGELOG.md +12 -0
- package/dist/components/ClusterInfo/ClusterInfo.tsx +3 -3
- package/dist/{containers/Nodes/NodesTable.scss → components/NodeHostWrapper/NodeHostWrapper.scss} +4 -6
- package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +60 -0
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +1 -11
- package/dist/containers/Header/Header.tsx +1 -1
- package/dist/containers/Nodes/getNodesColumns.tsx +7 -46
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +0 -24
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +2 -39
- package/dist/containers/Tenants/Tenants.js +1 -1
- package/dist/services/api.ts +383 -0
- package/dist/store/reducers/{cluster.js → cluster/cluster.ts} +9 -14
- package/dist/store/reducers/cluster/types.ts +13 -0
- package/dist/store/reducers/executeTopQueries.ts +2 -2
- package/dist/store/reducers/index.ts +5 -4
- package/dist/store/reducers/settings.js +1 -14
- package/dist/store/reducers/{tenants.js → tenants/tenants.ts} +14 -9
- package/dist/store/reducers/tenants/types.ts +17 -0
- package/dist/store/utils.ts +3 -2
- package/dist/types/api/acl.ts +25 -0
- package/dist/types/api/cluster.ts +3 -0
- package/dist/types/api/compute.ts +5 -3
- package/dist/types/api/netInfo.ts +48 -0
- package/dist/types/api/nodes.ts +5 -3
- package/dist/types/api/pdisk.ts +11 -2
- package/dist/types/api/storage.ts +5 -3
- package/dist/types/api/tenant.ts +18 -3
- package/dist/types/api/vdisk.ts +10 -2
- package/dist/types/api/whoami.ts +19 -0
- package/dist/types/window.d.ts +5 -0
- package/dist/utils/hooks/useTypedSelector.ts +2 -2
- package/dist/utils/nodes.ts +3 -1
- package/package.json +1 -1
- package/dist/services/api.d.ts +0 -87
- package/dist/services/api.js +0 -278
@@ -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
|
+
null,
|
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
|
+
null,
|
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
|
+
null,
|
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}`), null);
|
338
|
+
}
|
339
|
+
stopTablet(id?: string, hiveId?: string) {
|
340
|
+
return this.get<string>(
|
341
|
+
this.getPath(`/tablets/app?TabletID=${hiveId}&page=StopTablet&tablet=${id}`),
|
342
|
+
null,
|
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
|
+
null,
|
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
|
+
null,
|
372
|
+
);
|
373
|
+
}
|
374
|
+
logout() {
|
375
|
+
return this.post(this.getPath('/logout'), null, null);
|
376
|
+
}
|
377
|
+
whoami() {
|
378
|
+
return this.get<TUserToken>(this.getPath('/viewer/json/whoami'), null);
|
379
|
+
}
|
380
|
+
}
|
381
|
+
|
382
|
+
const api = new YdbEmbeddedAPI({config: config});
|
383
|
+
window.api = api;
|
@@ -1,11 +1,14 @@
|
|
1
|
-
import {
|
2
|
-
import '../../services/api';
|
1
|
+
import type {Reducer} from 'redux';
|
3
2
|
|
4
|
-
|
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 =
|
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 {
|
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>,
|
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
|
86
|
-
export type
|
85
|
+
export type RootReducer = typeof combinedReducer;
|
86
|
+
export type RootState = ReturnType<RootReducer>;
|
87
|
+
export type GetState = () => RootState;
|
87
88
|
|
88
89
|
export default combinedReducer;
|
@@ -26,16 +26,6 @@ export function readSavedSettingsValue(key, defaultValue) {
|
|
26
26
|
return savedValue ?? defaultValue;
|
27
27
|
}
|
28
28
|
|
29
|
-
// navigation managed its compact state internally before, and its approach is not compatible with settings
|
30
|
-
// try reading the old localStorage entry to use it as a default value, for backward compatibility
|
31
|
-
// assume it is safe to remove this code block if it is at least a few months old
|
32
|
-
// there a two of these, search for a similar comment
|
33
|
-
let legacyAsideNavCompactState = '';
|
34
|
-
try {
|
35
|
-
legacyAsideNavCompactState = String(JSON.parse(getValueFromLS('nvAsideHeader')).isCompact);
|
36
|
-
localStorage.removeItem('nvAsideHeader');
|
37
|
-
} catch {}
|
38
|
-
|
39
29
|
export const initialState = {
|
40
30
|
problemFilter: ALL,
|
41
31
|
userSettings: {
|
@@ -53,10 +43,7 @@ export const initialState = {
|
|
53
43
|
[SAVED_QUERIES_KEY]: readSavedSettingsValue(SAVED_QUERIES_KEY, '[]'),
|
54
44
|
[TENANT_INITIAL_TAB_KEY]: readSavedSettingsValue(TENANT_INITIAL_TAB_KEY),
|
55
45
|
[QUERY_INITIAL_MODE_KEY]: readSavedSettingsValue(QUERY_INITIAL_MODE_KEY, QueryModes.script),
|
56
|
-
[ASIDE_HEADER_COMPACT_KEY]: readSavedSettingsValue(
|
57
|
-
ASIDE_HEADER_COMPACT_KEY,
|
58
|
-
legacyAsideNavCompactState || 'true',
|
59
|
-
),
|
46
|
+
[ASIDE_HEADER_COMPACT_KEY]: readSavedSettingsValue(ASIDE_HEADER_COMPACT_KEY, 'true'),
|
60
47
|
[PARTITIONS_SELECTED_COLUMNS_KEY]: readSavedSettingsValue(PARTITIONS_SELECTED_COLUMNS_KEY),
|
61
48
|
},
|
62
49
|
systemSettings,
|
@@ -1,12 +1,15 @@
|
|
1
|
-
import
|
2
|
-
import {createRequestActionTypes, createApiRequest} from '../utils';
|
3
|
-
import '../../services/api';
|
1
|
+
import type {Reducer} from 'redux';
|
4
2
|
|
5
|
-
|
3
|
+
import '../../../services/api';
|
4
|
+
import {createRequestActionTypes, createApiRequest} from '../../utils';
|
6
5
|
|
7
|
-
|
6
|
+
import type {TenantsAction, TenantsState} from './types';
|
8
7
|
|
9
|
-
const
|
8
|
+
export const FETCH_TENANTS = createRequestActionTypes('tenants', 'FETCH_TENANTS');
|
9
|
+
|
10
|
+
const initialState = {loading: true, wasLoaded: false};
|
11
|
+
|
12
|
+
const tenants: Reducer<TenantsState, TenantsAction> = (state = initialState, action) => {
|
10
13
|
switch (action.type) {
|
11
14
|
case FETCH_TENANTS.REQUEST: {
|
12
15
|
return {
|
@@ -35,20 +38,22 @@ const tenants = function (state = initialState, action) {
|
|
35
38
|
}
|
36
39
|
};
|
37
40
|
|
38
|
-
export function getTenantsInfo(clusterName) {
|
41
|
+
export function getTenantsInfo(clusterName?: string) {
|
39
42
|
return createApiRequest({
|
40
43
|
request: window.api.getTenants(clusterName),
|
41
44
|
actions: FETCH_TENANTS,
|
42
45
|
dataHandler: (response, getState) => {
|
43
46
|
const {singleClusterMode} = getState();
|
47
|
+
|
44
48
|
if (singleClusterMode) {
|
45
49
|
return response.TenantInfo;
|
46
50
|
} else {
|
47
|
-
return response.
|
51
|
+
return response.TenantInfo?.map((tenant) => {
|
48
52
|
const node = tenant.Nodes ? tenant.Nodes[0] : {};
|
49
53
|
const address =
|
50
54
|
node.Host && node.Endpoints
|
51
|
-
?
|
55
|
+
? node.Endpoints.find((endpoint) => endpoint.Name === 'http-mon')
|
56
|
+
?.Address
|
52
57
|
: undefined;
|
53
58
|
const backend = node.Host ? `${node.Host}${address ? address : ''}` : undefined;
|
54
59
|
return {...tenant, backend};
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import {FETCH_TENANTS} from './tenants';
|
2
|
+
|
3
|
+
import type {TTenant} from '../../../types/api/tenant';
|
4
|
+
import type {ApiRequestAction} from '../../utils';
|
5
|
+
|
6
|
+
export interface PreparedTenant extends TTenant {
|
7
|
+
backend?: string;
|
8
|
+
}
|
9
|
+
|
10
|
+
export interface TenantsState {
|
11
|
+
loading: boolean;
|
12
|
+
wasLoaded: boolean;
|
13
|
+
tenants?: PreparedTenant[];
|
14
|
+
error?: unknown;
|
15
|
+
}
|
16
|
+
|
17
|
+
export type TenantsAction = ApiRequestAction<typeof FETCH_TENANTS, PreparedTenant[], unknown>;
|
package/dist/store/utils.ts
CHANGED
@@ -4,6 +4,7 @@ import {AxiosResponse} from 'axios';
|
|
4
4
|
import createToast from '../utils/createToast';
|
5
5
|
|
6
6
|
import {SET_UNAUTHENTICATED} from './reducers/authentication';
|
7
|
+
import type {GetState} from './reducers';
|
7
8
|
|
8
9
|
export const nop = (result: any) => result;
|
9
10
|
|
@@ -24,7 +25,7 @@ const isAxiosResponse = (response: any): response is AxiosResponse =>
|
|
24
25
|
type CreateApiRequestParams<Actions, Response, HandledResponse> = {
|
25
26
|
actions: Actions;
|
26
27
|
request: Promise<Response>;
|
27
|
-
dataHandler?: (data: Response, getState
|
28
|
+
dataHandler?: (data: Response, getState: GetState) => HandledResponse;
|
28
29
|
};
|
29
30
|
|
30
31
|
export function createApiRequest<
|
@@ -36,7 +37,7 @@ export function createApiRequest<
|
|
36
37
|
request,
|
37
38
|
dataHandler = nop,
|
38
39
|
}: CreateApiRequestParams<Actions, Response, HandledResponse>) {
|
39
|
-
const doRequest = async function (dispatch: Dispatch, getState:
|
40
|
+
const doRequest = async function (dispatch: Dispatch, getState: GetState) {
|
40
41
|
dispatch({
|
41
42
|
type: actions.REQUEST,
|
42
43
|
});
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
* endpoint: /viewer/json/acl
|
3
|
+
*
|
4
|
+
* source: https://github.com/ydb-platform/ydb/blob/main/ydb/core/viewer/protos/viewer.proto
|
5
|
+
*
|
6
|
+
* incomplete, only fields that present for ACL requests
|
7
|
+
*/
|
8
|
+
export interface TMetaInfo {
|
9
|
+
Common: TMetaCommonInfo;
|
10
|
+
}
|
11
|
+
|
12
|
+
/** incomplete */
|
13
|
+
export interface TMetaCommonInfo {
|
14
|
+
Path: string;
|
15
|
+
Owner?: string;
|
16
|
+
ACL?: TACE[];
|
17
|
+
}
|
18
|
+
|
19
|
+
interface TACE {
|
20
|
+
AccessType: string;
|
21
|
+
AccessRights?: string[];
|
22
|
+
Subject: string;
|
23
|
+
InheritanceType?: string[];
|
24
|
+
AccessRule: string;
|
25
|
+
}
|
@@ -2,9 +2,11 @@ import {EFlag} from './enums';
|
|
2
2
|
import {TEndpoint, TLegacyNodeLocation, TPoolStats} from './nodes';
|
3
3
|
import {TMetrics} from './tenant';
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
/**
|
6
|
+
* endpoint: viewer/json/compute
|
7
|
+
*
|
8
|
+
* source: https://github.com/ydb-platform/ydb/blob/main/ydb/core/viewer/protos/viewer.proto
|
9
|
+
*/
|
8
10
|
export interface TComputeInfo {
|
9
11
|
Overall: EFlag;
|
10
12
|
Tenants?: TComputeTenantInfo[];
|