ydb-embedded-ui 1.0.4 → 1.1.2

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