ydb-embedded-ui 1.0.4 → 1.1.2

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 (62) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/assets/icons/question.svg +1 -0
  3. package/dist/components/AsideNavigation/AsideHeader.tsx +2 -1
  4. package/dist/components/ClusterInfo/ClusterInfo.tsx +8 -4
  5. package/dist/components/FullNodeViewer/FullNodeViewer.scss +4 -9
  6. package/dist/components/InfoViewer/InfoViewer.scss +3 -2
  7. package/dist/components/InternalLink/InternalLink.js +8 -0
  8. package/dist/components/Loader/Loader.scss +5 -0
  9. package/dist/components/Loader/Loader.tsx +16 -0
  10. package/dist/components/PDiskViewer/PDiskViewer.js +3 -4
  11. package/dist/containers/App/App.scss +4 -0
  12. package/dist/containers/App/Content.js +0 -2
  13. package/dist/containers/AppIcons/AppIcons.js +4 -0
  14. package/dist/containers/Authentication/Authentication.tsx +2 -2
  15. package/dist/containers/Cluster/Cluster.tsx +1 -1
  16. package/dist/containers/Header/Header.tsx +6 -1
  17. package/dist/containers/Heatmap/Heatmap.js +0 -1
  18. package/dist/containers/Node/Node.scss +12 -1
  19. package/dist/containers/Node/Node.tsx +174 -0
  20. package/dist/containers/Node/NodeOverview/NodeOverview.scss +0 -0
  21. package/dist/containers/Node/NodeOverview/NodeOverview.tsx +23 -0
  22. package/dist/containers/Node/NodePages.js +16 -0
  23. package/dist/containers/Node/NodeStructure/NodeStructure.scss +151 -0
  24. package/dist/containers/Node/NodeStructure/NodeStructure.tsx +155 -0
  25. package/dist/containers/Node/NodeStructure/Pdisk.tsx +299 -0
  26. package/dist/containers/Node/NodeStructure/Vdisk.tsx +153 -0
  27. package/dist/containers/Pdisk/Pdisk.js +2 -5
  28. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +10 -3
  29. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +20 -15
  30. package/dist/containers/Storage/Pdisk/Pdisk.scss +1 -0
  31. package/dist/containers/Storage/Pdisk/Pdisk.tsx +7 -5
  32. package/dist/containers/Storage/Storage.js +12 -9
  33. package/dist/containers/Storage/StorageGroups/StorageGroups.scss +2 -1
  34. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +2 -2
  35. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +3 -2
  36. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +2 -2
  37. package/dist/containers/Storage/Vdisk/Vdisk.js +7 -6
  38. package/dist/containers/Storage/Vdisk/Vdisk.scss +1 -0
  39. package/dist/containers/Tablet/Tablet.js +2 -7
  40. package/dist/containers/Tablets/Tablets.js +4 -12
  41. package/dist/containers/Tenant/Acl/Acl.js +0 -3
  42. package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +1 -3
  43. package/dist/containers/Tenant/Diagnostics/Network/Network.js +3 -6
  44. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +2 -2
  45. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +24 -24
  46. package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +4 -0
  47. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +4 -1
  48. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +1 -0
  49. package/dist/containers/Vdisk/Vdisk.js +2 -4
  50. package/dist/containers/VdiskPdiskNode/VdiskPdiskNode.js +4 -6
  51. package/dist/services/api.js +0 -1
  52. package/dist/store/reducers/executeQuery.js +1 -1
  53. package/dist/store/reducers/header.ts +1 -1
  54. package/dist/store/reducers/node.js +98 -3
  55. package/dist/store/reducers/nodes.js +0 -3
  56. package/dist/store/reducers/storage.js +8 -2
  57. package/dist/store/reducers/tablets.js +0 -3
  58. package/dist/utils/constants.js +0 -6
  59. package/dist/utils/getNodesColumns.js +2 -9
  60. package/dist/utils/utils.js +10 -1
  61. package/package.json +43 -29
  62. package/dist/containers/Node/Node.js +0 -184
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ### [1.1.2](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.1.1...v1.1.2) (2022-04-19)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **ObjectSummary:** should correctly parse table creation time ([c9887dd](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/c9887dd162720667dcbe3b4834b3b0ba5a9f3f6e))
9
+
10
+ ### [1.1.1](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.1.0...v1.1.1) (2022-04-19)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * add typecheck + fix type errors ([e6d9086](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/e6d9086c46702a611f848c992377d18826ca2e23))
16
+ * **Node:** scroll to selected vdisk should not apply to undefined container ([7236a43](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/7236a43655b935777abb5b8df228ae011ceb6bed))
17
+
18
+ ## [1.1.0](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.4...v1.1.0) (2022-04-15)
19
+
20
+
21
+ ### Features
22
+
23
+ * local precommit check ([d5da9b3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/d5da9b3fb89eeeb5461e7e14fe33964a8ed9078d))
24
+ * new Node Structure view ([5cf5dd3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/5cf5dd39fa59625be4bb89f16796f16ecb9d9d78))
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * **Authentication:** should be able to send authentication data with empty password [YDB-1610] ([5d4d881](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/5d4d8810bb2ddabb9db1316a99194f5a1bd986b6))
30
+ * **Cluster:** should show additional info ([cb21ce3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/cb21ce317c55d05c7a7c166bc09dc1fe14e41692))
31
+ * code-review ([a706903](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/a706903e6a30ee62aff5829c37ba8c197335e106))
32
+ * different interface fixes ([0bd3a32](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/0bd3a32bf1502cc6d0f7419aa9d00653afe5d7bf))
33
+ * improve usability ([20f1acc](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/20f1acc255876968ea366a860d33a12eecc5e74f))
34
+ * **Nodes:** default path to node should be Overview ([ac4add6](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/ac4add6c1403ac2b9614f252fabf23b9e97ef2c2))
35
+ * query run type select should be styled as action button [YDB-1567] ([d06cd6a](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/d06cd6ac72ccb8c7eef205fddb1153e6383baeea))
36
+ * **QueryEditor:** should resolve row key by index [YDB-1604] ([4acd2a3](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/4acd2a30d03f2e45368587839549f4e5981f93dd))
37
+ * refactoring ([0c5aca5](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/0c5aca5b96bc5d5e9c3f121aa1ffe394f3fbd28f))
38
+ * **Storage:** wording fixed [YDB-1552] ([431f77f](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/431f77f090073037404639c686246d2f115d98f4))
39
+ * styles ([2725055](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/2725055b0f25e711c73e2888da41cfaf2657b110))
40
+
3
41
  ### [1.0.4](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.3...v1.0.4) (2022-03-24)
