ydb-embedded-ui 4.10.1 → 4.11.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/components/QueryResultTable/Cell/Cell.tsx +8 -8
  3. package/dist/components/QueryResultTable/i18n/en.json +1 -1
  4. package/dist/components/QueryResultTable/i18n/ru.json +1 -1
  5. package/dist/components/ShortyString/ShortyString.tsx +3 -6
  6. package/dist/components/ShortyString/i18n/en.json +8 -8
  7. package/dist/components/ShortyString/i18n/ru.json +8 -8
  8. package/dist/components/SpeedMultiMeter/i18n/index.ts +0 -2
  9. package/dist/components/Stack/Stack.tsx +16 -16
  10. package/dist/components/TableSkeleton/TableSkeleton.tsx +3 -3
  11. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +7 -3
  12. package/dist/containers/Header/Header.tsx +2 -2
  13. package/dist/containers/Header/breadcrumbs.ts +2 -1
  14. package/dist/containers/Heatmap/Heatmap.tsx +4 -3
  15. package/dist/containers/Node/NodeStructure/PDiskTitleBadge.tsx +2 -8
  16. package/dist/containers/Nodes/Nodes.tsx +1 -1
  17. package/dist/containers/Storage/EmptyFilter/i18n/en.json +2 -2
  18. package/dist/containers/Storage/EmptyFilter/i18n/ru.json +2 -2
  19. package/dist/containers/Storage/StorageGroups/i18n/en.json +5 -5
  20. package/dist/containers/Storage/StorageGroups/i18n/ru.json +5 -5
  21. package/dist/containers/Storage/UsageFilter/i18n/en.json +3 -8
  22. package/dist/containers/Storage/UsageFilter/i18n/ru.json +3 -8
  23. package/dist/containers/Tablet/Tablet.tsx +2 -2
  24. package/dist/containers/Tenant/Acl/Acl.scss +1 -9
  25. package/dist/containers/Tenant/Acl/Acl.tsx +137 -0
  26. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -2
  27. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -0
  28. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +3 -3
  29. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +2 -0
  30. package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +2 -3
  31. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +0 -6
  32. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +95 -83
  33. package/dist/containers/Tenant/Query/Issues/Issues.tsx +27 -23
  34. package/dist/containers/Tenant/Query/Issues/models.ts +0 -11
  35. package/dist/containers/Tenant/Query/Preview/Preview.tsx +3 -3
  36. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +2 -2
  37. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx +99 -0
  38. package/dist/containers/Tenant/Tenant.tsx +1 -5
  39. package/dist/containers/Tenant/TenantPages.tsx +9 -14
  40. package/dist/containers/Tenant/i18n/en.json +11 -0
  41. package/dist/containers/Tenant/i18n/index.ts +11 -0
  42. package/dist/containers/Tenant/i18n/ru.json +11 -0
  43. package/dist/containers/Tenant/utils/schema.ts +24 -0
  44. package/dist/containers/Tenant/utils/schemaActions.ts +28 -24
  45. package/dist/containers/Tenants/Tenants.tsx +1 -4
  46. package/dist/services/api.ts +6 -7
  47. package/dist/store/index.js +1 -1
  48. package/dist/store/reducers/nodes/nodes.ts +14 -5
  49. package/dist/store/reducers/nodes/types.ts +22 -3
  50. package/dist/store/reducers/nodes/utils.ts +23 -10
  51. package/dist/store/reducers/preview.ts +6 -4
  52. package/dist/store/reducers/schemaAcl/schemaAcl.ts +17 -0
  53. package/dist/store/reducers/schemaAcl/types.ts +9 -7
  54. package/dist/store/reducers/tenant/constants.ts +6 -0
  55. package/dist/store/reducers/tenant/tenant.ts +15 -0
  56. package/dist/store/reducers/tenant/types.ts +18 -3
  57. package/dist/store/state-url-mapping.js +3 -0
  58. package/dist/types/api/cluster.ts +1 -1
  59. package/dist/types/api/compute.ts +11 -11
  60. package/dist/types/api/error.ts +2 -2
  61. package/dist/types/api/netInfo.ts +3 -3
  62. package/dist/types/api/nodes.ts +9 -8
  63. package/dist/types/api/query.ts +1 -1
  64. package/dist/types/api/schema/schema.ts +3 -0
  65. package/dist/types/api/schema/shared.ts +3 -3
  66. package/dist/types/api/schema/table.ts +22 -22
  67. package/dist/types/api/storage.ts +1 -1
  68. package/dist/types/assets.d.ts +1 -2
  69. package/dist/types/store/executeQuery.ts +2 -3
  70. package/dist/types/store/executeTopQueries.ts +8 -5
  71. package/dist/types/store/explainQuery.ts +4 -4
  72. package/dist/types/store/query.ts +4 -3
  73. package/dist/types/store/shardsWorkload.ts +8 -5
  74. package/dist/utils/constants.ts +4 -1
  75. package/dist/utils/error.ts +2 -3
  76. package/dist/utils/query.ts +3 -9
  77. package/dist/utils/tests/providers.tsx +6 -9
  78. package/package.json +6 -2
  79. package/dist/containers/Tenant/Acl/Acl.js +0 -153
  80. 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 enum TenantInfoTabsIds {
4
- overview = 'overview',
5
- acl = 'acl',
6
- schema = 'schema',
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: TenantInfoTabsIds.overview,
12
+ id: TENANT_SUMMARY_TABS_IDS.overview,
18
13
  title: 'Overview',
19
14
  },
