ydb-embedded-ui 4.10.0 → 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/components/InfoViewer/formatters/schema.ts +3 -1
  3. package/dist/components/QueryResultTable/Cell/Cell.tsx +8 -8
  4. package/dist/components/QueryResultTable/i18n/en.json +1 -1
  5. package/dist/components/QueryResultTable/i18n/ru.json +1 -1
  6. package/dist/components/ShortyString/ShortyString.tsx +3 -6
  7. package/dist/components/ShortyString/i18n/en.json +8 -8
  8. package/dist/components/ShortyString/i18n/ru.json +8 -8
  9. package/dist/components/SpeedMultiMeter/i18n/index.ts +0 -2
  10. package/dist/components/Stack/Stack.tsx +16 -16
  11. package/dist/components/TableSkeleton/TableSkeleton.tsx +3 -3
  12. package/dist/components/TableWithControlsLayout/TableWithControlsLayout.scss +32 -0
  13. package/dist/components/TableWithControlsLayout/TableWithControlsLayout.tsx +43 -0
  14. package/dist/containers/AsideNavigation/AsideNavigation.tsx +2 -2
  15. package/dist/containers/Cluster/Cluster.scss +4 -5
  16. package/dist/containers/Cluster/Cluster.tsx +3 -22
  17. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +4 -0
  18. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +14 -3
  19. package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.tsx +1 -1
  20. package/dist/containers/Cluster/utils.tsx +0 -11
  21. package/dist/containers/Header/Header.scss +1 -5
  22. package/dist/containers/Header/Header.tsx +2 -2
  23. package/dist/containers/Header/breadcrumbs.ts +2 -1
  24. package/dist/containers/Heatmap/Heatmap.tsx +4 -3
  25. package/dist/containers/Node/NodeStructure/PDiskTitleBadge.tsx +2 -8
  26. package/dist/containers/Nodes/Nodes.scss +1 -24
  27. package/dist/containers/Nodes/Nodes.tsx +29 -39
  28. package/dist/containers/Storage/EmptyFilter/i18n/en.json +2 -2
  29. package/dist/containers/Storage/EmptyFilter/i18n/ru.json +2 -2
  30. package/dist/containers/Storage/Storage.scss +1 -14
  31. package/dist/containers/Storage/Storage.tsx +15 -18
  32. package/dist/containers/Storage/StorageGroups/i18n/en.json +5 -5
  33. package/dist/containers/Storage/StorageGroups/i18n/ru.json +5 -5
  34. package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +3 -1
  35. package/dist/containers/Storage/{StorageVisibleEntityFilter/StorageVisibleEntityFilter.tsx → StorageVisibleEntitiesFilter/StorageVisibleEntitiesFilter.tsx} +4 -2
  36. package/dist/containers/Storage/UsageFilter/i18n/en.json +3 -8
  37. package/dist/containers/Storage/UsageFilter/i18n/ru.json +3 -8
  38. package/dist/containers/Tablet/Tablet.tsx +2 -2
  39. package/dist/containers/Tenant/Acl/Acl.scss +1 -9
  40. package/dist/containers/Tenant/Acl/Acl.tsx +137 -0
  41. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -2
  42. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +6 -2
  43. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -0
  44. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +3 -3
  45. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +2 -0
  46. package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +2 -3
  47. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +3 -18
  48. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +95 -88
  49. package/dist/containers/Tenant/Query/Issues/Issues.tsx +27 -23
  50. package/dist/containers/Tenant/Query/Issues/models.ts +0 -11
  51. package/dist/containers/Tenant/Query/Preview/Preview.tsx +3 -3
  52. package/dist/containers/Tenant/Query/i18n/en.json +1 -1
  53. package/dist/containers/Tenant/Query/i18n/ru.json +1 -1
  54. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +2 -2
  55. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx +99 -0
  56. package/dist/containers/Tenant/Tenant.tsx +1 -5
  57. package/dist/containers/Tenant/TenantPages.tsx +9 -14
  58. package/dist/containers/Tenant/i18n/en.json +11 -0
  59. package/dist/containers/Tenant/i18n/index.ts +11 -0
  60. package/dist/containers/Tenant/i18n/ru.json +11 -0
  61. package/dist/containers/Tenant/utils/schema.ts +24 -0
  62. package/dist/containers/Tenant/utils/schemaActions.ts +28 -24
  63. package/dist/containers/Tenants/Tenants.scss +1 -13
  64. package/dist/containers/Tenants/Tenants.tsx +18 -28
  65. package/dist/services/api.ts +6 -7
  66. package/dist/store/index.js +1 -1
  67. package/dist/store/reducers/nodes/nodes.ts +12 -111
  68. package/dist/store/reducers/nodes/selectors.ts +74 -0
  69. package/dist/store/reducers/nodes/types.ts +22 -3
  70. package/dist/store/reducers/nodes/utils.ts +59 -0
  71. package/dist/store/reducers/preview.ts +6 -4
  72. package/dist/store/reducers/schemaAcl/schemaAcl.ts +17 -0
  73. package/dist/store/reducers/schemaAcl/types.ts +9 -7
  74. package/dist/store/reducers/storage/selectors.ts +1 -1
  75. package/dist/store/reducers/tenant/constants.ts +6 -0
  76. package/dist/store/reducers/tenant/tenant.ts +15 -0
  77. package/dist/store/reducers/tenant/types.ts +18 -3
  78. package/dist/store/state-url-mapping.js +3 -0
  79. package/dist/types/api/cluster.ts +1 -1
  80. package/dist/types/api/compute.ts +27 -2
  81. package/dist/types/api/error.ts +2 -2
  82. package/dist/types/api/netInfo.ts +3 -3
  83. package/dist/types/api/nodes.ts +13 -1
  84. package/dist/types/api/query.ts +1 -1
  85. package/dist/types/api/schema/cdcStream.ts +32 -0
  86. package/dist/types/api/schema/columnEntity.ts +138 -0
  87. package/dist/types/api/schema/externalDataSource.ts +24 -0
  88. package/dist/types/api/schema/externalTable.ts +14 -0
  89. package/dist/types/api/schema/index.ts +10 -0
  90. package/dist/types/api/schema/persQueueGroup.ts +191 -0
  91. package/dist/types/api/schema/schema.ts +302 -0
  92. package/dist/types/api/schema/shared.ts +42 -0
  93. package/dist/types/api/schema/table.ts +616 -0
  94. package/dist/types/api/schema/tableIndex.ts +33 -0
  95. package/dist/types/api/storage.ts +1 -1
  96. package/dist/types/assets.d.ts +1 -2
  97. package/dist/types/store/executeQuery.ts +2 -3
  98. package/dist/types/store/executeTopQueries.ts +8 -5
  99. package/dist/types/store/explainQuery.ts +4 -4
  100. package/dist/types/store/query.ts +4 -3
  101. package/dist/types/store/shardsWorkload.ts +8 -5
  102. package/dist/utils/constants.ts +4 -1
  103. package/dist/utils/error.ts +2 -3
  104. package/dist/utils/query.ts +3 -9
  105. package/dist/utils/tests/providers.tsx +6 -9
  106. package/package.json +6 -2
  107. package/dist/assets/icons/versions.svg +0 -3
  108. package/dist/containers/Tenant/Acl/Acl.js +0 -153
  109. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +0 -94
  110. package/dist/types/api/schema.ts +0 -1326
