ydb-embedded-ui 1.8.8 → 1.10.1

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 (41) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/components/BasicNodeViewer/BasicNodeViewer.scss +43 -0
  3. package/dist/components/BasicNodeViewer/BasicNodeViewer.tsx +53 -0
  4. package/dist/components/BasicNodeViewer/index.ts +1 -0
  5. package/dist/components/EntityStatus/EntityStatus.js +15 -3
  6. package/dist/components/FullNodeViewer/FullNodeViewer.js +29 -48
  7. package/dist/components/FullNodeViewer/FullNodeViewer.scss +0 -45
  8. package/dist/components/IndexInfoViewer/IndexInfoViewer.tsx +52 -0
  9. package/dist/components/InfoViewer/index.ts +4 -0
  10. package/dist/components/InfoViewer/utils.ts +32 -0
  11. package/dist/components/ProgressViewer/ProgressViewer.js +1 -1
  12. package/dist/containers/Node/Node.scss +5 -1
  13. package/dist/containers/Node/Node.tsx +7 -1
  14. package/dist/containers/Node/NodeOverview/NodeOverview.tsx +1 -3
  15. package/dist/containers/Node/NodeStructure/NodeStructure.scss +30 -1
  16. package/dist/containers/Node/NodeStructure/PDiskTitleBadge.tsx +25 -0
  17. package/dist/containers/Node/NodeStructure/Pdisk.tsx +24 -2
  18. package/dist/containers/Nodes/Nodes.js +1 -0
  19. package/dist/containers/Storage/Pdisk/Pdisk.tsx +25 -33
  20. package/dist/containers/Storage/Vdisk/Vdisk.js +2 -0
  21. package/dist/containers/Tablet/Tablet.js +2 -2
  22. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +24 -14
  23. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +3 -3
  24. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +24 -3
  25. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +80 -10
  26. package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +20 -16
  27. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +1 -0
  28. package/dist/containers/Tenant/utils/schema.ts +73 -28
  29. package/dist/containers/Tenant/utils/schemaActions.ts +45 -32
  30. package/dist/services/api.js +13 -8
  31. package/dist/store/reducers/executeQuery.js +1 -1
  32. package/dist/store/reducers/executeTopQueries.js +1 -1
  33. package/dist/store/reducers/olapStats.js +5 -1
  34. package/dist/store/reducers/preview.js +1 -1
  35. package/dist/store/reducers/shardsWorkload.js +32 -4
  36. package/dist/types/api/schema.ts +43 -1
  37. package/dist/types/api/storage.ts +54 -0
  38. package/dist/utils/getNodesColumns.js +2 -0
  39. package/dist/utils/pdisk.ts +74 -0
  40. package/dist/utils/tooltip.js +27 -0
  41. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.10.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.10.0...v1.10.1) (2022-08-10)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **Tenant:** fix actions set for topics ([0c75bf4](https://github.com/ydb-platform/ydb-embedded-ui/commit/0c75bf4561966dd663ab1cd7c7b81ef6b4632e50))
9
+
10
+ ## [1.10.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.9.0...v1.10.0) (2022-08-10)
11
+
12
+
13
+ ### Features
14
+
15
+ * **TopShards:** add DataSize column ([cbcd047](https://github.com/ydb-platform/ydb-embedded-ui/commit/cbcd047d277f699a67bc002a5542f3b9f6a0c942))
16
+ * **TopShards:** sort table data on backend ([dc28c5c](https://github.com/ydb-platform/ydb-embedded-ui/commit/dc28c5c75b0036480bf804d49f82fc54eac98c8e))
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * add concurrentId for sendQuery request ([dc6b32a](https://github.com/ydb-platform/ydb-embedded-ui/commit/dc6b32a8fd51064ddeca2fc60a0f08a725216334))
22
+ * **Storage:** display pdisk type in tooltip ([2b03a35](https://github.com/ydb-platform/ydb-embedded-ui/commit/2b03a35fc11ddeae3bdd30a0690b324ae917f5c3))
23
+ * **Tablet:** change Kill to Restart ([dd585b1](https://github.com/ydb-platform/ydb-embedded-ui/commit/dd585b1d1a6a5ddb484a702523773b169900f582))
24
+ * **Tenant:** add missing schema node types ([62a0ecb](https://github.com/ydb-platform/ydb-embedded-ui/commit/62a0ecb848dbcee53e18535cbf7c03a731d0cfeb))
25
+ * **Tenant:** ensure correct behavior for new schema node types ([f80c381](https://github.com/ydb-platform/ydb-embedded-ui/commit/f80c38152656e8bbbe51ec38b29fc0d954c361cc))
26
+ * **Tenant:** use new schema icons ([389a921](https://github.com/ydb-platform/ydb-embedded-ui/commit/389a9214c64b1adb183fa0c6caa6f2ec536dbef3))
27
+ * **TopShards:** disable virtualization for table ([006d3d9](https://github.com/ydb-platform/ydb-embedded-ui/commit/006d3d9fb9a4744b8bb4ad03e53693199213f80e))
28
+ * **TopShards:** format DataSize value ([c51ce66](https://github.com/ydb-platform/ydb-embedded-ui/commit/c51ce66286f6454f7252d1194628ee5a50aafba2))
29
+ * **TopShards:** only allow DESC sort ([6aa326f](https://github.com/ydb-platform/ydb-embedded-ui/commit/6aa326fc4b8165f00f8b3ecf5becdb0943ed57af))
30
+ * **TopShards:** substring tenant name out of shards path ([9e57672](https://github.com/ydb-platform/ydb-embedded-ui/commit/9e5767222c7dac7734c68abd08067cea507b1e15))
31
+
32
+ ## [1.9.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.8...v1.9.0) (2022-07-29)
33
+
34
+
35
+ ### Features
36
+
37
+ * **Node:** display endpoints in overview ([89e9e47](https://github.com/ydb-platform/ydb-embedded-ui/commit/89e9e470499b6f458e8949211d97293c0b7d9b97))
38
+ * **Node:** display node basic info above tabs ([aafb15b](https://github.com/ydb-platform/ydb-embedded-ui/commit/aafb15b399bf116026eff36f3c4ac817e2c40e18))
39
+ * **Node:** more informative pdisks panels ([342712b](https://github.com/ydb-platform/ydb-embedded-ui/commit/342712bcaa793971e1ca354da57fb962639ef90c))
40
+ * **Nodes:** show node endpoints in tooltip ([34be559](https://github.com/ydb-platform/ydb-embedded-ui/commit/34be55957e02f947ede30b43f22fde82d21df308))
41
+ * **Tenant:** table index overview ([2aed714](https://github.com/ydb-platform/ydb-embedded-ui/commit/2aed71488cde1175e6569c236ab609bb126f9cf3))
42
+ * **Tenant:** virtualized tree in schema ([815f558](https://github.com/ydb-platform/ydb-embedded-ui/commit/815f5588e5fed6fb86f69653c4937e975465372f))
43
+ * utils for parsing bitfields in pdisk data ([da22b4a](https://github.com/ydb-platform/ydb-embedded-ui/commit/da22b4afde9efe4d9605cefb69ddd51aed989722))
44
+
45
+
46
+ ### Bug Fixes
47
+
48
+ * **Node:** fix pdisk title items width ([ca5fec6](https://github.com/ydb-platform/ydb-embedded-ui/commit/ca5fec6388364b7d1d6362f1bda36431d9c29749))
49
+ * **Nodes:** hide tooltip on unmount ([54e4fdc](https://github.com/ydb-platform/ydb-embedded-ui/commit/54e4fdc8045c555338e79d89a93faf58e888fa0e))
50
+ * **ProgressViewer:** apply provided custom class name ([aa60e9d](https://github.com/ydb-platform/ydb-embedded-ui/commit/aa60e9d1b9c0752853f4323d3bcfd220bedd272d))
51
+ * **Tenant:** display all table props in overview ([d70e311](https://github.com/ydb-platform/ydb-embedded-ui/commit/d70e311296f6a4d1781f6e72929c70e0db7c3226))
52
+ * **Tenant:** display PartCount first in table overview ([8c09746](https://github.com/ydb-platform/ydb-embedded-ui/commit/8c09746b026a23a36fe31be94057cc92535aceaa))
53
+
3
54
  ## [1.8.8](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.8.7...v1.8.8) (2022-07-21)
4
55
 
5
56
 
@@ -0,0 +1,43 @@
1
+ @import '../../styles/mixins.scss';
2
+
3
+ .basic-node-viewer {
4
+ font-size: var(--yc-text-body-2-font-size);
5
+ line-height: var(--yc-text-body-2-line-height);
6
+
7
+ display: flex;
8
+ align-items: center;
9
+
10
+ margin: 15px 0;
11
+
12
+ &__title {
13
+ margin: 0 20px 0 0;
14
+
15
+ font-size: var(--yc-text-body-2-font-size);
16
+ font-weight: 600;
17
+ line-height: var(--yc-text-body-2-line-height);
18
+ text-transform: uppercase;
19
+ }
20
+
21
+ &__id {
22
+ margin: 0 15px 0 24px;
23
+ }
24
+
25
+ &__label {
26
+ margin-right: 10px;
27
+
28
+ font-size: var(--yc-text-body-2-font-size);
29
+ line-height: 18px;
30
+ white-space: nowrap;
31
+
32
+ color: var(--yc-color-text-hint);
33
+
34
+ .yc-root_theme_dark & {
35
+ color: var(--yc-color-text-hint);
36
+ }
37
+ }
38
+
39
+ &__link {
40
+ margin-left: 5px;
41
+ @extend .link;
42
+ }
43
+ }
@@ -0,0 +1,53 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import EntityStatus from '../EntityStatus/EntityStatus';
4
+ import Tags from '../Tags/Tags';
5
+ import Icon from '../Icon/Icon';
6
+
7
+ import './BasicNodeViewer.scss';
8
+
9
+ const b = cn('basic-node-viewer');
10
+
11
+ interface BasicNodeViewerProps {
12
+ node: any;
13
+ additionalNodesInfo?: any;
14
+ className?: string;
15
+ }
16
+
17
+ export const BasicNodeViewer = ({node, additionalNodesInfo, className}: BasicNodeViewerProps) => {
18
+ const nodeHref = additionalNodesInfo?.getNodeRef
19
+ ? additionalNodesInfo.getNodeRef(node) + 'internal'
20
+ : undefined;
21
+
22
+ return (
23
+ <div className={b(null, className)}>
24
+ {node ? (
25
+ <>
26
+ <div className={b('title')}>Node</div>
27
+ <EntityStatus status={node.SystemState} name={node.Host} />
28
+ {nodeHref && (
29
+ <a
30
+ rel="noopener noreferrer"
31
+ className={b('link', {external: true})}
32
+ href={nodeHref}
33
+ target="_blank"
34
+ >
35
+ <Icon name="external" />
36
+ </a>
37
+ )}
38
+
39
+ <div className={b('id')}>
40
+ <label className={b('label')}>NodeID</label>
41
+ <label>{node.NodeId}</label>
42
+ </div>
43
+
44
+ <Tags tags={[node.DataCenter]} />
45
+ <Tags tags={node.Roles} tagsType="blue" />
46
+ </>
47
+ ) : (
48
+ <div className="error">no data</div>
49
+ )}
50
+
51
+ </div>
52
+ );
53
+ };
@@ -0,0 +1 @@
1
+ export * from './BasicNodeViewer';
@@ -12,6 +12,8 @@ class EntityStatus extends React.Component {
12
12
  static propTypes = {
13
13
  status: PropTypes.string,
14
14
  name: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
15
+ onNameMouseEnter: PropTypes.func,
16
+ onNameMouseLeave: PropTypes.func,
15
17
  path: PropTypes.string,
16
18
  size: PropTypes.string,
17
19
  label: PropTypes.string,
@@ -49,19 +51,29 @@ class EntityStatus extends React.Component {
49
51
  );
50
52
  }
51
53
  renderLink() {
52
- const {externalLink, name, path} = this.props;
54
+ const {externalLink, name, path, onNameMouseEnter, onNameMouseLeave} = this.props;
53
55
 
54
56
  if (externalLink) {
55
57
  return <ExternalLink href={path}>{name}</ExternalLink>;
56
58
  }
57
59
 
58
60
  return path ? (
59
- <Link title={name} to={path}>
61
+ <Link
62
+ title={name}
63
+ to={path}
64
+ onMouseEnter={onNameMouseEnter}
65
+ onMouseLeave={onNameMouseLeave}
66
+ >
60
67
  {name}
61
68
  </Link>
62
69
  ) : (
63
70
  name && (
64
- <span className={b('name')} title={name}>
71
+ <span
72
+ className={b('name')}
73
+ title={name}
74
+ onMouseEnter={onNameMouseEnter}
75
+ onMouseLeave={onNameMouseLeave}
76
+ >
65
77
  {name}
66
78
  </span>
67
79
  )
@@ -3,11 +3,8 @@ import cn from 'bem-cn-lite';
3
3
  import PropTypes from 'prop-types';
4
4
 
5
5
  import InfoViewer from '../InfoViewer/InfoViewer';
6
- import EntityStatus from '../EntityStatus/EntityStatus';
7
6
  import ProgressViewer from '../ProgressViewer/ProgressViewer';
8
7
  import PoolUsage from '../PoolUsage/PoolUsage';
9
- import Tags from '../Tags/Tags';
10
- import Icon from '../Icon/Icon';
11
8
 
12
9
  import {LOAD_AVERAGE_TIME_INTERVALS} from '../../utils/constants';
13
10
  import {calcUptime} from '../../utils';
@@ -22,7 +19,6 @@ class FullNodeViewer extends React.Component {
22
19
  node: PropTypes.object.isRequired,
23
20
  backend: PropTypes.string,
24
21
  singleClusterMode: PropTypes.bool,
25
- additionalNodesInfo: PropTypes.object,
26
22
  };
27
23
 
28
24
  static defaultProps = {
@@ -30,10 +26,12 @@ class FullNodeViewer extends React.Component {
30
26
  };
31
27
 
32
28
  render() {
33
- const {node, className, additionalNodesInfo={}} = this.props;
34
- const nodeHref = additionalNodesInfo.getNodeRef
35
- ? additionalNodesInfo.getNodeRef(node) + 'internal'
36
- : undefined;
29
+ const {node, className} = this.props;
30
+
31
+ const endpointsInfo = node.Endpoints?.map(({Name, Address}) => ({
32
+ label: Name,
33
+ value: Address,
34
+ }));
37
35
 
38
36
  const commonInfo = [
39
37
  {label: 'Version', value: node.Version},
@@ -50,52 +48,35 @@ class FullNodeViewer extends React.Component {
50
48
  return (
51
49
  <div className={`${b()} ${className}`}>
52
50
  {node ? (
53
- <div>
54
- <div className={b('row')}>
55
- <div className={b('title')}>Node</div>
56
- <EntityStatus status={node.SystemState} name={node.Host} />
57
- {nodeHref && (
58
- <a
59
- rel="noopener noreferrer"
60
- className={b('link', {external: true})}
61
- href={nodeHref}
62
- target="_blank"
63
- >
64
- <Icon name="external" />
65
- </a>
66
- )}
67
-
68
- <div className={b('row', {id: true})}>
69
- <label className={b('label', {id: true})}>NodeID</label>
70
- <label>{node.NodeId}</label>
51
+ <div className={b('common-info')}>
52
+ <div>
53
+ <div className={b('section-title')}>Pools</div>
54
+ <div className={b('section', {pools: true})}>
55
+ {node.PoolStats.map((pool, poolIndex) => (
56
+ <PoolUsage key={poolIndex} data={pool} />
57
+ ))}
71
58
  </div>
72
-
73
- <Tags tags={[node.DataCenter]} />
74
- <Tags tags={node.Roles} tagsType="blue" />
75
59
  </div>
76
60
 
77
- <div className={b('common-info')}>
78
- <div>
79
- <div className={b('section-title')}>Pools</div>
80
- <div className={b('section', {pools: true})}>
81
- {node.PoolStats.map((pool, poolIndex) => (
82
- <PoolUsage key={poolIndex} data={pool} />
83
- ))}
84
- </div>
85
- </div>
86
-
61
+ {endpointsInfo && endpointsInfo.length && (
87
62
  <InfoViewer
88
- title="Common info"
63
+ title="Endpoints"
89
64
  className={b('section')}
90
- info={commonInfo}
65
+ info={endpointsInfo}
91
66
  />
92
-
93
- <InfoViewer
94
- title="Load average"
95
- className={b('section', {average: true})}
96
- info={averageInfo}
97
- />
98
- </div>
67
+ )}
68
+
69
+ <InfoViewer
70
+ title="Common info"
71
+ className={b('section')}
72
+ info={commonInfo}
73
+ />
74
+
75
+ <InfoViewer
76
+ title="Load average"
77
+ className={b('section', {average: true})}
78
+ info={averageInfo}
79
+ />
99
80
  </div>
100
81
  ) : (
101
82
  <div className="error">no data</div>
@@ -4,26 +4,6 @@
4
4
  font-size: var(--yc-text-body-2-font-size);
5
5
  line-height: var(--yc-text-body-2-line-height);
6
6
 
7
- &__title {
8
- margin: 0 20px 0 0;
9
-
10
- font-size: var(--yc-text-body-2-font-size);
11
- font-weight: 600;
12
- line-height: var(--yc-text-body-2-line-height);
13
- text-transform: uppercase;
14
- }
15
-
16
- &__row {
17
- display: flex;
18
- align-items: center;
19
-
20
- margin: 15px 0;
21
-
22
- &_id {
23
- margin: 0 15px 0 24px;
24
- }
25
- }
26
-
27
7
  &__common-info {
28
8
  display: flex;
29
9
  flex-direction: column;
@@ -46,26 +26,6 @@
46
26
  min-width: 60px;
47
27
  }
48
28
 
49
- &__label {
50
- min-width: 100px;
51
- margin-right: 25px;
52
-
53
- font-size: var(--yc-text-body-2-font-size);
54
- line-height: 18px;
55
- white-space: nowrap;
56
-
57
- color: var(--yc-color-text-hint);
58
-
59
- .yc-root_theme_dark & {
60
- color: var(--yc-color-text-hint);
61
- }
62
-
63
- &_id {
64
- min-width: auto;
65
- margin-right: 10px;
66
- }
67
- }
68
-
69
29
  &__section-title {
70
30
  margin: 15px 0 10px;
71
31
 
@@ -73,9 +33,4 @@
73
33
  font-weight: 600;
74
34
  line-height: var(--yc-text-body-2-line-height);
75
35
  }
76
-
77
- &__link {
78
- margin-left: 5px;
79
- @extend .link;
80
- }
81
36
  }
@@ -0,0 +1,52 @@
1
+ import type {TEvDescribeSchemeResult, TIndexDescription} from '../../types/api/schema';
2
+ import {InfoViewer, createInfoFormatter} from '../InfoViewer';
3
+
4
+ const DISPLAYED_FIELDS: Set<keyof TIndexDescription> = new Set([
5
+ 'Type',
6
+ 'State',
7
+ 'DataSize',
8
+ 'KeyColumnNames',
9
+ 'DataColumnNames',
10
+ ]);
11
+
12
+ const formatItem = createInfoFormatter<TIndexDescription>({
13
+ Type: (value) => value?.substring(10), // trims EIndexType prefix
14
+ State: (value) => value?.substring(11), // trims EIndexState prefix
15
+ KeyColumnNames: (value) => value?.join(', '),
16
+ DataColumnNames: (value) => value?.join(', '),
17
+ }, {
18
+ KeyColumnNames: 'Columns',
19
+ DataColumnNames: 'Includes',
20
+ });
21
+
22
+ interface IndexInfoViewerProps {
23
+ data?: TEvDescribeSchemeResult;
24
+ }
25
+
26
+ export const IndexInfoViewer = ({data}: IndexInfoViewerProps) => {
27
+ if (!data) {
28
+ return (
29
+ <div className="error">no index data</div>
30
+ );
31
+ }
32
+
33
+ const TableIndex = data.PathDescription?.TableIndex;
34
+ const info: Array<{label?: string, value?: unknown}> = [];
35
+
36
+ let key: keyof TIndexDescription;
37
+ for (key in TableIndex) {
38
+ if (DISPLAYED_FIELDS.has(key)) {
39
+ info.push(formatItem(key, TableIndex?.[key]));
40
+ }
41
+ }
42
+
43
+ return (
44
+ <>
45
+ {info.length ? (
46
+ <InfoViewer info={info}></InfoViewer>
47
+ ) : (
48
+ <>Empty</>
49
+ )}
50
+ </>
51
+ );
52
+ };
@@ -0,0 +1,4 @@
1
+ import InfoViewer from './InfoViewer';
2
+
3
+ export {InfoViewer};
4
+ export * from './utils';
@@ -0,0 +1,32 @@
1
+ type LabelMap<T> = {
2
+ [label in keyof T]?: string;
3
+ }
4
+
5
+ type FieldMappers<T> = {
6
+ [label in keyof T]?: (value: T[label]) => string | undefined;
7
+ }
8
+
9
+ function formatLabel<Shape>(label: keyof Shape, map: LabelMap<Shape>) {
10
+ return map[label] ?? label;
11
+ }
12
+
13
+ function formatValue<Shape, Key extends keyof Shape>(
14
+ label: Key,
15
+ value: Shape[Key],
16
+ mappers: FieldMappers<Shape>,
17
+ ) {
18
+ const mapper = mappers[label];
19
+ const mappedValue = mapper ? mapper(value) : value;
20
+
21
+ return String(mappedValue ?? '');
22
+ }
23
+
24
+ export function createInfoFormatter<Shape extends Record<string, any>>(
25
+ fieldMappers?: FieldMappers<Shape>,
26
+ labelMap?: LabelMap<Shape>,
27
+ ) {
28
+ return <Key extends keyof Shape>(label: Key, value: Shape[Key]) => ({
29
+ label: formatLabel(label, labelMap || {}),
30
+ value: formatValue(label, value, fieldMappers || {}),
31
+ });
32
+ }
@@ -76,7 +76,7 @@ export class ProgressViewer extends React.Component {
76
76
 
77
77
  if (!isNaN(fillWidth)) {
78
78
  return (
79
- <div className={b({size})}>
79
+ <div className={b({size}, className)}>
80
80
  <div className={b('line', {bg})} style={lineStyle}></div>
81
81
  <span className={b('text', {text})}>
82
82
  {`${valueText} ${divider} ${capacityText}`}
@@ -4,6 +4,10 @@
4
4
  overflow: auto;
5
5
  @include flex-container();
6
6
 
7
+ &__header {
8
+ margin: 16px 20px;
9
+ }
10
+
7
11
  &__content {
8
12
  position: relative;
9
13
 
@@ -19,7 +23,7 @@
19
23
  }
20
24
 
21
25
  &__tabs {
22
- padding: 16px 20px 0;
26
+ padding: 0 20px;
23
27
  }
24
28
 
25
29
  &__tab {
@@ -13,6 +13,7 @@ import Storage from '../Storage/Storage';
13
13
  import NodeOverview from './NodeOverview/NodeOverview';
14
14
  import NodeStructure from './NodeStructure/NodeStructure';
15
15
  import Loader from '../../components/Loader/Loader';
16
+ import {BasicNodeViewer} from '../../components/BasicNodeViewer';
16
17
 
17
18
  import {getNodeInfo, resetNode} from '../../store/reducers/node';
18
19
  import routes, {CLUSTER_PAGES, createHref} from '../../routes';
@@ -133,7 +134,6 @@ function Node(props: NodeProps) {
133
134
  case OVERVIEW: {
134
135
  return (
135
136
  <NodeOverview
136
- additionalNodesInfo={additionalNodesInfo}
137
137
  node={node}
138
138
  className={b('overview-wrapper')}
139
139
  />
@@ -162,6 +162,12 @@ function Node(props: NodeProps) {
162
162
  if (node) {
163
163
  return (
164
164
  <div className={b(null, props.className)}>
165
+ <BasicNodeViewer
166
+ node={node}
167
+ additionalNodesInfo={props.additionalNodesInfo}
168
+ className={b('header')}
169
+ />
170
+
165
171
  {renderTabs()}
166
172
 
167
173
  <div className={b('content')}>{renderTabContent()}</div>
@@ -5,16 +5,14 @@ import {backend} from '../../../store';
5
5
 
6
6
  interface NodeOverviewProps {
7
7
  node: any;
8
- additionalNodesInfo: any;
9
8
  className?: string;
10
9
  }
11
10
 
12
- function NodeOverview({node, additionalNodesInfo, className}: NodeOverviewProps) {
11
+ function NodeOverview({node, className}: NodeOverviewProps) {
13
12
  return (
14
13
  <FullNodeViewer
15
14
  node={node}
16
15
  backend={backend}
17
- additionalNodesInfo={additionalNodesInfo}
18
16
  className={className}
19
17
  />
20
18
  );
@@ -44,9 +44,38 @@
44
44
  &__pdisk-title-wrapper {
45
45
  display: flex;
46
46
  align-items: center;
47
- gap: 8px;
47
+ gap: 16px;
48
48
 
49
49
  font-weight: 600;
50
+
51
+ .entity-status__status-icon {
52
+ margin-right: 0;
53
+ }
54
+ }
55
+
56
+ &__pdisk-title-item {
57
+ display: flex;
58
+ gap: 4px;
59
+
60
+ &-label {
61
+ font-weight: 400;
62
+
63
+ color: var(--yc-color-text-secondary);
64
+ }
65
+ }
66
+
67
+ &__pdisk-title-id {
68
+ min-width: 110px;
69
+ }
70
+
71
+ &__pdisk-title-type {
72
+ justify-content: flex-end;
73
+
74
+ min-width: 50px;
75
+ }
76
+
77
+ &__pdisk-title-size {
78
+ min-width: 150px;
50
79
  }
51
80
 
52
81
  &__pdisk-details {
@@ -0,0 +1,25 @@
1
+ import {ReactNode} from 'react';
2
+ import cn from 'bem-cn-lite';
3
+
4
+ const b = cn('kv-node-structure');
5
+
6
+ interface PDiskTitleBadgeProps {
7
+ label?: string;
8
+ value: ReactNode;
9
+ className?: string;
10
+ }
11
+
12
+ export function PDiskTitleBadge({label, value, className}: PDiskTitleBadgeProps) {
13
+ return (
14
+ <span className={b('pdisk-title-item', className)}>
15
+ {label && (
16
+ <span className={b('pdisk-title-item-label')}>
17
+ {label}:
18
+ </span>
19
+ )}
20
+ <span className={b('pdisk-title-item-value')}>
21
+ {value}
22
+ </span>
23
+ </span>
24
+ );
25
+ }
@@ -14,9 +14,11 @@ import {Vdisk} from './Vdisk';
14
14
 
15
15
  import {bytesToGB, pad9} from '../../../utils/utils';
16
16
  import {formatStorageValuesToGb} from '../../../utils';
17
+ import {getPDiskType} from '../../../utils/pdisk';
17
18
 
18
19
  import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
19
20
  import {valueIsDefined} from './NodeStructure';
21
+ import {PDiskTitleBadge} from './PDiskTitleBadge';
20
22
 
21
23
  const b = cn('kv-node-structure');
22
24
 
@@ -230,6 +232,7 @@ export function PDisk(props: PDiskProps) {
230
232
  }
231
233
  if (valueIsDefined(Category)) {
232
234
  pdiskInfo.push({label: 'Category', value: Category});
235
+ pdiskInfo.push({label: 'Type', value: getPDiskType(data)});
233
236
  }
234
237
  pdiskInfo.push({
235
238
  label: 'Allocated Size',
@@ -286,8 +289,27 @@ export function PDisk(props: PDiskProps) {
286
289
  <div className={b('pdisk')} id={props.id}>
287
290
  <div className={b('pdisk-header')}>
288
291
  <div className={b('pdisk-title-wrapper')}>
289
- <span>{data.Path}</span>
290
- <EntityStatus status={data.Device} name={`${data.NodeId}-${data.PDiskId}`} />
292
+ <EntityStatus status={data.Device} />
293
+ <PDiskTitleBadge
294
+ label="PDiskID"
295
+ value={data.PDiskId}
296
+ className={b('pdisk-title-id')}
297
+ />
298
+ <PDiskTitleBadge
299
+ value={getPDiskType(data)}
300
+ className={b('pdisk-title-type')}
301
+ />
302
+ <ProgressViewer
303
+ value={data.TotalSize - data.AvailableSize}
304
+ capacity={data.TotalSize}
305
+ formatValues={formatStorageValuesToGb}
306
+ colorizeProgress={true}
307
+ className={b('pdisk-title-size')}
308
+ />
309
+ <PDiskTitleBadge
310
+ label="VDisks"
311
+ value={data.vDisks.length}
312
+ />
291
313
  </div>
292
314
  <Button onClick={unfolded ? onClosePDiskDetails : onOpenPDiskDetails} view="flat-secondary">
293
315
  <ArrowToggle direction={unfolded ? 'top' : 'bottom'} />
@@ -63,6 +63,7 @@ class Nodes extends React.Component {
63
63
  }
64
64
 
65
65
  componentWillUnmount() {
66
+ this.props.hideTooltip();
66
67
  clearInterval(this.reloadDescriptor);
67
68
  }
68
69