ydb-embedded-ui 4.10.1 → 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
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;