ydb-embedded-ui 4.5.1 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/FullNodeViewer/FullNodeViewer.js +1 -1
  3. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +1 -1
  4. package/dist/components/PoolUsage/PoolUsage.scss +1 -1
  5. package/dist/components/PoolUsage/PoolUsage.tsx +50 -0
  6. package/dist/containers/App/Content.js +3 -2
  7. package/dist/containers/AsideNavigation/AsideNavigation.tsx +4 -50
  8. package/dist/containers/Cluster/Cluster.scss +7 -48
  9. package/dist/containers/Cluster/Cluster.tsx +136 -20
  10. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +34 -17
  11. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +57 -91
  12. package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.scss +48 -0
  13. package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.tsx +34 -0
  14. package/dist/containers/Cluster/utils.ts +34 -0
  15. package/dist/containers/Header/Header.scss +0 -24
  16. package/dist/containers/Header/Header.tsx +14 -44
  17. package/dist/containers/Node/Node.tsx +23 -21
  18. package/dist/containers/Node/NodeStructure/NodeStructure.tsx +19 -17
  19. package/dist/containers/Nodes/Nodes.tsx +0 -16
  20. package/dist/containers/Nodes/getNodesColumns.tsx +1 -1
  21. package/dist/containers/Storage/Storage.js +1 -11
  22. package/dist/containers/Tablet/Tablet.tsx +28 -0
  23. package/dist/containers/TabletsFilters/TabletsFilters.js +16 -1
  24. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +1 -1
  25. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +3 -0
  26. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -3
  27. package/dist/containers/Tenant/Diagnostics/Network/Network.js +2 -2
  28. package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/ChangefeedInfo.tsx +4 -6
  29. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +56 -53
  30. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +1 -1
  31. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +1 -1
  32. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +1 -1
  33. package/dist/containers/Tenant/Preview/Preview.js +1 -1
  34. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +26 -22
  35. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +10 -3
  36. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +8 -1
  37. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/shared.ts +1 -6
  38. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +1 -1
  39. package/dist/containers/Tenant/Tenant.tsx +8 -13
  40. package/dist/containers/Tenant/utils/schemaActions.ts +1 -1
  41. package/dist/containers/Tenants/Tenants.js +18 -28
  42. package/dist/containers/Tenants/Tenants.scss +2 -4
  43. package/dist/containers/UserSettings/i18n/en.json +2 -2
  44. package/dist/containers/UserSettings/i18n/ru.json +2 -2
  45. package/dist/containers/UserSettings/settings.ts +4 -4
  46. package/dist/containers/Versions/GroupedNodesTree/GroupedNodesTree.scss +1 -0
  47. package/dist/containers/Versions/NodesTable/NodesTable.tsx +2 -3
  48. package/dist/containers/Versions/Versions.scss +0 -4
  49. package/dist/containers/Versions/Versions.tsx +74 -66
  50. package/dist/routes.ts +0 -7
  51. package/dist/services/api.ts +8 -4
  52. package/dist/store/reducers/clusterNodes/clusterNodes.tsx +4 -0
  53. package/dist/store/reducers/index.ts +6 -4
  54. package/dist/store/reducers/{network.js → network/network.ts} +11 -8
  55. package/dist/store/reducers/network/types.ts +16 -0
  56. package/dist/store/reducers/node/node.ts +102 -0
  57. package/dist/store/reducers/node/selectors.ts +59 -0
  58. package/dist/store/reducers/node/types.ts +44 -0
  59. package/dist/store/reducers/overview/overview.ts +109 -0
  60. package/dist/store/reducers/overview/types.ts +24 -0
  61. package/dist/store/reducers/{schema.ts → schema/schema.ts} +24 -50
  62. package/dist/{types/store/schema.ts → store/reducers/schema/types.ts} +16 -15
  63. package/dist/store/reducers/{schemaAcl.js → schemaAcl/schemaAcl.ts} +20 -9
  64. package/dist/store/reducers/schemaAcl/types.ts +15 -0
  65. package/dist/store/reducers/settings/settings.ts +5 -3
  66. package/dist/types/api/acl.ts +1 -1
  67. package/dist/types/api/query.ts +78 -44
  68. package/dist/types/store/explainQuery.ts +2 -2
  69. package/dist/types/store/query.ts +4 -2
  70. package/dist/utils/constants.ts +3 -1
  71. package/dist/utils/nodes.ts +1 -1
  72. package/dist/utils/query.ts +3 -3
  73. package/package.json +1 -1
  74. package/dist/components/PoolUsage/PoolUsage.js +0 -54
  75. package/dist/store/reducers/node.js +0 -141