4
42
 
5
43
 
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 400c-18 0-32-14-32-32s13.1-32 32-32c17.1 0 32 14 32 32S273.1 400 256 400zM325.1 258L280 286V288c0 13-11 24-24 24S232 301 232 288V272c0-8 4-16 12-21l57-34C308 213 312 206 312 198C312 186 301.1 176 289.1 176h-51.1C225.1 176 216 186 216 198c0 13-11 24-24 24s-24-11-24-24C168 159 199 128 237.1 128h51.1C329 128 360 159 360 198C360 222 347 245 325.1 258z"/></svg>
@@ -20,7 +20,7 @@ import {
20
20
  FooterItemIconView,
21
21
  } from './constants';
22
22
  import i18n from './i18n';
23
- import {Lang} from 'utils/i18n';
23
+
24
24
  import {getLocalData, setLocalData} from './helpers';
25
25
  import {SetSlotsContext, SlotsProvider} from './AsideHeaderFooterSlot/SlotsContext';
26
26
  import {SlotName} from './AsideHeaderFooterSlot/AsideHeaderFooterSlot';
@@ -28,6 +28,7 @@ import {SlotName} from './AsideHeaderFooterSlot/AsideHeaderFooterSlot';
28
28
  import controlMenuButton from '../../assets/icons/control-menu-button.svg';