@@ -0,0 +1,99 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import DataTable, {Column} from '@gravity-ui/react-data-table';
4
+
5
+ import type {EPathType, TColumnDescription} from '../../../../types/api/schema';
6
+ import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
7
+
8
+ import {Icon} from '../../../../components/Icon';
9
+
10
+ import {isExternalTable} from '../../utils/schema';
11
+
12
+ import './SchemaViewer.scss';
13
+
14
+ const b = cn('schema-viewer');
15
+
16
+ const SchemaViewerColumns = {
17
+ id: 'Id',
18
+ name: 'Name',
19
+ key: 'Key',
20
+ type: 'Type',
21
+ notNull: 'NotNull',
22
+ };
23
+
24
+ interface SchemaViewerProps {
25
+ keyColumnIds?: number[];
26
+ columns?: TColumnDescription[];
27
+ type?: EPathType;
28
+ }
29
+
30
+ export const SchemaViewer = ({keyColumnIds = [], columns = [], type}: SchemaViewerProps) => {
31
+ let dataTableColumns: Column<TColumnDescription>[] = [
32
+ {
33
+ name: SchemaViewerColumns.id,
34
+ width: 40,
35
+ },
36
+ {
37
+ name: SchemaViewerColumns.key,
38
+ width: 40,
39
+ sortAccessor: (row) => {
40
+ return row.Id && keyColumnIds.includes(row.Id) ? 1 : 0;
41
+ },
42
+ render: ({row}) => {
43
+ return row.Id && keyColumnIds.includes(row.Id) ? (
44
+ <div className={b('key-icon')}>
45
+ <Icon name="key" viewBox="0 0 12 7" width={12} height={7} />
46
+ </div>
47
+ ) : null;
48
+ },
49
+ },
50
+ {
51
+ name: SchemaViewerColumns.name,
52
+ width: 100,
53
+ },
54
+ {
55
+ name: SchemaViewerColumns.type,
56
+ width: 100,
57
+ },
58
+ {
59
+ name: SchemaViewerColumns.notNull,
60
+ width: 100,
61
+ render: ({row}) => {
62
+ if (row.NotNull) {
63
+ return '\u2713';
64
+ }
65
+
66
+ return undefined;
67
+ },
68
+ },
69
+ ];
70
+
71
+ if (isExternalTable(type)) {
72
+ // External tables don't have key columns
73
+ dataTableColumns = dataTableColumns.filter(
74
+ (column) => column.name !== SchemaViewerColumns.key,
75
+ );
76
+ }
77
+
78
+ // Display key columns first
79
+ const tableData = columns.sort((column) => {
80
+ if (column.Id && keyColumnIds.includes(column.Id)) {
81
+ return 1;
82
+ }
83
+ return -1;
84
+ });
85
+
86
+ return (
87
+ <div className={b()}>
88
+ <DataTable
89
+ theme="yandex-cloud"
90
+ data={tableData}
91
+ columns={dataTableColumns}
92
+ settings={DEFAULT_TABLE_SETTINGS}
93
+ initialSortOrder={{columnId: SchemaViewerColumns.key, order: DataTable.DESCENDING}}
94
+ />
95
+ </div>
96
+ );
97
+ };
98
+
99
+ export default SchemaViewer;
@@ -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];
@@ -1,9 +1,6 @@
1
1
  @import '../../styles/mixins.scss';
