ydb-embedded-ui 4.10.1 → 4.11.1
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +24 -0
- package/dist/components/QueryResultTable/Cell/Cell.tsx +8 -8
- package/dist/components/QueryResultTable/i18n/en.json +1 -1
- package/dist/components/QueryResultTable/i18n/ru.json +1 -1
- package/dist/components/ShortyString/ShortyString.tsx +3 -6
- package/dist/components/ShortyString/i18n/en.json +8 -8
- package/dist/components/ShortyString/i18n/ru.json +8 -8
- package/dist/components/SpeedMultiMeter/i18n/index.ts +0 -2
- package/dist/components/Stack/Stack.tsx +16 -16
- package/dist/components/TableSkeleton/TableSkeleton.tsx +3 -3
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +7 -3
- package/dist/containers/Header/Header.tsx +2 -2
- package/dist/containers/Header/breadcrumbs.ts +2 -1
- package/dist/containers/Heatmap/Heatmap.tsx +4 -3
- package/dist/containers/Node/NodeStructure/PDiskTitleBadge.tsx +2 -8
- package/dist/containers/Nodes/Nodes.tsx +1 -1
- package/dist/containers/Storage/EmptyFilter/i18n/en.json +2 -2
- package/dist/containers/Storage/EmptyFilter/i18n/ru.json +2 -2
- package/dist/containers/Storage/StorageGroups/i18n/en.json +5 -5
- package/dist/containers/Storage/StorageGroups/i18n/ru.json +5 -5
- package/dist/containers/Storage/UsageFilter/i18n/en.json +3 -8
- package/dist/containers/Storage/UsageFilter/i18n/ru.json +3 -8
- package/dist/containers/Tablet/Tablet.tsx +2 -2
- package/dist/containers/Tenant/Acl/Acl.scss +1 -9
- package/dist/containers/Tenant/Acl/Acl.tsx +137 -0
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -0
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +3 -3
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +2 -0
- package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +2 -3
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +0 -6
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +95 -83
- package/dist/containers/Tenant/Query/Issues/Issues.tsx +27 -23
- package/dist/containers/Tenant/Query/Issues/models.ts +0 -11
- package/dist/containers/Tenant/Query/Preview/Preview.tsx +3 -3
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +2 -2
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx +99 -0
- package/dist/containers/Tenant/Tenant.tsx +1 -5
- package/dist/containers/Tenant/TenantPages.tsx +9 -14
- package/dist/containers/Tenant/i18n/en.json +11 -0
- package/dist/containers/Tenant/i18n/index.ts +11 -0
- package/dist/containers/Tenant/i18n/ru.json +11 -0
- package/dist/containers/Tenant/utils/schema.ts +24 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +28 -24
- package/dist/containers/Tenants/Tenants.tsx +1 -4
- package/dist/services/api.ts +6 -7
- package/dist/store/index.js +1 -1
- package/dist/store/reducers/nodes/nodes.ts +14 -5
- package/dist/store/reducers/nodes/types.ts +22 -3
- package/dist/store/reducers/nodes/utils.ts +23 -10
- package/dist/store/reducers/preview.ts +6 -4
- package/dist/store/reducers/schemaAcl/schemaAcl.ts +17 -0
- package/dist/store/reducers/schemaAcl/types.ts +9 -7
- package/dist/store/reducers/tenant/constants.ts +6 -0
- package/dist/store/reducers/tenant/tenant.ts +15 -0
- package/dist/store/reducers/tenant/types.ts +18 -3
- package/dist/store/state-url-mapping.js +3 -0
- package/dist/types/api/cluster.ts +1 -1
- package/dist/types/api/compute.ts +11 -11
- package/dist/types/api/error.ts +2 -2
- package/dist/types/api/netInfo.ts +3 -3
- package/dist/types/api/nodes.ts +9 -8
- package/dist/types/api/query.ts +1 -1
- package/dist/types/api/schema/schema.ts +3 -0
- package/dist/types/api/schema/shared.ts +3 -3
- package/dist/types/api/schema/table.ts +22 -22
- package/dist/types/api/storage.ts +1 -1
- package/dist/types/assets.d.ts +1 -2
- package/dist/types/store/executeQuery.ts +2 -3
- package/dist/types/store/executeTopQueries.ts +8 -5
- package/dist/types/store/explainQuery.ts +4 -4
- package/dist/types/store/query.ts +4 -3
- package/dist/types/store/shardsWorkload.ts +8 -5
- package/dist/utils/constants.ts +4 -1
- package/dist/utils/error.ts +2 -3
- package/dist/utils/query.ts +3 -9
- package/dist/utils/tests/providers.tsx +6 -9
- package/package.json +6 -2
- package/dist/containers/Tenant/Acl/Acl.js +0 -153
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +0 -94
@@ -10,12 +10,11 @@ import {DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY} from '../.
|
|
10
10
|
import {useTypedSelector} from '../../utils/hooks';
|
11
11
|
import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
|
12
12
|
import {disableAutorefresh, getSchema} from '../../store/reducers/schema/schema';
|
13
|
-
import {getSchemaAcl} from '../../store/reducers/schemaAcl/schemaAcl';
|
14
13
|
|
15
14
|
import SplitPane from '../../components/SplitPane';
|
16
15
|
import {AccessDenied} from '../../components/Errors/403';
|
17
16
|
|
18
|
-
import ObjectSummary from './ObjectSummary/ObjectSummary';
|
17
|
+
import {ObjectSummary} from './ObjectSummary/ObjectSummary';
|
19
18
|
import ObjectGeneral from './ObjectGeneral/ObjectGeneral';
|
20
19
|
|
21
20
|
import {
|
@@ -74,12 +73,10 @@ function Tenant(props: TenantProps) {
|
|
74
73
|
|
75
74
|
useEffect(() => {
|
76
75
|
dispatch(getSchema({path: tenantName}));
|
77
|
-
dispatch(getSchemaAcl({path: tenantName}));
|
78
76
|
}, [tenantName, dispatch]);
|
79
77
|
|
80
78
|
useEffect(() => {
|
81
79
|
dispatch(getSchema({path: currentSchemaPath}));
|
82
|
-
dispatch(getSchemaAcl({path: currentSchemaPath}));
|
83
80
|
}, [currentSchemaPath, dispatch]);
|
84
81
|
|
85
82
|
useEffect(() => {
|
@@ -124,7 +121,6 @@ function Tenant(props: TenantProps) {
|
|
124
121
|
onCollapseSummary={onCollapseSummaryHandler}
|
125
122
|
onExpandSummary={onExpandSummaryHandler}
|
126
123
|
isCollapsed={summaryVisibilityState.collapsed}
|
127
|
-
additionalTenantInfo={props.additionalTenantInfo}
|
128
124
|
/>
|
129
125
|
<ObjectGeneral
|
130
126
|
type={preloadedPathType || currentPathType}
|
@@ -1,31 +1,26 @@
|
|
1
1
|
import routes, {createHref} from '../../routes';
|
2
|
+
import {TENANT_SUMMARY_TABS_IDS} from '../../store/reducers/tenant/constants';
|
2
3
|
|
3
|
-
export
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
}
|
8
|
-
|
9
|
-
export enum TenantTabsGroups {
|
10
|
-
info = 'info',
|
11
|
-
queryTab = 'queryTab',
|
12
|
-
diagnosticsTab = 'diagnosticsTab',
|
13
|
-
}
|
4
|
+
export const TenantTabsGroups = {
|
5
|
+
summaryTab: 'summaryTab',
|
6
|
+
queryTab: 'queryTab',
|
7
|
+
diagnosticsTab: 'diagnosticsTab',
|
8
|
+
} as const;
|
14
9
|
|
15
10
|
export const TENANT_INFO_TABS = [
|
16
11
|
{
|
17
|
-
id:
|
12
|
+
id: TENANT_SUMMARY_TABS_IDS.overview,
|
18
13
|
title: 'Overview',
|
19
14
|
},
|
20
15
|
{
|
21
|
-
id:
|
16
|
+
id: TENANT_SUMMARY_TABS_IDS.acl,
|
22
17
|
title: 'ACL',
|
23
18
|
},
|
24
19
|
];
|
25
20
|
|
26
21
|
export const TENANT_SCHEMA_TAB = [
|
27
22
|
{
|
28
|
-
id:
|
23
|
+
id: TENANT_SUMMARY_TABS_IDS.schema,
|
29
24
|
title: 'Schema',
|
30
25
|
},
|
31
26
|
];
|
@@ -0,0 +1,11 @@
|
|
1
|
+
{
|
2
|
+
"acl.owner": "Owner",
|
3
|
+
"acl.empty": "No Acl data",
|
4
|
+
|
5
|
+
"summary.navigation": "Navigation",
|
6
|
+
"summary.showPreview": "Show preview",
|
7
|
+
"summary.copySchemaPath": "Copy schema path",
|
8
|
+
|
9
|
+
"actions.copied" : "The path is copied to the clipboard",
|
10
|
+
"actions.notCopied" : "Couldn’t copy the path"
|
11
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import {i18n, Lang} from '../../../utils/i18n';
|
2
|
+
|
3
|
+
import en from './en.json';
|
4
|
+
import ru from './ru.json';
|
5
|
+
|
6
|
+
const COMPONENT = 'ydb-tenant';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|
@@ -0,0 +1,11 @@
|
|
1
|
+
{
|
2
|
+
"acl.owner": "Владелец",
|
3
|
+
"acl.empty": "Нет данных об Acl",
|
4
|
+
|
5
|
+
"summary.navigation": "Навигация",
|
6
|
+
"summary.showPreview": "Показать превью",
|
7
|
+
"summary.copySchemaPath": "Скопировать путь",
|
8
|
+
|
9
|
+
"actions.copied": "Путь успешно скопирован",
|
10
|
+
"actions.notCopied": "Не получилось скопировать путь"
|
11
|
+
}
|
@@ -32,6 +32,9 @@ const pathTypeToNodeType: Record<EPathType, NavigationTreeNodeType | undefined>
|
|
32
32
|
|
33
33
|
[EPathType.EPathTypeCdcStream]: 'topic',
|
34
34
|
[EPathType.EPathTypePersQueueGroup]: 'topic',
|
35
|
+
|
36
|
+
[EPathType.EPathTypeExternalDataSource]: 'external_data_source',
|
37
|
+
[EPathType.EPathTypeExternalTable]: 'external_table',
|
35
38
|
};
|
36
39
|
|
37
40
|
export const mapPathTypeToNavigationTreeType = (
|
@@ -64,6 +67,8 @@ const pathTypeToEntityName: Record<EPathType, string | undefined> = {
|
|
64
67
|
[EPathType.EPathTypeColumnTable]: 'Columntable',
|
65
68
|
[EPathType.EPathTypeCdcStream]: 'Changefeed',
|
66
69
|
[EPathType.EPathTypePersQueueGroup]: 'Topic',
|
70
|
+
[EPathType.EPathTypeExternalDataSource]: 'External Data Source',
|
71
|
+
[EPathType.EPathTypeExternalTable]: 'External Table',
|
67
72
|
};
|
68
73
|
|
69
74
|
export const mapPathTypeToEntityName = (
|
@@ -90,6 +95,8 @@ const pathTypeToIsTable: Record<EPathType, boolean> = {
|
|
90
95
|
[EPathType.EPathTypeTable]: true,
|
91
96
|
[EPathType.EPathTypeColumnTable]: true,
|
92
97
|
|
98
|
+
[EPathType.EPathTypeExternalTable]: true,
|
99
|
+
|
93
100
|
[EPathType.EPathTypeInvalid]: false,
|
94
101
|
[EPathType.EPathTypeDir]: false,
|
95
102
|
[EPathType.EPathTypeSubDomain]: false,
|
@@ -98,6 +105,7 @@ const pathTypeToIsTable: Record<EPathType, boolean> = {
|
|
98
105
|
[EPathType.EPathTypeColumnStore]: false,
|
99
106
|
[EPathType.EPathTypeCdcStream]: false,
|
100
107
|
[EPathType.EPathTypePersQueueGroup]: false,
|
108
|
+
[EPathType.EPathTypeExternalDataSource]: false,
|
101
109
|
};
|
102
110
|
|
103
111
|
export const isTableType = (pathType?: EPathType) =>
|
@@ -130,6 +138,8 @@ const pathTypeToIsColumn: Record<EPathType, boolean> = {
|
|
130
138
|
[EPathType.EPathTypeExtSubDomain]: false,
|
131
139
|
[EPathType.EPathTypeCdcStream]: false,
|
132
140
|
[EPathType.EPathTypePersQueueGroup]: false,
|
141
|
+
[EPathType.EPathTypeExternalDataSource]: false,
|
142
|
+
[EPathType.EPathTypeExternalTable]: false,
|
133
143
|
};
|
134
144
|
|
135
145
|
export const isColumnEntityType = (type?: EPathType) => (type && pathTypeToIsColumn[type]) ?? false;
|
@@ -148,6 +158,8 @@ const pathTypeToIsDatabase: Record<EPathType, boolean> = {
|
|
148
158
|
[EPathType.EPathTypeTableIndex]: false,
|
149
159
|
[EPathType.EPathTypeCdcStream]: false,
|
150
160
|
[EPathType.EPathTypePersQueueGroup]: false,
|
161
|
+
[EPathType.EPathTypeExternalDataSource]: false,
|
162
|
+
[EPathType.EPathTypeExternalTable]: false,
|
151
163
|
};
|
152
164
|
|
153
165
|
export const isDatabaseEntityType = (type?: EPathType) =>
|
@@ -171,6 +183,8 @@ const pathTypeToEntityWithMergedImplementation: Record<EPathType, boolean> = {
|
|
171
183
|
[EPathType.EPathTypeSubDomain]: false,
|
172
184
|
[EPathType.EPathTypeTableIndex]: false,
|
173
185
|
[EPathType.EPathTypeExtSubDomain]: false,
|
186
|
+
[EPathType.EPathTypeExternalDataSource]: false,
|
187
|
+
[EPathType.EPathTypeExternalTable]: false,
|
174
188
|
};
|
175
189
|
|
176
190
|
export const isEntityWithMergedImplementation = (type?: EPathType) =>
|
@@ -190,6 +204,9 @@ const pathTypeToChildless: Record<EPathType, boolean> = {
|
|
190
204
|
[EPathType.EPathTypeCdcStream]: true,
|
191
205
|
[EPathType.EPathTypePersQueueGroup]: true,
|
192
206
|
|
207
|
+
[EPathType.EPathTypeExternalDataSource]: true,
|
208
|
+
[EPathType.EPathTypeExternalTable]: true,
|
209
|
+
|
193
210
|
[EPathType.EPathTypeInvalid]: false,
|
194
211
|
[EPathType.EPathTypeColumnStore]: false,
|
195
212
|
[EPathType.EPathTypeColumnTable]: false,
|
@@ -217,7 +234,14 @@ const mapPathTypeToIsWithTopic: Record<EPathType, boolean> = {
|
|
217
234
|
[EPathType.EPathTypeSubDomain]: false,
|
218
235
|
[EPathType.EPathTypeTableIndex]: false,
|
219
236
|
[EPathType.EPathTypeExtSubDomain]: false,
|
237
|
+
|
238
|
+
[EPathType.EPathTypeExternalDataSource]: false,
|
239
|
+
[EPathType.EPathTypeExternalTable]: false,
|
220
240
|
};
|
221
241
|
|
222
242
|
export const isPathTypeWithTopic = (type?: EPathType) =>
|
223
243
|
(type && mapPathTypeToIsWithTopic[type]) ?? false;
|
244
|
+
|
245
|
+
// ====================
|
246
|
+
|
247
|
+
export const isExternalTable = (type?: EPathType) => type === EPathType.EPathTypeExternalTable;
|
@@ -1,15 +1,16 @@
|
|
1
1
|
import {Dispatch} from 'react';
|
2
|
+
import copy from 'copy-to-clipboard';
|
3
|
+
|
2
4
|
import type {NavigationTreeNodeType, NavigationTreeProps} from 'ydb-ui-components';
|
3
5
|
|
4
6
|
import {changeUserInput} from '../../../store/reducers/executeQuery';
|
5
7
|
import {setShowPreview} from '../../../store/reducers/schema/schema';
|
6
8
|
import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
|
7
|
-
import {
|
8
|
-
TENANT_QUERY_TABS_ID,
|
9
|
-
TENANT_PAGES_IDS,
|
10
|
-
} from '../../../store/reducers/tenant/constants';
|
9
|
+
import {TENANT_QUERY_TABS_ID, TENANT_PAGES_IDS} from '../../../store/reducers/tenant/constants';
|
11
10
|
import createToast from '../../../utils/createToast';
|
12
11
|
|
12
|
+
import i18n from '../i18n';
|
13
|
+
|
13
14
|
const createTableTemplate = (path: string) => {
|
14
15
|
return `CREATE TABLE \`${path}/my_table\`
|
15
16
|
(
|
@@ -51,22 +52,20 @@ const bindActions = (
|
|
51
52
|
selectQuery: inputQuery(selectQueryTemplate),
|
52
53
|
upsertQuery: inputQuery(upsertQueryTemplate),
|
53
54
|
copyPath: () => {
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
title: 'Couldn’t copy the path',
|
67
|
-
type: 'error',
|
68
|
-
});
|
55
|
+
try {
|
56
|
+
copy(path);
|
57
|
+
createToast({
|
58
|
+
name: 'Copied',
|
59
|
+
title: i18n('actions.copied'),
|
60
|
+
type: 'success',
|
61
|
+
});
|
62
|
+
} catch {
|
63
|
+
createToast({
|
64
|
+
name: 'Not copied',
|
65
|
+
title: i18n('actions.notCopied'),
|
66
|
+
type: 'error',
|
69
67
|
});
|
68
|
+
}
|
70
69
|
},
|
71
70
|
openPreview: () => {
|
72
71
|
dispatch(setShowPreview(true));
|
@@ -84,23 +83,25 @@ export const getActions =
|
|
84
83
|
(path: string, type: NavigationTreeNodeType) => {
|
85
84
|
const actions = bindActions(path, dispatch, setActivePath);
|
86
85
|
const copyItem = {text: 'Copy path', action: actions.copyPath};
|
86
|
+
const openPreview = {text: 'Open preview', action: actions.openPreview};
|
87
|
+
const selectQuery = {text: 'Select query...', action: actions.selectQuery};
|
87
88
|
|
88
89
|
const DIR_SET: ActionsSet = [
|
89
90
|
[copyItem],
|
90
91
|
[{text: 'Create table...', action: actions.createTable}],
|
91
92
|
];
|
92
93
|
const TABLE_SET: ActionsSet = [
|
93
|
-
[
|
94
|
+
[openPreview, copyItem],
|
94
95
|
[
|
95
96
|
{text: 'Alter table...', action: actions.alterTable},
|
96
|
-
|
97
|
+
selectQuery,
|
97
98
|
{text: 'Upsert query...', action: actions.upsertQuery},
|
98
99
|
],
|
99
100
|
];
|
100
101
|
|
101
|
-
const
|
102
|
+
const EXTERNAL_TABLE_SET = [[openPreview, copyItem], [selectQuery]];
|
102
103
|
|
103
|
-
const
|
104
|
+
const JUST_COPY: ActionsSet = [copyItem];
|
104
105
|
|
105
106
|
// verbose mapping to guarantee a correct actions set for new node types
|
106
107
|
// TS will error when a new type is added in the lib but is not mapped here
|
@@ -114,7 +115,10 @@ export const getActions =
|
|
114
115
|
index_table: JUST_COPY,
|
115
116
|
topic: JUST_COPY,
|
116
117
|
|
117
|
-
index:
|
118
|
+
index: JUST_COPY,
|
119
|
+
|
120
|
+
external_table: EXTERNAL_TABLE_SET,
|
121
|
+
external_data_source: JUST_COPY,
|
118
122
|
};
|
119
123
|
|
120
124
|
return nodeTypeToActions[type];
|
@@ -31,7 +31,7 @@ import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
|
|
31
31
|
import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
|
32
32
|
import {clusterName} from '../../store';
|
33
33
|
|
34
|
-
import {
|
34
|
+
import {getTenantPath} from '../Tenant/TenantPages';
|
35
35
|
|
36
36
|
import './Tenants.scss';
|
37
37
|
|
@@ -80,8 +80,6 @@ export const Tenants = ({additionalTenantsProps}: TenantsProps) => {
|
|
80
80
|
};
|
81
81
|
|
82
82
|
const renderTable = () => {
|
83
|
-
const initialTenantInfoTab = TENANT_INFO_TABS[0].id;
|
84
|
-
|
85
83
|
const getTenantBackend = (tenant: PreparedTenant) => {
|
86
84
|
const backend = tenant.MonitoringEndpoint ?? tenant.backend;
|
87
85
|
return additionalTenantsProps?.prepareTenantBackend?.(backend);
|
@@ -106,7 +104,6 @@ export const Tenants = ({additionalTenantsProps}: TenantsProps) => {
|
|
106
104
|
path={getTenantPath({
|
107
105
|
name: row.Name,
|
108
106
|
backend,
|
109
|
-
[TenantTabsGroups.info]: initialTenantInfoTab,
|
110
107
|
})}
|
111
108
|
/>
|
112
109
|
{additionalTenantsProps?.getMonitoringLink?.(row.Name, row.Type)}
|
package/dist/services/api.ts
CHANGED
@@ -28,7 +28,7 @@ import type {DescribeTopicResult} from '../types/api/topic';
|
|
28
28
|
import type {TEvPDiskStateResponse} from '../types/api/pdisk';
|
29
29
|
import type {TEvVDiskStateResponse} from '../types/api/vdisk';
|
30
30
|
import type {TUserToken} from '../types/api/whoami';
|
31
|
-
import type {NodesApiRequestParams} from '../store/reducers/nodes/types';
|
31
|
+
import type {ComputeApiRequestParams, NodesApiRequestParams} from '../store/reducers/nodes/types';
|
32
32
|
import type {StorageApiRequestParams} from '../store/reducers/storage/types';
|
33
33
|
|
34
34
|
import {backend as BACKEND} from '../store';
|
@@ -82,25 +82,24 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
82
82
|
});
|
83
83
|
}
|
84
84
|
getNodes(
|
85
|
-
{
|
85
|
+
{visibleEntities, type = 'any', tablets = true, ...params}: NodesApiRequestParams,
|
86
86
|
{concurrentId}: AxiosOptions = {},
|
87
87
|
) {
|
88
88
|
return this.get<TNodesInfo>(
|
89
89
|
this.getPath('/viewer/json/nodes?enums=true'),
|
90
90
|
{
|
91
|
-
tenant,
|
92
91
|
with: visibleEntities,
|
93
|
-
storage,
|
94
92
|
type,
|
95
93
|
tablets,
|
94
|
+
...params,
|
96
95
|
},
|
97
96
|
{
|
98
97
|
concurrentId,
|
99
98
|
},
|
100
99
|
);
|
101
100
|
}
|
102
|
-
getCompute(
|
103
|
-
return this.get<TComputeInfo>(this.getPath('/viewer/json/compute?enums=true'),
|
101
|
+
getCompute(params: ComputeApiRequestParams) {
|
102
|
+
return this.get<TComputeInfo>(this.getPath('/viewer/json/compute?enums=true'), params);
|
104
103
|
}
|
105
104
|
getStorageInfo(
|
106
105
|
{tenant, visibleEntities, nodeId}: StorageApiRequestParams,
|
@@ -189,7 +188,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
189
188
|
{
|
190
189
|
path,
|
191
190
|
},
|
192
|
-
{concurrentId: `getSchemaAcl
|
191
|
+
{concurrentId: `getSchemaAcl`},
|
193
192
|
);
|
194
193
|
}
|
195
194
|
getHeatmapData({path}: {path: string}) {
|
package/dist/store/index.js
CHANGED
@@ -32,6 +32,6 @@ function configureStore(aRootReducer = rootReducer, singleClusterMode = true) {
|
|
32
32
|
export const webVersion = window.web_version;
|
33
33
|
export const customBackend = window.custom_backend;
|
34
34
|
|
35
|
-
export * from
|
35
|
+
export * from './reducers';
|
36
36
|
|
37
37
|
export default configureStore;
|
@@ -2,10 +2,16 @@ import type {Reducer} from 'redux';
|
|
2
2
|
|
3
3
|
import '../../../services/api';
|
4
4
|
import {NodesUptimeFilterValues} from '../../../utils/nodes';
|
5
|
+
import {EVersion} from '../../../types/api/compute';
|
5
6
|
|
6
7
|
import {createRequestActionTypes, createApiRequest} from '../../utils';
|
7
8
|
|
8
|
-
import type {
|
9
|
+
import type {
|
10
|
+
ComputeApiRequestParams,
|
11
|
+
NodesAction,
|
12
|
+
NodesApiRequestParams,
|
13
|
+
NodesState,
|
14
|
+
} from './types';
|
9
15
|
import {prepareComputeNodesData, prepareNodesData} from './utils';
|
10
16
|
|
11
17
|
export const FETCH_NODES = createRequestActionTypes('nodes', 'FETCH_NODES');
|
@@ -80,17 +86,20 @@ const nodes: Reducer<NodesState, NodesAction> = (state = initialState, action) =
|
|
80
86
|
}
|
81
87
|
};
|
82
88
|
|
83
|
-
export function getNodes({
|
89
|
+
export function getNodes({type = 'any', ...params}: NodesApiRequestParams) {
|
84
90
|
return createApiRequest({
|
85
|
-
request: window.api.getNodes({
|
91
|
+
request: window.api.getNodes({
|
92
|
+
type,
|
93
|
+
...params,
|
94
|
+
}),
|
86
95
|
actions: FETCH_NODES,
|
87
96
|
dataHandler: prepareNodesData,
|
88
97
|
});
|
89
98
|
}
|
90
99
|
|
91
|
-
export function getComputeNodes(
|
100
|
+
export function getComputeNodes({version = EVersion.v2, ...params}: ComputeApiRequestParams) {
|
92
101
|
return createApiRequest({
|
93
|
-
request: window.api.getCompute(
|
102
|
+
request: window.api.getCompute({version, ...params}),
|
94
103
|
actions: FETCH_NODES,
|
95
104
|
dataHandler: prepareComputeNodesData,
|
96
105
|
});
|
@@ -1,6 +1,9 @@
|
|
1
1
|
import type {IResponseError} from '../../../types/api/error';
|
2
2
|
import type {TEndpoint, TPoolStats} from '../../../types/api/nodes';
|
3
|
-
import type {
|
3
|
+
import type {
|
4
|
+
EVersion,
|
5
|
+
TTabletStateInfo as TComputeTabletStateInfo,
|
6
|
+
} from '../../../types/api/compute';
|
4
7
|
import type {TTabletStateInfo as TFullTabletStateInfo} from '../../../types/api/tablet';
|
5
8
|
import type {EFlag} from '../../../types/api/enums';
|
6
9
|
import type {ApiRequestAction} from '../../utils';
|
@@ -46,17 +49,33 @@ export interface NodesState {
|
|
46
49
|
|
47
50
|
export type NodeType = 'static' | 'dynamic' | 'any';
|
48
51
|
|
49
|
-
|
52
|
+
interface RequestParams {
|
53
|
+
filter?: string; // NodeId or Host
|
54
|
+
uptime?: number; // return nodes with less uptime in seconds
|
55
|
+
problems_only?: boolean; // return nodes with SystemState !== EFlag.Green
|
56
|
+
sort?: string; // Sort by one of ESort params (may differ for /nodes and /compute)
|
57
|
+
|
58
|
+
offser?: number;
|
59
|
+
limit?: number;
|
60
|
+
}
|
61
|
+
|
62
|
+
export interface NodesApiRequestParams extends RequestParams {
|
50
63
|
tenant?: string;
|
51
64
|
type?: NodeType;
|
52
|
-
visibleEntities?: VisibleEntities;
|
65
|
+
visibleEntities?: VisibleEntities; // "with" param
|
53
66
|
storage?: boolean;
|
54
67
|
tablets?: boolean;
|
55
68
|
}
|
56
69
|
|
70
|
+
export interface ComputeApiRequestParams extends RequestParams {
|
71
|
+
path: string;
|
72
|
+
version?: EVersion; // only v2 works with filters
|
73
|
+
}
|
74
|
+
|
57
75
|
export interface NodesHandledResponse {
|
58
76
|
Nodes?: NodesPreparedEntity[];
|
59
77
|
TotalNodes: number;
|
78
|
+
FoundNodes?: number;
|
60
79
|
}
|
61
80
|
|
62
81
|
type NodesApiRequestAction = ApiRequestAction<
|
@@ -1,28 +1,40 @@
|
|
1
|
-
import type {TComputeInfo} from '../../../types/api/compute';
|
1
|
+
import type {TComputeInfo, TComputeNodeInfo} from '../../../types/api/compute';
|
2
2
|
import type {TNodesInfo} from '../../../types/api/nodes';
|
3
3
|
import {calcUptime} from '../../../utils';
|
4
4
|
|
5
5
|
import type {NodesHandledResponse, NodesPreparedEntity} from './types';
|
6
6
|
|
7
|
+
const prepareComputeNode = (node: TComputeNodeInfo, tenantName?: string) => {
|
8
|
+
return {
|
9
|
+
...node,
|
10
|
+
// v2 response has tenant name, v1 - doesn't
|
11
|
+
TenantName: node.Tenant ?? tenantName,
|
12
|
+
SystemState: node?.Overall,
|
13
|
+
Uptime: calcUptime(node?.StartTime),
|
14
|
+
};
|
15
|
+
};
|
16
|
+
|
7
17
|
export const prepareComputeNodesData = (data: TComputeInfo): NodesHandledResponse => {
|
8
18
|
const preparedNodes: NodesPreparedEntity[] = [];
|
9
19
|
|
10
|
-
|
20
|
+
// First try to parse v2 response in case backend supports it
|
21
|
+
// Else parse v1 response
|
22
|
+
if (data.Nodes) {
|
23
|
+
data.Nodes.forEach((node) => {
|
24
|
+
preparedNodes.push(prepareComputeNode(node));
|
25
|
+
});
|
26
|
+
} else if (data.Tenants) {
|
11
27
|
for (const tenant of data.Tenants) {
|
12
28
|
tenant.Nodes?.forEach((node) => {
|
13
|
-
preparedNodes.push(
|
14
|
-
...node,
|
15
|
-
TenantName: tenant.Name,
|
16
|
-
SystemState: node?.Overall,
|
17
|
-
Uptime: calcUptime(node?.StartTime),
|
18
|
-
});
|
29
|
+
preparedNodes.push(prepareComputeNode(node, tenant.Name));
|
19
30
|
});
|
20
31
|
}
|
21
32
|
}
|
22
33
|
|
23
34
|
return {
|
24
35
|
Nodes: preparedNodes,
|
25
|
-
TotalNodes: preparedNodes.length,
|
36
|
+
TotalNodes: Number(data.TotalNodes) || preparedNodes.length,
|
37
|
+
FoundNodes: Number(data.FoundNodes),
|
26
38
|
};
|
27
39
|
};
|
28
40
|
|
@@ -41,6 +53,7 @@ export const prepareNodesData = (data: TNodesInfo): NodesHandledResponse => {
|
|
41
53
|
|
42
54
|
return {
|
43
55
|
Nodes: preparedNodes,
|
44
|
-
TotalNodes: Number(data.TotalNodes)
|
56
|
+
TotalNodes: Number(data.TotalNodes) || preparedNodes.length,
|
57
|
+
FoundNodes: Number(data.FoundNodes),
|
45
58
|
};
|
46
59
|
};
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import '../../services/api';
|
2
2
|
|
3
|
-
import type {
|
4
|
-
import type {IQueryResult} from '../../types/store/query';
|
3
|
+
import type {ExecuteActions} from '../../types/api/query';
|
4
|
+
import type {IQueryResult, QueryErrorResponse} from '../../types/store/query';
|
5
5
|
import {parseQueryAPIExecuteResponse} from '../../utils/query';
|
6
6
|
|
7
7
|
import {createRequestActionTypes, createApiRequest, ApiRequestAction} from '../utils';
|
@@ -16,7 +16,9 @@ const initialState = {
|
|
16
16
|
|
17
17
|
const preview = (
|
18
18
|
state = initialState,
|
19
|
-
action:
|
19
|
+
action:
|
20
|
+
| ApiRequestAction<typeof SEND_QUERY, IQueryResult, QueryErrorResponse>
|
21
|
+
| ReturnType<typeof setQueryOptions>,
|
20
22
|
) => {
|
21
23
|
switch (action.type) {
|
22
24
|
case SEND_QUERY.REQUEST: {
|
@@ -57,7 +59,7 @@ interface SendQueryParams {
|
|
57
59
|
query?: string;
|
58
60
|
database?: string;
|
59
61
|
action?: ExecuteActions;
|
60
|
-
}
|
62
|
+
}
|
61
63
|
|
62
64
|
export const sendQuery = ({query, database, action}: SendQueryParams) => {
|
63
65
|
return createApiRequest({
|
@@ -6,6 +6,7 @@ import {createRequestActionTypes, createApiRequest} from '../../utils';
|
|
6
6
|
import type {SchemaAclAction, SchemaAclState} from './types';
|
7
7
|
|
8
8
|
export const FETCH_SCHEMA_ACL = createRequestActionTypes('schemaAcl', 'FETCH_SCHEMA_ACL');
|
9
|
+
const SET_ACL_WAS_NOT_LOADED = 'schemaAcl/SET_DATA_WAS_NOT_LOADED';
|
9
10
|
|
10
11
|
const initialState = {
|
11
12
|
loading: false,
|
@@ -34,12 +35,22 @@ const schemaAcl: Reducer<SchemaAclState, SchemaAclAction> = (state = initialStat
|
|
34
35
|
};
|
35
36
|
}
|
36
37
|
case FETCH_SCHEMA_ACL.FAILURE: {
|
38
|
+
if (action.error?.isCancelled) {
|
39
|
+
return state;
|
40
|
+
}
|
41
|
+
|
37
42
|
return {
|
38
43
|
...state,
|
39
44
|
error: action.error,
|
40
45
|
loading: false,
|
41
46
|
};
|
42
47
|
}
|
48
|
+
case SET_ACL_WAS_NOT_LOADED: {
|
49
|
+
return {
|
50
|
+
...state,
|
51
|
+
wasLoaded: false,
|
52
|
+
};
|
53
|
+
}
|
43
54
|
default:
|
44
55
|
return state;
|
45
56
|
}
|
@@ -52,4 +63,10 @@ export function getSchemaAcl({path}: {path: string}) {
|
|
52
63
|
});
|
53
64
|
}
|
54
65
|
|
66
|
+
export const setAclWasNotLoaded = () => {
|
67
|
+
return {
|
68
|
+
type: SET_ACL_WAS_NOT_LOADED,
|
69
|
+
} as const;
|
70
|
+
};
|
71
|
+
|
55
72
|
export default schemaAcl;
|
@@ -2,14 +2,16 @@ import type {TACE, TMetaInfo} from '../../../types/api/acl';
|
|
2
2
|
import type {IResponseError} from '../../../types/api/error';
|
3
3
|
import type {ApiRequestAction} from '../../utils';
|
4
4
|
|
5
|
-
import {FETCH_SCHEMA_ACL} from './schemaAcl';
|
5
|
+
import {FETCH_SCHEMA_ACL, setAclWasNotLoaded} from './schemaAcl';
|
6
6
|
|
7
7
|
export interface SchemaAclState {
|
8
|
-
loading: boolean
|
9
|
-
wasLoaded: boolean
|
10
|
-
acl?: TACE[]
|
11
|
-
owner?: string
|
12
|
-
error?: IResponseError
|
8
|
+
loading: boolean;
|
9
|
+
wasLoaded: boolean;
|
10
|
+
acl?: TACE[];
|
11
|
+
owner?: string;
|
12
|
+
error?: IResponseError;
|
13
13
|
}
|
14
14
|
|
15
|
-
export type SchemaAclAction =
|
15
|
+
export type SchemaAclAction =
|
16
|
+
| ApiRequestAction<typeof FETCH_SCHEMA_ACL, TMetaInfo, IResponseError>
|
17
|
+
| ReturnType<typeof setAclWasNotLoaded>;
|