20
15
  {
21
- id: TenantInfoTabsIds.acl,
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: TenantInfoTabsIds.schema,
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
- navigator.clipboard
55
- .writeText(path)
56
- .then(() => {
57
- createToast({
58
- name: 'Copied',
59
- title: 'The path is copied to the clipboard',
60
- type: 'success',
61
- });
62
- })
63
- .catch(() => {
64
- createToast({
65
- name: 'Not copied',
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
- [{text: 'Open preview', action: actions.openPreview}, copyItem],
94
+ [openPreview, copyItem],
94
95
  [
95
96
  {text: 'Alter table...', action: actions.alterTable},
96
- {text: 'Select query...', action: actions.selectQuery},
97
+ selectQuery,
97
98
  {text: 'Upsert query...', action: actions.upsertQuery},
98
99
  ],
99
100
  ];
100
101
 
101
- const JUST_COPY: ActionsSet = [copyItem];
102
+ const EXTERNAL_TABLE_SET = [[openPreview, copyItem], [selectQuery]];
102
103
 
103
- const EMPTY_SET: ActionsSet = [];
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: EMPTY_SET,
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 {TenantTabsGroups, TENANT_INFO_TABS, getTenantPath} from '../Tenant/TenantPages';
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)}
@@ -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
- {tenant, visibleEntities, storage, type = 'any', tablets = true}: NodesApiRequestParams,
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(path: string) {
103
- return this.get<TComputeInfo>(this.getPath('/viewer/json/compute?enums=true'), {path});
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|${path}`},
191
+ {concurrentId: `getSchemaAcl`},
193
192
  );
194
193
  }
195
194
  getHeatmapData({path}: {path: string}) {
@@ -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 "./reducers"
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 {NodesAction, NodesApiRequestParams, NodesState} from './types';
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({tenant, visibleEntities, type = 'any'}: NodesApiRequestParams) {
89
+ export function getNodes({type = 'any', ...params}: NodesApiRequestParams) {
84
90
  return createApiRequest({
85
- request: window.api.getNodes({tenant, visibleEntities, type}),
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(path: string) {
100
+ export function getComputeNodes({version = EVersion.v2, ...params}: ComputeApiRequestParams) {
92
101
  return createApiRequest({
93
- request: window.api.getCompute(path),
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 {TTabletStateInfo as TComputeTabletStateInfo} from '../../../types/api/compute';
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
- export interface NodesApiRequestParams {
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
- if (data.Tenants) {
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) ?? preparedNodes.length,
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 {ErrorResponse, ExecuteActions} from '../../types/api/query';
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: ApiRequestAction<typeof SEND_QUERY, IQueryResult, ErrorResponse> | ReturnType<typeof setQueryOptions>,
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 = ApiRequestAction<typeof FETCH_SCHEMA_ACL, TMetaInfo, IResponseError>;
15
+ export type SchemaAclAction =
16
+ | ApiRequestAction<typeof FETCH_SCHEMA_ACL, TMetaInfo, IResponseError>
17
+ | ReturnType<typeof setAclWasNotLoaded>;
@@ -25,3 +25,9 @@ export const TENANT_DIAGNOSTICS_TABS_IDS = {
25
25
  consumers: 'consumers',
26
26
  partitions: 'partitions',
27
27
  } as const;
28
+
29
+ export const TENANT_SUMMARY_TABS_IDS = {
30
+ overview: 'overview',
31
+ acl: 'acl',
32
+ schema: 'schema',
33
+ } as const;