2
2
 
3
3
  .tenants {
4
- height: 100%;
5
- @include flex-container();
6
-
7
4
  &__format-label {
8
5
  margin-right: 15px;
9
6
  }
@@ -28,16 +25,7 @@
28
25
  }
29
26
  }
30
27
 
31
- &__controls {
32
- @include controls();
33
- }
34
-
35
- &__table-wrapper {
36
- overflow: auto;
37
- flex-grow: 1;
38
-
39
- @include freeze-nth-column(1);
40
-
28
+ &__table {
41
29
  @include table-styles;
42
30
  }
43
31
 
@@ -2,7 +2,7 @@ import cn from 'bem-cn-lite';
2
2
  import {useDispatch} from 'react-redux';
3
3
 
4
4
  import DataTable, {Column} from '@gravity-ui/react-data-table';
5
- import {Loader, Button} from '@gravity-ui/uikit';
5
+ import {Button} from '@gravity-ui/uikit';
6
6
 
7
7
  import EntityStatus from '../../components/EntityStatus/EntityStatus';
8
8
  import {PoolsGraph} from '../../components/PoolsGraph/PoolsGraph';
@@ -10,6 +10,7 @@ import {TabletsStatistic} from '../../components/TabletsStatistic';
10
10
  import {ProblemFilter} from '../../components/ProblemFilter';
11
11
  import {Illustration} from '../../components/Illustration';
12
12
  import {Search} from '../../components/Search';
13
+ import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout';
13
14
  import {ResponseError} from '../../components/Errors/ResponseError';
14
15
 
15
16
  import type {AdditionalTenantsProps} from '../../types/additionalProps';
@@ -30,7 +31,7 @@ import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
30
31
  import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
31
32
  import {clusterName} from '../../store';
32
33
 
33
- import {TenantTabsGroups, TENANT_INFO_TABS, getTenantPath} from '../Tenant/TenantPages';
34
+ import {getTenantPath} from '../Tenant/TenantPages';
34
35
 
35
36
  import './Tenants.scss';
36
37
 
@@ -66,7 +67,7 @@ export const Tenants = ({additionalTenantsProps}: TenantsProps) => {
66
67
 
67
68
  const renderControls = () => {
68
69
  return (
69
- <div className={b('controls')}>
70
+ <>
70
71
  <Search
71
72
  value={searchValue}
72
73
  onChange={handleSearchChange}
@@ -74,13 +75,11 @@ export const Tenants = ({additionalTenantsProps}: TenantsProps) => {
74
75
  className={b('search')}
75
76
  />
76
77
  <ProblemFilter value={problemFilter} onChange={handleProblemFilterChange} />
77
- </div>
78
+ </>
78
79
  );
79
80
  };
80
81
 
81
82
  const renderTable = () => {
82
- const initialTenantInfoTab = TENANT_INFO_TABS[0].id;
83
-
84
83
  const getTenantBackend = (tenant: PreparedTenant) => {
85
84
  const backend = tenant.MonitoringEndpoint ?? tenant.backend;
86
85
  return additionalTenantsProps?.prepareTenantBackend?.(backend);
@@ -105,7 +104,6 @@ export const Tenants = ({additionalTenantsProps}: TenantsProps) => {
105
104
  path={getTenantPath({
106
105
  name: row.Name,
107
106
  backend,
108
- [TenantTabsGroups.info]: initialTenantInfoTab,
109
107
  })}
110
108
  />
111
109
  {additionalTenantsProps?.getMonitoringLink?.(row.Name, row.Type)}
@@ -236,34 +234,26 @@ export const Tenants = ({additionalTenantsProps}: TenantsProps) => {
236
234
  }
237
235
 
238
236
  return (
239
- <div className={b('table-wrapper')}>
240
- <DataTable
241
- theme="yandex-cloud"
242
- data={filteredTenants}
243
- columns={columns}
244
- settings={DEFAULT_TABLE_SETTINGS}
245
- emptyDataMessage="No such tenants"
246
- />
247
- </div>
237
+ <DataTable
238
+ theme="yandex-cloud"
239
+ data={filteredTenants}
240
+ columns={columns}
241
+ settings={DEFAULT_TABLE_SETTINGS}
242
+ emptyDataMessage="No such tenants"
243
+ />
248
244
  );
249
245
  };
250
246
 
251
- if (loading && !wasLoaded) {
252
- return (
253
- <div className={'loader'}>
254
- <Loader size="l" />
255
- </div>
256
- );
257
- }
258
-
259
247
  if (error) {
260
248
  return <ResponseError error={error} />;
261
249
  }
262
250
 
263
251
  return (
264
- <div className={b()}>
265
- {renderControls()}
266
- {renderTable()}
267
- </div>
252
+ <TableWithControlsLayout>
253
+ <TableWithControlsLayout.Controls>{renderControls()}</TableWithControlsLayout.Controls>
254
+ <TableWithControlsLayout.Table loading={loading && !wasLoaded} className={b('table')}>
255
+ {renderTable()}
256
+ </TableWithControlsLayout.Table>
257
+ </TableWithControlsLayout>
268
258
  );
269
259
  };
@@ -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;