@@ -3,7 +3,7 @@ import {useDispatch} from 'react-redux';
3
3
 
4
4
  import {NavigationTree} from 'ydb-ui-components';
5
5
 
6
- import {setCurrentSchemaPath, preloadSchemas} from '../../../../store/reducers/schema';
6
+ import {setCurrentSchemaPath, preloadSchemas} from '../../../../store/reducers/schema/schema';
7
7
  import type {EPathType, TEvDescribeSchemeResult} from '../../../../types/api/schema';
8
8
 
9
9
  import {isChildlessPathType, mapPathTypeToNavigationTreeType} from '../../utils/schema';
@@ -8,15 +8,16 @@ import type {TEvDescribeSchemeResult} from '../../types/api/schema';
8
8
 
9
9
  import {DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY} from '../../utils/constants';
10
10
  import {useTypedSelector} from '../../utils/hooks';
11
- import routes, {CLUSTER_PAGES, createHref} from '../../routes';
11
+ import routes, {createHref} from '../../routes';
12
12
  import {setHeader} from '../../store/reducers/header';
13
- import {disableAutorefresh, getSchema, resetLoadingState} from '../../store/reducers/schema';
14
- import {getSchemaAcl} from '../../store/reducers/schemaAcl';
15
- import {getTenantInfo, clearTenant} from '../../store/reducers/tenant/tenant';
13
+ import {disableAutorefresh, getSchema} from '../../store/reducers/schema/schema';
14
+ import {getSchemaAcl} from '../../store/reducers/schemaAcl/schemaAcl';
16
15
 
17
16
  import SplitPane from '../../components/SplitPane';
18
17
  import {AccessDenied} from '../../components/Errors/403';
19
18
 
19
+ import {getClusterPath} from '../Cluster/utils';
20
+
20
21
  import ObjectGeneralTabs from './ObjectGeneralTabs/ObjectGeneralTabs';
21
22
  import ObjectSummary from './ObjectSummary/ObjectSummary';
22
23
  import ObjectGeneral from './ObjectGeneral/ObjectGeneral';
@@ -62,7 +63,6 @@ function Tenant(props: TenantProps) {
62
63
  const {PathType: currentPathType, PathSubType: currentPathSubType} =
63
64
  (currentItem as TEvDescribeSchemeResult).PathDescription?.Self || {};
64
65
 
65
- const {error: {status: tenantStatus = 200} = {}} = useTypedSelector((state) => state.tenant);
66
66
  const {error: {status: schemaStatus = 200} = {}} = useTypedSelector((state) => state.schema);
67
67
 
68
68
  const dispatch = useDispatch();
@@ -82,7 +82,6 @@ function Tenant(props: TenantProps) {
82
82
  }, [tenantName, dispatch]);
83
83
 
84
84
  useEffect(() => {
85
- dispatch(resetLoadingState());
86
85
  dispatch(getSchema({path: currentSchemaPath}));
87
86
  dispatch(getSchemaAcl({path: currentSchemaPath}));
88
87
  }, [currentSchemaPath, dispatch]);