29
29
 
30
30
  import './AsideHeader.scss';
31
+ import {Lang} from '../../utils/i18n';
31
32
 
32
33
  const b = block('nv-aside-header');
33
34
 
@@ -31,7 +31,7 @@ import {Link, Loader} from '@yandex-cloud/uikit';
31
31
  //@ts-ignore
32
32
  import Icon from '../Icon/Icon';
33
33
  import {setHeader} from '../../store/reducers/header';
34
- import routes, { CLUSTER_PAGES, createHref } from '../../routes';
34
+ import routes, {CLUSTER_PAGES, createHref} from '../../routes';
35
35
 
36
36
  const b = cn('cluster-info');
37
37
 
@@ -62,7 +62,7 @@ interface ClusterInfoProps {
62
62
  setHeader: any;
63
63
  getClusterInfo: (clusterName: string) => void;
64
64
  clusterTitle?: string;
65
- additionalInfo?: IClusterInfoItem[];
65
+ additionalClusterInfo?: IClusterInfoItem[];
66
66
  loading: boolean;
67
67
  singleClusterMode: boolean;
68
68
  wasLoaded: boolean;
@@ -128,7 +128,11 @@ class ClusterInfo extends React.Component<ClusterInfoProps> {
128
128
  private autofetcher: any;
129
129
 
130
130
  private getInfo() {
131
- const {cluster = {} as ICluster, additionalInfo = [], singleClusterMode} = this.props;
131
+ const {
132
+ cluster = {} as ICluster,
133
+ additionalClusterInfo = [],
134
+ singleClusterMode,
135
+ } = this.props;
132
136
  const {StorageTotal, StorageUsed} = cluster;
133
137
 
134
138
  let link = backend + '/internal';
@@ -173,7 +177,7 @@ class ClusterInfo extends React.Component<ClusterInfoProps> {
173
177
  label: 'Versions',
174
178
  value: <div>{cluster.Versions?.join(', ')}</div>,
175
179
  },
176
- ...additionalInfo,
180
+ ...additionalClusterInfo,
177
181
  {
178
182
  label: 'Internal viewer',
179
183
  value: (
@@ -3,13 +3,12 @@
3
3
  .full-node-viewer {
4
4
  font-size: var(--yc-text-body2-font-size);
5
5
  line-height: var(--yc-text-body2-line-height);
6
- @include container-fluid();
7
6
 
8
7
  &__title {
9
8
  margin: 0 20px 0 0;
10
9
 
11
10
  font-size: var(--yc-text-body2-font-size);
12
- font-weight: 500;
11
+ font-weight: 600;
13
12
  line-height: var(--yc-text-body2-line-height);
14
13
  text-transform: uppercase;
15
14
  }
@@ -27,14 +26,12 @@
27
26
 
28
27
  &__common-info {
29
28
  display: flex;
29
+ flex-direction: column;
30
30
  justify-content: flex-start;
31
31
  align-items: stretch;
32
32
  }
33
33
 
34
34
  &__section {
35
- margin-right: 20px;
36
- padding: 15px;
37
-
38
35
  border-radius: 10px;
39
36
 
40
37
  &_pools {
@@ -42,8 +39,6 @@
42
39
  grid-gap: 7px 20px;
43
40
 
44
41
  grid-template-columns: 110px 110px;
45
-
46
- padding: 15px 15px 15px 0;
47
42
  }
48
43
  }
49
44
 
@@ -72,10 +67,10 @@
72
67
  }
73
68
 
74
69
  &__section-title {
75
- margin: 15px 0 0;
70
+ margin: 15px 0 10px;
76
71
 
77
72
  font-size: var(--yc-text-body2-font-size);
78
- font-weight: 500;
73
+ font-weight: 600;
79
74
  line-height: var(--yc-text-body2-line-height);
80
75
  }
81
76
 
@@ -2,10 +2,10 @@
2
2
  font-size: var(--yc-text-body2-font-size);
3
3
  line-height: var(--yc-text-body2-line-height);
4
4
  &__title {
5
- margin: 0 0 16px;
5
+ margin: 15px 0 10px;
6
6
 
7
7
  font-size: var(--yc-text-body2-font-size);
8
- font-weight: 500;
8
+ font-weight: 600;
9
9
  line-height: var(--yc-text-body2-line-height);
10
10
  }
11
11
 
@@ -30,6 +30,7 @@
30
30
  flex: 1 1 auto;
31
31
  align-items: baseline;
32
32
 
33
+ min-width: 200px;
33
34
  max-width: 200px;
34
35
 
35
36
  white-space: nowrap;
@@ -1,3 +1,4 @@
1
+ import PropTypes from 'prop-types';
1
2
  import cn from 'bem-cn-lite';
2
3
 
3
4
  import {Link} from 'react-router-dom';
@@ -13,3 +14,10 @@ export default function InternalLink({to, children, onClick, className}) {
13
14
  children
14
15
  );
15
16
  }
17
+
18
+ InternalLink.propTypes = {
19
+ to: PropTypes.string.isRequired,
20
+ children: PropTypes.node,
21
+ onClick: PropTypes.func,
22
+ className: PropTypes.string,
23
+ };
@@ -0,0 +1,5 @@
1
+ @import '../../styles/mixins.scss';
2
+
3
+ .kv-loader {
4
+ @include loader();
5
+ }
@@ -0,0 +1,16 @@
1
+ import cn from 'bem-cn-lite';
2
+ import {Loader as KitLoader, LoaderSize} from '@yandex-cloud/uikit';
3
+
4
+ import './Loader.scss';
5
+
6
+ const b = cn('kv-loader');
7
+
8
+ function Loader({size = 'l'}: {size?: LoaderSize}) {
9
+ return (
10
+ <div className={b()}>
11
+ <KitLoader size={size} />
12
+ </div>
13
+ );
14
+ }
15
+
16
+ export default Loader;
@@ -8,6 +8,8 @@ import EntityStatus from '../EntityStatus/EntityStatus';
8
8
  import {formatStorageValues} from '../../utils';
9
9
  import routes, {createHref} from '../../routes';
10
10
 
11
+ import {getDefaultNodePath} from '../../containers/Node/NodePages';
12
+
11
13
  import './PDiskViewer.scss';
12
14
 
13
15
  const b = cn('pdisk-viewer');
@@ -48,10 +50,7 @@ class PDiskViewer extends React.Component {
48
50
  <EntityStatus
49
51
  status={'green'}
50
52
  label="NodeID"
51
- path={createHref(routes.node, {
52
- id: disk.NodeId,
53
- activeTab: 'storage',
54
- })}
53
+ path={getDefaultNodePath(disk.NodeId)}
55
54
  name={disk.NodeId}
56
55
  />
57
56
  </div>
@@ -171,3 +171,7 @@ body,
171
171
  .app_embedded {
172
172
  font-family: 'Rubik', sans-serif;
173
173
  }
174
+
175
+ .yc-popup {
176
+ max-width: 500px;
177
+ }
@@ -12,7 +12,6 @@ import Tenant from '../Tenant/Tenant';
12
12
  import Node from '../Node/Node';
13
13
  import Pdisk from '../Pdisk/Pdisk';
14
14
  import Group from '../Group/Group';
15
- import VdiskPdiskNode from '../VdiskPdiskNode/VdiskPdiskNode';
16
15
  import Pool from '../Pool/Pool';
17
16
  import Tablet from '../Tablet/Tablet';
18
17
  import TabletsFilters from '../TabletsFilters/TabletsFilters';
@@ -44,7 +43,6 @@ export function Content(props) {
44
43
  <Route path={routes.cluster} component={Cluster} />
45
44
  <Route path={routes.tenant} component={Tenant} />
46
45
  <Route path={routes.pdisk} component={Pdisk} />
47
- <Route path={routes.vdisk} component={VdiskPdiskNode} />
48
46
  <Route path={routes.node} component={Node} />
49
47
  <Route path={routes.group} component={Group} />
50
48
  <Route path={routes.pool} component={Pool} />
@@ -2,6 +2,10 @@ const AppIcons = () => (
2
2
  /* eslint-disable */
3
3
  <svg width="0" height="0">
4
4
  <defs>
5
+ <path
6
+ id="icon.information"
7
+ d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"
8
+ />
5
9
  <path
6
10
  id="icon.tablePreview"
7
11
  d="M13.2812 2.4375H2.71875C2.0332 2.4375 1.5 2.99609 1.5 3.65625V12.5938C1.5 13.2793 2.0332 13.8125 2.71875 13.8125H13.2812C13.9414 13.8125 14.5 13.2793 14.5 12.5938V3.65625C14.5 2.99609 13.9414 2.4375 13.2812 2.4375ZM7.1875 12.1875H3.125V9.75H7.1875V12.1875ZM7.1875 8.125H3.125V5.6875H7.1875V8.125ZM12.875 12.1875H8.8125V9.75H12.875V12.1875ZM12.875 8.125H8.8125V5.6875H12.875V8.125Z"
@@ -43,7 +43,7 @@ function Authentication({authenticate, error}: any) {
43
43
  authenticate(login, pass);
44
44
  };
45
45
 
46
- const onEnterClick = (e: KeyboardEvent<HTMLInputElement>) => {
46
+ const onEnterClick = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
47
47
  if (e.keyCode === 13) {
48
48
  onLoginClick();
49
49
  }
@@ -99,7 +99,7 @@ function Authentication({authenticate, error}: any) {
99
99
  onClick={onLoginClick}
100
100
  width="max"
101
101
  size="l"
102
- disabled={Boolean(!login || !pass || loginError || passwordError)}
102
+ disabled={Boolean(!login || loginError || passwordError)}
103
103
  className={b('button-sign-in')}
104
104
  >
105
105
  Sign in
@@ -35,7 +35,7 @@ function Cluster(props: ClusterProps) {
35
35
  return <Storage {...props} />;
36
36
  }
37
37
  case CLUSTER_PAGES.cluster.id: {
38
- return <ClusterInfo />;
38
+ return <ClusterInfo additionalClusterInfo={props.additionalClusterInfo} />;
39
39
  }
40
40
  default: {
41
41
  return null;
@@ -60,7 +60,12 @@ function Header() {
60
60
  }
61
61
 
62
62
  const breadcrumbItems = header.reduce((acc, el) => {
63
- acc.push({text: el.text, action: () => history.push(el.link)});
63
+ const action = () => {
64
+ if (el.link) {
65
+ history.push(el.link);
66
+ }
67
+ };
68
+ acc.push({text: el.text, action});
64
69
  return acc;
65
70
  }, [] as BreadcrumbsItem[]);
66
71
 
@@ -35,7 +35,6 @@ class Heatmap extends React.Component {
35
35
  hideTooltip: PropTypes.func,
36
36
  getTabletsInfo: PropTypes.func,
37
37
  nodeId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
38
- timeoutForRequest: PropTypes.number,
39
38
  path: PropTypes.string,
40
39
  clearWasLoadingFlag: PropTypes.func,
41
40
  metrics: PropTypes.array,
@@ -5,6 +5,8 @@
5
5
  @include flex-container();
6
6
 
7
7
  &__content {
8
+ position: relative;
9
+
8
10
  overflow: auto;
9
11
  @include flex-container();
10
12
  }
@@ -17,7 +19,8 @@
17
19
  }
18
20
 
19
21
  &__tabs {
20
- padding: 0 15px;
22
+ padding: 16px 20px 0;
23
+ @include body2-typography();
21
24
  }
22
25
 
23
26
  &__tab {
@@ -33,4 +36,12 @@
33
36
  text-transform: uppercase;
34
37
  }
35
38
  }
39
+
40
+ &__overview-wrapper {
41
+ padding: 0 20px 20px;
42
+ }
43
+
44
+ &__node-page-wrapper {
45
+ padding: 20px;
46
+ }
36
47
  }
@@ -0,0 +1,174 @@
1
+ import * as React from 'react';
2
+ import {useRouteMatch} from 'react-router';
3
+ import cn from 'bem-cn-lite';
4
+ import {useDispatch, useSelector} from 'react-redux';
5
+ import _ from 'lodash';
6
+
7
+ import {Tabs} from '@yandex-cloud/uikit';
8
+ import {Link} from 'react-router-dom';
9
+
10
+ import {TABLETS, STORAGE, NODE_PAGES, OVERVIEW, STRUCTURE} from './NodePages';
11
+ import Tablets from '../Tablets/Tablets';
12
+ import Storage from '../Storage/Storage';
13
+ import NodeOverview from './NodeOverview/NodeOverview';
14
+ import NodeStructure from './NodeStructure/NodeStructure';
15
+ import Loader from '../../components/Loader/Loader';
16
+
17
+ import {getNodeInfo, resetNode} from '../../store/reducers/node';
18
+ import routes, {CLUSTER_PAGES, createHref} from '../../routes';
19
+ import {setHeader} from '../../store/reducers/header';
20
+ import {AutoFetcher} from '../../utils/autofetcher';
21
+
22
+ import './Node.scss';
23
+
24
+ const b = cn('node');
25
+
26
+ export const STORAGE_ROLE = 'Storage';
27
+
28
+ const headerNodes = {
29
+ text: CLUSTER_PAGES.nodes.title,
30
+ link: createHref(routes.cluster, {activeTab: CLUSTER_PAGES.nodes.id}),
31
+ };
32
+
33
+ const autofetcher = new AutoFetcher();
34
+
35
+ interface NodeProps {
36
+ additionalNodesInfo?: any;
37
+ className?: string;
38
+ }
39
+
40
+ function Node(props: NodeProps) {
41
+ const dispatch = useDispatch();
42
+
43
+ const wasLoaded = useSelector((state: any) => state.node.wasLoaded);
44
+ const loading = useSelector((state: any) => state.node.loading);
45
+ const error = useSelector((state: any) => state.node.error);
46
+
47
+ const node = useSelector((state: any) => state.node?.data?.SystemStateInfo?.[0]);
48
+
49
+ const nodeHost = node?.Host;
50
+
51
+ const match =
52
+ useRouteMatch<{id: string; activeTab: string}>(routes.node) ?? Object.create(null);
53
+
54
+ const {id: nodeId, activeTab} = match.params;
55
+
56
+ const {activeTabVerified, nodeTabs} = React.useMemo(() => {
57
+ const hasStorage = _.find(node?.Roles as any[], (el) => el === STORAGE_ROLE);
58
+ let activeTabVerified = activeTab;
59
+ if (!hasStorage && activeTab === STORAGE) {
60
+ activeTabVerified = OVERVIEW;
61
+ }
62
+ const nodePages = hasStorage ? NODE_PAGES : NODE_PAGES.filter((el) => el.id !== STORAGE);
63
+
64
+ const nodeTabs = nodePages.map((page) => {
65
+ return {
66
+ ...page,
67
+ title: page.name,
68
+ };
69
+ });
70
+
71
+ return {activeTabVerified, nodeTabs};
72
+ }, [activeTab, node]);
73
+
74
+ React.useEffect(() => {
75
+ const fetchData = () => dispatch(getNodeInfo(nodeId));
76
+ fetchData();
77
+ autofetcher.start();
78
+ autofetcher.fetch(() => fetchData());
79
+ dispatch(setHeader([headerNodes]));
80
+ return () => {
81
+ autofetcher.stop();
82
+ dispatch(resetNode());
83
+ };
84
+ }, [nodeId]);
85
+
86
+ React.useEffect(() => {
87
+ dispatch(
88
+ setHeader([
89
+ headerNodes,
90
+ {
91
+ text: nodeHost,
92
+ },
93
+ ]),
94
+ );
95
+ }, [nodeHost]);
96
+
97
+ const renderTabs = () => {
98
+ return (
99
+ <div className={b('tabs')}>
100
+ <Tabs
101
+ items={nodeTabs}
102
+ activeTab={activeTabVerified}
103
+ wrapTo={({id}, node) => (
104
+ <Link
105
+ to={createHref(routes.node, {id: nodeId, activeTab: id})}
106
+ key={id}
107
+ className={b('tab')}
108
+ >
109
+ {node}
110
+ </Link>
111
+ )}
112
+ allowNotSelected={true}
113
+ />
114
+ </div>
115
+ );
116
+ };
117
+ const renderTabContent = () => {
118
+ const {additionalNodesInfo} = props;
119
+
120
+ switch (activeTab) {
121
+ case STORAGE: {
122
+ return (
123
+ <div className={b('storage')}>
124
+ <Storage nodeId={nodeId} />
125
+ </div>
126
+ );
127
+ }
128
+ case TABLETS: {
129
+ return <Tablets nodeId={nodeId} className={b('node-page-wrapper')} />;
130
+ }
131
+
132
+ case OVERVIEW: {
133
+ return (
134
+ <NodeOverview
135
+ additionalNodesInfo={additionalNodesInfo}
136
+ node={node}
137
+ className={b('overview-wrapper')}
138
+ />
139
+ );
140
+ }
141
+
142
+ case STRUCTURE: {
143
+ return (
144
+ <NodeStructure
145
+ className={b('node-page-wrapper')}
146
+ nodeId={nodeId}
147
+ additionalNodesInfo={additionalNodesInfo}
148
+ />
149
+ );
150
+ }
151
+ default:
152
+ return false;
153
+ }
154
+ };
155
+
156
+ if (loading && !wasLoaded) {
157
+ return <Loader />;
158
+ } else if (error) {
159
+ return <div>{error.statusText}</div>;
160
+ } else {
161
+ if (node) {
162
+ return (
163
+ <div className={b(null, props.className)}>
164
+ {renderTabs()}
165
+
166
+ <div className={b('content')}>{renderTabContent()}</div>
167
+ </div>
168
+ );
169
+ }
170
+ return <div className="error">no node data</div>;
171
+ }
172
+ }
173
+
174
+ export default Node;
@@ -0,0 +1,23 @@
1
+
2
+ //@ts-ignore
3
+ import FullNodeViewer from '../../../components/FullNodeViewer/FullNodeViewer';
4
+ import {backend} from '../../../store';
5
+
6
+ interface NodeOverviewProps {
7
+ node: any;
8
+ additionalNodesInfo: any;
9
+ className?: string;
10
+ }
11
+
12
+ function NodeOverview({node, additionalNodesInfo, className}: NodeOverviewProps) {
13
+ return (
14
+ <FullNodeViewer
15
+ node={node}
16
+ backend={backend}
17
+ additionalNodesInfo={additionalNodesInfo}
18
+ className={className}
19
+ />
20
+ );
21
+ }
22
+
23
+ export default NodeOverview;
@@ -1,13 +1,29 @@
1
+ import routes, {createHref} from '../../routes';
2
+
1
3
  export const STORAGE = 'storage';
2
4
  export const TABLETS = 'tablets';
5
+ export const OVERVIEW = 'overview';
6
+ export const STRUCTURE = 'structure';
3
7
 
4
8
  export const NODE_PAGES = [
9
+ {
10
+ id: OVERVIEW,
11
+ name: 'Overview',
12
+ },
5
13
  {
6
14
  id: STORAGE,
7
15
  name: 'Storage',
8
16
  },
17
+ {id: STRUCTURE, name: 'Structure'},
9
18
  {
10
19
  id: TABLETS,
11
20
  name: 'Tablets',
12
21
  },
13
22
  ];
23
+
24
+ export function getDefaultNodePath(nodeId) {
25
+ return createHref(routes.node, {
26
+ id: nodeId,
27
+ activeTab: OVERVIEW,
28
+ });
29
+ }