ydb-embedded-ui 4.0.0 → 4.2.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 +28 -0
- package/dist/components/ClusterInfo/ClusterInfo.tsx +3 -3
- package/dist/components/LabelWithPopover/LabelWithPopover.tsx +10 -4
- package/dist/{containers/Nodes/NodesTable.scss → components/NodeHostWrapper/NodeHostWrapper.scss} +4 -6
- package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +60 -0
- package/dist/components/TabletsStatistic/TabletsStatistic.scss +1 -1
- package/dist/containers/App/App.scss +7 -4
- 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/StorageGroups/StorageGroups.tsx +3 -12
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +0 -24
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +2 -39
- package/dist/containers/Storage/VDisk/VDisk.tsx +4 -11
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +13 -16
- package/dist/containers/Storage/utils/types.ts +2 -1
- package/dist/containers/Tablet/Tablet.scss +4 -0
- package/dist/containers/Tablet/TabletTable/TabletTable.tsx +28 -6
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +4 -3
- package/dist/containers/Tenant/QueryEditor/Issues/Issues.scss +1 -1
- package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +1 -1
- package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +1 -1
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +12 -0
- package/dist/containers/Tenants/Tenants.js +1 -1
- package/dist/containers/UserSettings/UserSettings.tsx +19 -17
- 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/node.js +5 -1
- package/dist/store/reducers/nodesList.ts +2 -7
- package/dist/store/reducers/settings.js +1 -14
- package/dist/store/reducers/storage.js +12 -0
- package/dist/store/reducers/tablet.ts +16 -2
- 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/store/tablet.ts +1 -0
- package/dist/types/window.d.ts +5 -0
- package/dist/utils/createToast.tsx +2 -2
- package/dist/utils/hooks/useTypedSelector.ts +2 -2
- package/dist/utils/nodes.ts +14 -1
- package/package.json +4 -4
- package/dist/services/api.d.ts +0 -87
- 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 =
|
90
|
-
|
91
|
-
|
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'
|
@@ -61,7 +61,7 @@ export const QueryEditorControls = ({
|
|
61
61
|
</Button>
|
62
62
|
<DropdownMenu
|
63
63
|
items={querySelectorMenuItems}
|
64
|
-
|
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
|
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
|
-
<
|
50
|
-
{
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
<
|
63
|
-
{
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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 {
|
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;
|
@@ -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] =
|
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
|
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;
|