@@ -93,12 +92,11 @@ function Tenant(props: TenantProps) {
93
92
 
94
93
  useEffect(() => {
95
94
  if (tenantName) {
96
- dispatch(getTenantInfo({path: tenantName}));
97
95
  dispatch(
98
96
  setHeader([
99
97
  {
100
- text: CLUSTER_PAGES.tenants.title,
101
- link: createHref(routes.cluster, {activeTab: CLUSTER_PAGES.tenants.id}),
98
+ text: 'Cluster',
99
+ link: getClusterPath(),
102
100
  },
103
101
  {
104
102
  text: tenantName.startsWith('/') ? tenantName.slice(1) : tenantName,
@@ -109,9 +107,6 @@ function Tenant(props: TenantProps) {
109
107
  ]),
110
108
  );
111
109
  }
112
- return () => {
113
- dispatch(clearTenant());
114
- };
115
110
  }, [tenantName, dispatch]);
116
111
 
117
112
  const onCollapseSummaryHandler = () => {
@@ -125,7 +120,7 @@ function Tenant(props: TenantProps) {
125
120
  dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.clear);
126
121
  };
127
122
 
128
- const showBlockingError = tenantStatus === 403 || schemaStatus === 403;
123
+ const showBlockingError = schemaStatus === 403;
129
124
 
130
125
  return (
131
126
  <div className={b()}>
@@ -2,7 +2,7 @@ import {Dispatch} from 'react';
2
2
  import type {NavigationTreeNodeType, NavigationTreeProps} from 'ydb-ui-components';
3
3
 
4
4
  import {changeUserInput} from '../../../store/reducers/executeQuery';
5
- import {setShowPreview} from '../../../store/reducers/schema';
5
+ import {setShowPreview} from '../../../store/reducers/schema/schema';
6
6
  import {setTopLevelTab} from '../../../store/reducers/tenant/tenant';
7
7
  import {TENANT_GENERAL_TABS_IDS} from '../../../store/reducers/tenant/constants';
8
8
  import createToast from '../../../utils/createToast';
@@ -15,7 +15,7 @@ import {ProblemFilter} from '../../components/ProblemFilter';
15
15
  import {Illustration} from '../../components/Illustration';
16
16
  import {AutoFetcher} from '../../utils/autofetcher';
17
17
 
18
- import routes, {CLUSTER_PAGES, createHref} from '../../routes';
18
+ import routes, {createHref} from '../../routes';
19
19
  import {formatCPU, formatBytesToGigabyte, formatNumber} from '../../utils';
20
20
  import {withSearch} from '../../HOCS';
21
21
  import {DEFAULT_TABLE_SETTINGS, TENANT_INITIAL_TAB_KEY} from '../../utils/constants';
@@ -25,7 +25,6 @@ import {
25
25
  getSettingValue,
26
26
  ProblemFilterValues,
27
27
  } from '../../store/reducers/settings/settings';
28
- import {setHeader} from '../../store/reducers/header';
29
28
 
30
29
  import {clusterName} from '../../store';
31
30
  import {TenantTabsGroups, TENANT_GENERAL_TABS, TENANT_INFO_TABS} from '../Tenant/TenantPages';
@@ -51,7 +50,6 @@ class Tenants extends React.Component {
51
50
  tenants: PropTypes.array,
52
51
  searchQuery: PropTypes.string,
53
52
  handleSearchQuery: PropTypes.func,
54
- setHeader: PropTypes.func,
55
53
  filter: PropTypes.string,
56
54
  changeFilter: PropTypes.func,
57
55
  cluster: PropTypes.object,
@@ -77,12 +75,6 @@ class Tenants extends React.Component {
77
75
  this.autofetcher = new AutoFetcher();
78
76
  this.props.getTenantsInfo(clusterName);
79
77
  this.autofetcher.fetch(() => this.props.getTenantsInfo(clusterName));
80
- this.props.setHeader([
81
- {
82
- text: CLUSTER_PAGES.tenants.title,
83
- link: createHref(routes.cluster, {activeTab: CLUSTER_PAGES.tenants.id}),
84
- },
85
- ]);
86
78
  }
87
79
 
88
80
  componentWillUnmount() {
@@ -94,14 +86,15 @@ class Tenants extends React.Component {
94
86
 
95
87
  return (
96
88
  <div className={b('controls')}>
97
- <TextInput
98
- className={b('search')}
99
- placeholder="Database name"
100
- value={searchQuery}
101
- onUpdate={handleSearchQuery}
102
- hasClear
103
- autoFocus
104
- />
89
+ <div className={b('search')}>
90
+ <TextInput
91
+ placeholder="Database name"
92
+ value={searchQuery}
93
+ onUpdate={handleSearchQuery}
94
+ hasClear
95
+ autoFocus
96
+ />
97
+ </div>
105
98
  <ProblemFilter value={filter} onChange={changeFilter} />
106
99
  </div>
107
100
  );
@@ -309,16 +302,14 @@ class Tenants extends React.Component {
309
302
 
310
303
  return (
311
304
  <div className={b('table-wrapper')}>
312
- <div className={b('table-content')}>
313
- <DataTable
314
- theme="yandex-cloud"
315
- data={filteredTenants}
316
- columns={columns}
317
- settings={DEFAULT_TABLE_SETTINGS}
318
- dynamicRender={true}
319
- emptyDataMessage="No such tenants"
320
- />
321
- </div>
305
+ <DataTable
306
+ theme="yandex-cloud"
307
+ data={filteredTenants}
308
+ columns={columns}
309
+ settings={DEFAULT_TABLE_SETTINGS}
310
+ dynamicRender={true}
311
+ emptyDataMessage="No such tenants"
312
+ />
322
313
  </div>
323
314
  );
324
315
  };
@@ -363,7 +354,6 @@ const mapStateToProps = (state) => {
363
354
  const mapDispatchToProps = {
364
355
  getTenantsInfo,
365
356
  changeFilter,
366
- setHeader,
367
357
  };
368
358
 
369
359
  export default withSearch(connect(mapStateToProps, mapDispatchToProps)(Tenants));
@@ -1,7 +1,7 @@
1
1
  @import '../../styles/mixins.scss';
2
2
 
3
3
  .tenants {
4
- overflow: auto;
4
+ height: 100%;
5
5
  @include flex-container();
6
6
 
7
7
  &__format-label {
@@ -34,10 +34,8 @@
34
34
 
35
35
  &__table-wrapper {
36
36
  overflow: auto;
37
- @include flex-container();
38
- }
37
+ flex-grow: 1;
39
38
 
40
- &__table-content {
41
39
  @include freeze-nth-column(1);
42
40
 
43
41
  @include table-styles;
@@ -15,6 +15,6 @@
15
15
  "settings.useNodesEndpoint.title": "Break the Nodes tab in Diagnostics",
16
16
  "settings.useNodesEndpoint.popover": "Use /viewer/json/nodes endpoint for Nodes Tab in diagnostics. It returns incorrect data on versions before 23-1",
17
17
 
18
- "settings.enableQueryModesForExplain.title": "Enable query modes for explain",
19
- "settings.enableQueryModesForExplain.popover": "Enable script | scan query mode selector for both run and explain. May not work on versions before 23-2"
18
+ "settings.enableAdditionalQueryModes.title": "Enable additional query modes",
19
+ "settings.enableAdditionalQueryModes.popover": "Adds 'data' and 'query' modes for run. Enables query modes for explain. May not work on some versions"
20
20
  }
@@ -15,6 +15,6 @@
15
15
  "settings.useNodesEndpoint.title": "Сломать вкладку Nodes в диагностике",
16
16
  "settings.useNodesEndpoint.popover": "Использовать эндпоинт /viewer/json/nodes для вкладки Nodes в диагностике. Может возвращать некорректные данные на версиях до 23-1",
17
17
 
18
- "settings.enableQueryModesForExplain.title": "Включить режимы выполнения запроса для explain",
19
- "settings.enableQueryModesForExplain.popover": "Включить общий переключатель script | scan для run и explain. Может работать некорректно на версиях до 23-2"
18
+ "settings.enableAdditionalQueryModes.title": "Включить дополнительные режимы выполнения запросов",
19
+ "settings.enableAdditionalQueryModes.popover": "Добавляет режимы 'data' и 'query' для run. Включает возможность выбрать режим выполнения запроса для explain. Может работать некорректно на некоторых версиях"
20
20
  }
@@ -4,7 +4,7 @@ import favoriteFilledIcon from '../../assets/icons/star.svg';
4
4
  import flaskIcon from '../../assets/icons/flask.svg';
5
5
 
6
6
  import {
7
- ENABLE_QUERY_MODES_FOR_EXPLAIN,
7
+ ENABLE_ADDITIONAL_QUERY_MODES,
8
8
  INVERTED_DISKS_KEY,
9
9
  THEME_KEY,
10
10
  USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
@@ -59,9 +59,9 @@ export const useNodesEndpointSetting: SettingProps = {
59
59
  helpPopoverContent: i18n('settings.useNodesEndpoint.popover'),
60
60
  };
61
61
  export const enableQueryModesForExplainSetting: SettingProps = {
62
- settingKey: ENABLE_QUERY_MODES_FOR_EXPLAIN,
63
- title: i18n('settings.enableQueryModesForExplain.title'),
64
- helpPopoverContent: i18n('settings.enableQueryModesForExplain.popover'),
62
+ settingKey: ENABLE_ADDITIONAL_QUERY_MODES,
63
+ title: i18n('settings.enableAdditionalQueryModes.title'),
64
+ helpPopoverContent: i18n('settings.enableAdditionalQueryModes.popover'),
65
65
  };
66
66
 
67
67
  export const generalSection: SettingsSection = {
@@ -17,6 +17,7 @@
17
17
  z-index: 0;
18
18
 
19
19
  overflow-x: auto;
20
+ overflow-y: hidden;
20
21
 
21
22
  margin-right: $margin-size;
22
23
  margin-left: $margin-size;
@@ -2,6 +2,7 @@ import DataTable, {Column} from '@gravity-ui/react-data-table';
2
2
 
3
3
  import type {PreparedClusterNode} from '../../../store/reducers/clusterNodes/types';
4
4
  import {isUnavailableNode} from '../../../utils/nodes';
5
+ import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
5
6
  import {formatBytes} from '../../../utils';
6
7
  import {getDefaultNodePath} from '../../Node/NodePages';
7
8
 
@@ -112,9 +113,7 @@ export const NodesTable = ({nodes}: NodesTableProps) => {
112
113
  theme="yandex-cloud"
113
114
  data={nodes}
114
115
  columns={columns}
115
- settings={{
116
- displayIndices: false,
117
- }}
116
+ settings={DEFAULT_TABLE_SETTINGS}
118
117
  />
119
118
  );
120
119
  };
@@ -3,10 +3,6 @@
3
3
  .ydb-versions {
4
4
  $_: &;
5
5
 
6
- &__content {
7
- padding: 20px;
8
- }
9
-
10
6
  &__controls {
11
7
  display: flex;
12
8
  align-items: center;
@@ -1,10 +1,14 @@
1
1
  import {useState} from 'react';
2
+ import {useDispatch} from 'react-redux';
2
3
  import block from 'bem-cn-lite';
3
4
 
4
5
  import {Checkbox, RadioButton} from '@gravity-ui/uikit';
5
6
 
6
- import type {PreparedClusterNode} from '../../store/reducers/clusterNodes/types';
7
7
  import type {VersionToColorMap} from '../../types/versions';
8
+ import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
9
+ import {getClusterNodes} from '../../store/reducers/clusterNodes/clusterNodes';
10
+ import {Loader} from '../../components/Loader';
11
+
8
12
  import {getGroupedStorageNodes, getGroupedTenantNodes, getOtherNodes} from './groupNodes';
9
13
  import {GroupedNodesTree} from './GroupedNodesTree/GroupedNodesTree';
10
14
  import {GroupByValue} from './types';
@@ -14,11 +18,16 @@ import './Versions.scss';
14
18
  const b = block('ydb-versions');
15
19
 
16
20
  interface VersionsProps {
17
- nodes?: PreparedClusterNode[];
18
21
  versionToColor?: VersionToColorMap;
19
22
  }
20
23
 
21
- export const Versions = ({nodes = [], versionToColor}: VersionsProps) => {
24
+ export const Versions = ({versionToColor}: VersionsProps) => {
25
+ const dispatch = useDispatch();
26
+
27
+ const {nodes = [], loading, wasLoaded} = useTypedSelector((state) => state.clusterNodes);
28
+
29
+ useAutofetcher(() => dispatch(getClusterNodes()), [dispatch], true);
30
+
22
31
  const [groupByValue, setGroupByValue] = useState<GroupByValue>(GroupByValue.VERSION);
23
32
  const [expanded, setExpanded] = useState(false);
24
33
 
@@ -55,67 +64,66 @@ export const Versions = ({nodes = [], versionToColor}: VersionsProps) => {
55
64
  </div>
56
65
  );
57
66
  };
58
- const renderGroupedNodes = () => {
59
- const tenantNodes = getGroupedTenantNodes(nodes, versionToColor, groupByValue);
60
- const storageNodes = getGroupedStorageNodes(nodes, versionToColor);
61
- const otherNodes = getOtherNodes(nodes, versionToColor);
62
- const storageNodesContent = storageNodes?.length ? (
63
- <>
64
- <h3>Storage nodes</h3>
65
- {storageNodes.map(({title, nodes: itemNodes, items, versionColor}, index) => (
66
- <GroupedNodesTree
67
- key={`storage-nodes-${index}`}
68
- title={title}
69
- nodes={itemNodes}
70
- items={items}
71
- versionColor={versionColor}
72
- />
73
- ))}
74
- </>
75
- ) : null;
76
- const tenantNodesContent = tenantNodes?.length ? (
77
- <>
78
- <h3>Database nodes</h3>
79
- {renderControls()}
80
- {tenantNodes.map(
81
- ({title, nodes: itemNodes, items, versionColor, versionsValues}, index) => (
82
- <GroupedNodesTree
83
- key={`tenant-nodes-${index}`}
84
- title={title}
85
- nodes={itemNodes}
86
- items={items}
87
- expanded={expanded}
88
- versionColor={versionColor}
89
- versionsValues={versionsValues}
90
- />
91
- ),
92
- )}
93
- </>
94
- ) : null;
95
- const otherNodesContent = otherNodes?.length ? (
96
- <>
97
- <h3>Other nodes</h3>
98
- {otherNodes.map(
99
- ({title, nodes: itemNodes, items, versionColor, versionsValues}, index) => (
100
- <GroupedNodesTree
101
- key={`other-nodes-${index}`}
102
- title={title}
103
- nodes={itemNodes}
104
- items={items}
105
- versionColor={versionColor}
106
- versionsValues={versionsValues}
107
- />
108
- ),
109
- )}
110
- </>
111
- ) : null;
112
- return (
113
- <div className={b('versions')}>
114
- {storageNodesContent}
115
- {tenantNodesContent}
116
- {otherNodesContent}
117
- </div>
118
- );
119
- };
120
- return <div className={b('content')}>{renderGroupedNodes()}</div>;
67
+
68
+ if (loading && !wasLoaded) {
69
+ return <Loader />;
70
+ }
71
+
72
+ const tenantNodes = getGroupedTenantNodes(nodes, versionToColor, groupByValue);
73
+ const storageNodes = getGroupedStorageNodes(nodes, versionToColor);
74
+ const otherNodes = getOtherNodes(nodes, versionToColor);
75
+ const storageNodesContent = storageNodes?.length ? (
76
+ <>
77
+ <h3>Storage nodes</h3>
78
+ {storageNodes.map(({title, nodes: itemNodes, items, versionColor}) => (
79
+ <GroupedNodesTree
80
+ key={`storage-nodes-${title}`}
81
+ title={title}
82
+ nodes={itemNodes}
83
+ items={items}
84
+ versionColor={versionColor}
85
+ />
86
+ ))}
87
+ </>
88
+ ) : null;
89
+ const tenantNodesContent = tenantNodes?.length ? (
90
+ <>
91
+ <h3>Database nodes</h3>
92
+ {renderControls()}
93
+ {tenantNodes.map(({title, nodes: itemNodes, items, versionColor, versionsValues}) => (
94
+ <GroupedNodesTree
95
+ key={`tenant-nodes-${title}`}
96
+ title={title}
97
+ nodes={itemNodes}
98
+ items={items}
99
+ expanded={expanded}
100
+ versionColor={versionColor}
101
+ versionsValues={versionsValues}
102
+ />
103
+ ))}
104
+ </>
105
+ ) : null;
106
+ const otherNodesContent = otherNodes?.length ? (
107
+ <>
108
+ <h3>Other nodes</h3>
109
+ {otherNodes.map(({title, nodes: itemNodes, items, versionColor, versionsValues}) => (
110
+ <GroupedNodesTree
111
+ key={`other-nodes-${title}`}
112
+ title={title}
113
+ nodes={itemNodes}
114
+ items={items}
115
+ versionColor={versionColor}
116
+ versionsValues={versionsValues}
117
+ />
118
+ ))}
119
+ </>
120
+ ) : null;
121
+
122
+ return (
123
+ <div className={b('versions')}>
124
+ {storageNodesContent}
125
+ {tenantNodesContent}
126
+ {otherNodesContent}
127
+ </div>
128
+ );
121
129
  };
package/dist/routes.ts CHANGED
@@ -13,13 +13,6 @@ const routes = {
13
13
  auth: '/auth',
14
14
  };
15
15
 
16
- export const CLUSTER_PAGES = {
17
- tenants: {id: 'tenants', name: 'Databases', title: 'Database list'},
18
- nodes: {id: 'nodes', name: 'Nodes', title: 'Nodes'},
19
- storage: {id: 'storage', name: 'Storage', title: 'Storage'},
20
- cluster: {id: 'cluster', name: 'Cluster', title: 'Cluster'},
21
- };
22
-
23
16
  export function createHref(
24
17
  route: string,
25
18
  params?: Record<string, string | number>,
@@ -50,8 +50,12 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
50
50
  tablets: true,
51
51
  });
52
52
  }
53
- getClusterNodes() {
54
- return this.get<TEvSystemStateResponse>(this.getPath('/viewer/json/sysinfo'), {});
53
+ getClusterNodes({concurrentId}: AxiosOptions = {}) {
54
+ return this.get<TEvSystemStateResponse>(
55
+ this.getPath('/viewer/json/sysinfo'),
56
+ {},
57
+ {concurrentId: concurrentId || `getClusterNodes`},
58
+ );
55
59
  }
56
60
  getNodeInfo(id?: string) {
57
61
  return this.get<TEvSystemStateResponse>(this.getPath('/viewer/json/sysinfo?enums=true'), {
@@ -99,8 +103,8 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
99
103
  filter,
100
104
  nodeId,
101
105
  }: {
102
- tenant: string;
103
- filter: string;
106
+ tenant?: string;
107
+ filter?: string;
104
108
  nodeId: string;
105
109
  },
106
110
  {concurrentId}: AxiosOptions = {},
@@ -34,6 +34,10 @@ const clusterNodes: Reducer<ClusterNodesState, ClusterNodesAction> = (
34
34
  };
35
35
  }
36
36
  case FETCH_CLUSTER_NODES.FAILURE: {
37
+ if (action.error?.isCancelled) {
38
+ return state;
39
+ }
40
+
37
41
  return {
38
42
  ...state,
39
43
  error: action.error,
@@ -5,13 +5,14 @@ import cluster from './cluster/cluster';
5
5
  import clusterNodes from './clusterNodes/clusterNodes';
6
6
  import tenant from './tenant/tenant';
7
7
  import storage from './storage';
8
- import node from './node';
8
+ import node from './node/node';
9
9
  import tooltip from './tooltip';
10
10
  import tablets from './tablets';
11
11
  import heatmap from './heatmap';
12
- import schema from './schema';
12
+ import schema from './schema/schema';
13
+ import overview from './overview/overview';
13
14
  import host from './host';
14
- import network from './network';
15
+ import network from './network/network';
15
16
  import tenants from './tenants/tenants';
16
17
  import tablet from './tablet';
17
18
  import topic from './topic';
@@ -23,7 +24,7 @@ import settings from './settings/settings';
23
24
  import preview from './preview';
24
25
  import nodesList from './nodesList';
25
26
  import describe from './describe';
26
- import schemaAcl from './schemaAcl';
27
+ import schemaAcl from './schemaAcl/schemaAcl';
27
28
  import executeTopQueries from './executeTopQueries';
28
29
  import healthcheckInfo from './healthcheckInfo';
29
30
  import shardsWorkload from './shardsWorkload';
@@ -46,6 +47,7 @@ export const rootReducer = {
46
47
  tooltip,
47
48
  tablets,
48
49
  schema,
50
+ overview,
49
51
  olapStats,
50
52
  host,
51
53
  network,
@@ -1,20 +1,23 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
2
- import '../../services/api';
1
+ import {Reducer} from 'redux';
3
2
 
4
- const FETCH_ALL_NODES_NETWORK = createRequestActionTypes(
5
- 'ALL_NODES_NETWORK',
3
+ import '../../../services/api';
4
+ import {createRequestActionTypes, createApiRequest} from '../../utils';
5
+
6
+ import type {NetworkAction, NetworkState} from './types';
7
+
8
+ export const FETCH_ALL_NODES_NETWORK = createRequestActionTypes(
9
+ 'network',
6
10
  'FETCH_ALL_NODES_NETWORK',
7
11
  );
8
12
 
9
13
  const SET_DATA_WAS_NOT_LOADED = 'network/SET_DATA_WAS_NOT_LOADED';
10
14
 
11
15
  const initialState = {
12
- data: {},
13
16
  loading: false,
14
17
  wasLoaded: false,
15
18
  };
16
19
 
17
- const network = (state = initialState, action) => {
20
+ const network: Reducer<NetworkState, NetworkAction> = (state = initialState, action) => {
18
21
  switch (action.type) {
19
22
  case FETCH_ALL_NODES_NETWORK.REQUEST: {
20
23
  return {
@@ -53,10 +56,10 @@ const network = (state = initialState, action) => {
53
56
  export const setDataWasNotLoaded = () => {
54
57
  return {
55
58
  type: SET_DATA_WAS_NOT_LOADED,
56
- };
59
+ } as const;
57
60
  };
58
61
 
59
- export const getNetworkInfo = (tenant) => {
62
+ export const getNetworkInfo = (tenant: string) => {
60
63
  return createApiRequest({
61
64
  request: window.api.getNetwork(tenant),
62
65
  actions: FETCH_ALL_NODES_NETWORK,
@@ -0,0 +1,16 @@
1
+ import type {IResponseError} from '../../../types/api/error';
2
+ import type {TNetInfo} from '../../../types/api/netInfo';
3
+ import type {ApiRequestAction} from '../../utils';
4
+
5
+ import {FETCH_ALL_NODES_NETWORK, setDataWasNotLoaded} from './network';
6
+
7
+ export interface NetworkState {
8
+ loading: boolean;
9
+ wasLoaded: boolean;
10
+ data?: TNetInfo;
11
+ error?: IResponseError;
12
+ }
13
+
14
+ export type NetworkAction =
15
+ | ApiRequestAction<typeof FETCH_ALL_NODES_NETWORK, TNetInfo, IResponseError>
16
+ | ReturnType<typeof setDataWasNotLoaded>;