ydb-embedded-ui 4.0.0 → 4.2.0

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 (57) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/components/ClusterInfo/ClusterInfo.tsx +3 -3
  3. package/dist/components/LabelWithPopover/LabelWithPopover.tsx +10 -4
  4. package/dist/{containers/Nodes/NodesTable.scss → components/NodeHostWrapper/NodeHostWrapper.scss} +4 -6
  5. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +60 -0
  6. package/dist/components/TabletsStatistic/TabletsStatistic.scss +1 -1
  7. package/dist/containers/App/App.scss +7 -4
  8. package/dist/containers/AsideNavigation/AsideNavigation.tsx +1 -11
  9. package/dist/containers/Header/Header.tsx +1 -1
  10. package/dist/containers/Nodes/getNodesColumns.tsx +7 -46
  11. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +3 -12
  12. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +0 -24
  13. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +2 -39
  14. package/dist/containers/Storage/VDisk/VDisk.tsx +4 -11
  15. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +13 -16
  16. package/dist/containers/Storage/utils/types.ts +2 -1
  17. package/dist/containers/Tablet/Tablet.scss +4 -0
  18. package/dist/containers/Tablet/TabletTable/TabletTable.tsx +28 -6
  19. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +1 -1
  20. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +4 -3
  21. package/dist/containers/Tenant/QueryEditor/Issues/Issues.scss +1 -1
  22. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +1 -1
  23. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +1 -1
  24. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +12 -0
  25. package/dist/containers/Tenants/Tenants.js +1 -1
  26. package/dist/containers/UserSettings/UserSettings.tsx +19 -17
  27. package/dist/services/api.ts +383 -0
  28. package/dist/store/reducers/{cluster.js → cluster/cluster.ts} +9 -14
  29. package/dist/store/reducers/cluster/types.ts +13 -0
  30. package/dist/store/reducers/executeTopQueries.ts +2 -2
  31. package/dist/store/reducers/index.ts +5 -4
  32. package/dist/store/reducers/node.js +5 -1
  33. package/dist/store/reducers/nodesList.ts +2 -7
  34. package/dist/store/reducers/settings.js +1 -14
  35. package/dist/store/reducers/storage.js +12 -0
  36. package/dist/store/reducers/tablet.ts +16 -2
  37. package/dist/store/reducers/{tenants.js → tenants/tenants.ts} +14 -9
  38. package/dist/store/reducers/tenants/types.ts +17 -0
  39. package/dist/store/utils.ts +3 -2
  40. package/dist/types/api/acl.ts +25 -0
  41. package/dist/types/api/cluster.ts +3 -0
  42. package/dist/types/api/compute.ts +5 -3
  43. package/dist/types/api/netInfo.ts +48 -0
  44. package/dist/types/api/nodes.ts +5 -3
  45. package/dist/types/api/pdisk.ts +11 -2
  46. package/dist/types/api/storage.ts +5 -3
  47. package/dist/types/api/tenant.ts +18 -3
  48. package/dist/types/api/vdisk.ts +10 -2
  49. package/dist/types/api/whoami.ts +19 -0
  50. package/dist/types/store/tablet.ts +1 -0
  51. package/dist/types/window.d.ts +5 -0
  52. package/dist/utils/createToast.tsx +2 -2
  53. package/dist/utils/hooks/useTypedSelector.ts +2 -2
  54. package/dist/utils/nodes.ts +14 -1
  55. package/package.json +4 -4
  56. package/dist/services/api.d.ts +0 -87
  57. package/dist/services/api.js +0 -278
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.1.0...v4.2.0) (2023-05-16)
4
+
5
+
6
+ ### Features
7
+
8
+ * **Tablet:** display node fqdn in table ([4d8099a](https://github.com/ydb-platform/ydb-embedded-ui/commit/4d8099a454f34fc76886b26ca948895171c57ab8))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **api:** change nulls to empty objects ([0ab14e8](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ab14e883a47aeac2f2bab437f2214a32ccb1c9b))
14
+ * display storage pool in VDisks popups ([5b5dd8a](https://github.com/ydb-platform/ydb-embedded-ui/commit/5b5dd8a4e6cb4bcc1ead78a7c06d2e80a81424cc))
15
+ * fix Select label and values align ([f796730](https://github.com/ydb-platform/ydb-embedded-ui/commit/f7967309fe4a042e7637de212f33b1ebfc6877fc))
16
+ * **Overview:** partitioning by size disabled for 0 SizeToSpit ([1028e7d](https://github.com/ydb-platform/ydb-embedded-ui/commit/1028e7d8d3566f5f5e6b2ebe04112ef135d7b55e))
17
+ * **Schema:** display NotNull columns ([d61eaa4](https://github.com/ydb-platform/ydb-embedded-ui/commit/d61eaa4ccff357c1e9ca6efde855ec46be24a314))
18
+
19
+ ## [4.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.0.0...v4.1.0) (2023-05-10)
20
+
21
+
22
+ ### Features
23
+
24
+ * **Navigation:** remove legacy navigation setting support ([8544f11](https://github.com/ydb-platform/ydb-embedded-ui/commit/8544f114255ba44834d38cd9e709450c49e4a96a))
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * disable link and popover for unavailable nodes ([990a9fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/990a9fa42a7133a6c40d07e11c3518240e18b4a9))
30
+
3
31
  ## [4.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.5.0...v4.0.0) (2023-04-28)
4
32
 
5
33
 
@@ -15,7 +15,7 @@ import {Tablet} from '../Tablet';
15
15
  //@ts-ignore
16
16
  import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
17
17
  //@ts-ignore
18
- import {getClusterInfo} from '../../store/reducers/cluster';
18
+ import {getClusterInfo} from '../../store/reducers/cluster/cluster';
19
19
  //@ts-ignore
20
20
  import {clusterName, backend, customBackend} from '../../store';
21
21
 
@@ -68,6 +68,8 @@ class ClusterInfo extends React.Component<ClusterInfoProps> {
68
68
  return 0;
69
69
  }
70
70
 
71
+ private autofetcher: any;
72
+
71
73
  componentDidMount() {
72
74
  const {setHeader} = this.props;
73
75
  setHeader([
@@ -107,8 +109,6 @@ class ClusterInfo extends React.Component<ClusterInfoProps> {
107
109
  return <div className={b(null, className)}>{helper || this.renderContent()}</div>;
108
110
  }
109
111
 
110
- private autofetcher: any;
111
-
112
112
  private getInfo() {
113
113
  const {cluster = {}, additionalClusterInfo = [], singleClusterMode} = this.props;
114
114
  const {StorageTotal, StorageUsed} = cluster;
@@ -3,14 +3,20 @@ import type {ReactNode} from 'react';
3
3
  import {HelpPopover} from '@gravity-ui/uikit';
4
4
 
5
5
  interface LabelWithPopoverProps {
6
- text: string;
6
+ text: ReactNode;
7
7
  popoverContent: ReactNode;
8
8
  className?: string;
9
+ contentClassName?: string;
9
10
  }
10
11
 
11
- export const LabelWithPopover = ({text, popoverContent, className}: LabelWithPopoverProps) => (
12
+ export const LabelWithPopover = ({
13
+ text,
14
+ popoverContent,
15
+ className,
16
+ contentClassName,
17
+ }: LabelWithPopoverProps) => (
12
18
  <div className={className}>
13
- {text}
14
- <HelpPopover content={popoverContent} />
19
+ {text + '\u00a0'}
20
+ <HelpPopover content={popoverContent} contentClassName={contentClassName} />
15
21
  </div>
16
22
  );
@@ -1,12 +1,10 @@
1
- .ydb-nodes-table {
2
- &__host-field-wrapper {
3
- display: flex;
4
- }
1
+ .ydb-node-host-wrapper {
2
+ display: flex;
5
3
 
6
4
  &__host-wrapper {
7
5
  display: flex;
8
6
 
9
- max-width: 330px;
7
+ width: 330px;
10
8
  }
11
9
 
12
10
  &__host {
@@ -21,7 +19,7 @@
21
19
  }
22
20
 
23
21
  .data-table__row:hover {
24
- .ydb-nodes-table__external-button {
22
+ .ydb-node-host-wrapper__external-button {
25
23
  display: inline-flex;
26
24
  }
27
25
  }
@@ -0,0 +1,60 @@
1
+ import block from 'bem-cn-lite';
2
+
3
+ import {Button, Popover, PopoverBehavior} from '@gravity-ui/uikit';
4
+
5
+ import type {INodesPreparedEntity} from '../../types/store/nodes';
6
+ import {getDefaultNodePath} from '../../containers/Node/NodePages';
7
+ import {isUnavailableNode, NodeAddress} from '../../utils/nodes';
8
+
9
+ import EntityStatus from '../EntityStatus/EntityStatus';
10
+ import {NodeEndpointsTooltip} from '../Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip';
11
+ import {IconWrapper} from '../Icon';
12
+
13
+ import './NodeHostWrapper.scss';
14
+
15
+ const b = block('ydb-node-host-wrapper');
16
+
17
+ interface NodeHostWrapperProps {
18
+ node: INodesPreparedEntity;
19
+ getNodeRef?: (node?: NodeAddress) => string;
20
+ }
21
+
22
+ export const NodeHostWrapper = ({node, getNodeRef}: NodeHostWrapperProps) => {
23
+ if (!node.Host) {
24
+ return <span>—</span>;
25
+ }
26
+
27
+ const isNodeAvailable = !isUnavailableNode(node);
28
+ const nodeRef = isNodeAvailable && getNodeRef ? getNodeRef(node) + 'internal' : undefined;
29
+
30
+ return (
31
+ <div className={b()}>
32
+ <Popover
33
+ disabled={!isNodeAvailable}
34
+ content={<NodeEndpointsTooltip data={node} />}
35
+ placement={['top', 'bottom']}
36
+ behavior={PopoverBehavior.Immediate}
37
+ >
38
+ <div className={b('host-wrapper')}>
39
+ <EntityStatus
40
+ name={node.Host}
41
+ status={node.SystemState}
42
+ path={isNodeAvailable ? getDefaultNodePath(node.NodeId) : undefined}
43
+ hasClipboardButton
44
+ className={b('host')}
45
+ />
46
+ {nodeRef && (
47
+ <Button
48
+ size="s"
49
+ href={nodeRef}
50
+ className={b('external-button')}
51
+ target="_blank"
52
+ >
53
+ <IconWrapper name="external" />
54
+ </Button>
55
+ )}
56
+ </div>
57
+ </Popover>
58
+ </div>
59
+ );
60
+ };
@@ -24,7 +24,7 @@
24
24
  background-color: var(--yc-color-base-positive);
25
25
  }
26
26
  &_state_yellow {
27
- color: var(--yc-color-text-warning-medium);
27
+ color: var(--yc-color-text-warning);
28
28
  background-color: var(--yc-color-base-warning);
29
29
  }
30
30
  &_state_blue {
@@ -34,10 +34,6 @@ body,
34
34
  --ydb-data-table-color-hover: var(--yc-color-base-float-hover);
35
35
  }
36
36
 
37
- .yc-select__label {
38
- font-weight: 600;
39
- }
40
-
41
37
  :is(#tab, .yc-tabs-item_active .yc-tabs-item__title) {
42
38
  color: var(--yc-color-text-primary) !important;
43
39
  }
@@ -110,10 +106,17 @@ body,
110
106
  align-items: center;
111
107
  }
112
108
 
109
+ // Should be removed after https://github.com/ydb-platform/ydb-embedded-ui/issues/344
113
110
  .yc-button__text {
114
111
  display: flex;
115
112
  align-items: center;
116
113
  }
114
+
115
+ .g-select {
116
+ .yc-button__text {
117
+ align-items: baseline;
118
+ }
119
+ }
117
120
  }
118
121
 
119
122
  .error {
@@ -1,4 +1,4 @@
1
- import React, {useEffect, useState} from 'react';
1
+ import React, {useState} from 'react';
2
2
  import {connect} from 'react-redux';
3
3
  import {useLocation} from 'react-router';
4
4
  import {useHistory} from 'react-router-dom';
@@ -170,16 +170,6 @@ function AsideNavigation(props: AsideNavigationProps) {
170
170
  props.setSettingValue(ASIDE_HEADER_COMPACT_KEY, JSON.stringify(compact));
171
171
  };
172
172
 
173
- // navigation managed its compact state internally before, and its approach is not compatible with settings
174
- // to migrate, save the incoming value again; save only `false` because `true` is the default value
175
- // assume it is safe to remove this code block if it is at least a few months old
176
- // there a two of these, search for a similar comment
177
- useEffect(() => {
178
- if (props.compact === false) {
179
- setIsCompact(props.compact);
180
- }
181
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
182
-
183
173
  const menuItems: AsideHeaderMenuItem[] = React.useMemo(() => {
184
174
  const {pathname} = location;
185
175
  const isClusterPage = pathname === '/cluster';
@@ -8,7 +8,7 @@ import Divider from '../../components/Divider/Divider';
8
8
  import {Icon} from '../../components/Icon';
9
9
 
10
10
  import {clusterName as clusterNameLocation, backend, customBackend} from '../../store';
11
- import {getClusterInfo} from '../../store/reducers/cluster';
11
+ import {getClusterInfo} from '../../store/reducers/cluster/cluster';
12
12
  import {getHostInfo} from '../../store/reducers/host';
13
13
  import {HeaderItemType} from '../../store/reducers/header';
14
14
 
@@ -1,29 +1,22 @@
1
- import cn from 'bem-cn-lite';
2
1
  import DataTable, {Column} from '@gravity-ui/react-data-table';
3
- import {Button, Popover, PopoverBehavior} from '@gravity-ui/uikit';
2
+ import {Popover} from '@gravity-ui/uikit';
4
3
 
5
- import {IconWrapper} from '../../components/Icon';
6
- import EntityStatus from '../../components/EntityStatus/EntityStatus';
7
4
  import PoolsGraph from '../../components/PoolsGraph/PoolsGraph';
8
5
  import ProgressViewer from '../../components/ProgressViewer/ProgressViewer';
9
6
  import {TabletsStatistic} from '../../components/TabletsStatistic';
10
- import {NodeEndpointsTooltip} from '../../components/Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip';
7
+ import {NodeHostWrapper} from '../../components/NodeHostWrapper/NodeHostWrapper';
11
8
 
9
+ import type {NodeAddress} from '../../utils/nodes';
12
10
  import {formatBytesToGigabyte} from '../../utils/index';
13
- import {INodesPreparedEntity} from '../../types/store/nodes';
14
- import {showTooltip as externalShowTooltip} from '../../store/reducers/tooltip';
15
-
16
- import {getDefaultNodePath} from '../Node/NodePages';
17
-
18
- import './NodesTable.scss';
19
11
 
20
- const b = cn('ydb-nodes-table');
12
+ import type {INodesPreparedEntity} from '../../types/store/nodes';
13
+ import {showTooltip as externalShowTooltip} from '../../store/reducers/tooltip';
21
14
 
22
15
  interface GetNodesColumnsProps {
23
16
  showTooltip: (...args: Parameters<typeof externalShowTooltip>) => void;
24
17
  hideTooltip: VoidFunction;
25
18
  tabletsPath?: string;
26
- getNodeRef?: Function;
19
+ getNodeRef?: (node?: NodeAddress) => string;
27
20
  }
28
21
 
29
22
  export function getNodesColumns({
@@ -42,39 +35,7 @@ export function getNodesColumns({
42
35
  {
43
36
  name: 'Host',
44
37
  render: ({row}) => {
45
- const nodeRef = getNodeRef ? getNodeRef(row) + 'internal' : undefined;
46
- if (typeof row.Host === 'undefined') {
47
- return <span>—</span>;
48
- }
49
- return (
50
- <div className={b('host-field-wrapper')}>
51
- <Popover
52
- content={<NodeEndpointsTooltip data={row} />}
53
- placement={['top', 'bottom']}
54
- behavior={PopoverBehavior.Immediate}
55
- >
56
- <div className={b('host-wrapper')}>
57
- <EntityStatus
58
- name={row.Host}
59
- status={row.SystemState}
60
- path={getDefaultNodePath(row.NodeId)}
61
- hasClipboardButton
62
- className={b('host')}
63
- />
64
- {nodeRef && (
65
- <Button
66
- size="s"
67
- href={nodeRef}
68
- className={b('external-button')}
69
- target="_blank"
70
- >
71
- <IconWrapper name="external" />
72
- </Button>
73
- )}
74
- </div>
75
- </Popover>
76
- </div>
77
- );
38
+ return <NodeHostWrapper node={row} getNodeRef={getNodeRef} />;
78
39
  },
79
40
  width: '350px',
80
41
  align: DataTable.LEFT,
@@ -256,18 +256,14 @@ function StorageGroups({
256
256
  name: TableColumnsIds.VDisks,
257
257
  className: b('vdisks-column'),
258
258
  header: tableColumnsNames[TableColumnsIds.VDisks],
259
- render: ({value, row}) => (
259
+ render: ({value}) => (
260
260
  <div className={b('vdisks-wrapper')}>
261
261
  {_.map(value as TVDiskStateInfo[], (el) => {
262
262
  const donors = el.Donors;
263
263
 
264
264
  return donors && donors.length > 0 ? (
265
265
  <Stack className={b('vdisks-item')} key={stringifyVdiskId(el.VDiskId)}>
266
- <VDisk
267
- data={el}
268
- poolName={row[TableColumnsIds.PoolName]}
269
- nodes={nodes}
270
- />
266
+ <VDisk data={el} nodes={nodes} />
271
267
  {donors.map((donor) => {
272
268
  const isFullData = isFullVDiskData(donor);
273
269
 
@@ -275,7 +271,6 @@ function StorageGroups({
275
271
  <VDisk
276
272
  data={isFullData ? donor : {...donor, DonorMode: true}}
277
273
  // donor and acceptor are always in the same group
278
- poolName={row[TableColumnsIds.PoolName]}
279
274
  nodes={nodes}
280
275
  key={stringifyVdiskId(
281
276
  isFullData ? donor.VDiskId : donor,
@@ -286,11 +281,7 @@ function StorageGroups({
286
281
  </Stack>
287
282
  ) : (
288
283
  <div className={b('vdisks-item')} key={stringifyVdiskId(el.VDiskId)}>
289
- <VDisk
290
- data={el}
291
- poolName={row[TableColumnsIds.PoolName]}
292
- nodes={nodes}
293
- />
284
+ <VDisk data={el} nodes={nodes} />
294
285
  </div>
295
286
  );
296
287
  })}
@@ -20,18 +20,6 @@
20
20
  margin-right: 0px;
21
21
  }
22
22
  }
23
- &__fqdn-field-wrapper {
24
- width: 330px;
25
- }
26
- &__fqdn-wrapper {
27
- display: flex;
28
- align-items: center;
29
-
30
- max-width: 330px;
31
- }
32
- &__fqdn {
33
- overflow: hidden;
34
- }
35
23
 
36
24
  &__group-id {
37
25
  font-weight: 500;
@@ -40,16 +28,4 @@
40
28
  &__node_unavailable {
41
29
  opacity: 0.6;
42
30
  }
43
-
44
- &__external-button {
45
- display: none;
46
-
47
- margin-left: 4px;
48
- }
49
- }
50
-
51
- .data-table__row:hover {
52
- .global-storage-nodes__external-button {
53
- display: inline-flex;
54
- }
55
31
  }
@@ -2,11 +2,6 @@ import _ from 'lodash';
2
2
  import cn from 'bem-cn-lite';
3
3
 
4
4
  import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
5
- import {Button, Popover, PopoverBehavior} from '@gravity-ui/uikit';
6
-
7
- import {NodeEndpointsTooltip} from '../../../components/Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip';
8
- import EntityStatus from '../../../components/EntityStatus/EntityStatus';
9
- import {IconWrapper} from '../../../components/Icon';
10
5
 
11
6
  import {VisibleEntities} from '../../../store/reducers/storage';
12
7
  import {
@@ -15,7 +10,7 @@ import {
15
10
  NodesUptimeFilterValues,
16
11
  } from '../../../utils/nodes';
17
12
 
18
- import {getDefaultNodePath} from '../../Node/NodePages';
13
+ import {NodeHostWrapper} from '../../../components/NodeHostWrapper/NodeHostWrapper';
19
14
 
20
15
  import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
21
16
  import {PDisk} from '../PDisk';
@@ -100,39 +95,7 @@ function StorageNodes({
100
95
  header: tableColumnsNames[TableColumnsIds.FQDN],
101
96
  width: 350,
102
97
  render: ({row}) => {
103
- const nodeRef = getNodeRef ? getNodeRef(row) + 'internal' : undefined;
104
- if (!row.Host) {
105
- return <span>—</span>;
106
- }
107
- return (
108
- <div className={b('fqdn-field-wrapper')}>
109
- <Popover
110
- content={<NodeEndpointsTooltip data={row} />}
111
- placement={['top', 'bottom']}
112
- behavior={PopoverBehavior.Immediate}
113
- >
114
- <div className={b('fqdn-wrapper')}>
115
- <EntityStatus
116
- name={row.Host}
117
- showStatus={false}
118
- path={getDefaultNodePath(row.NodeId)}
119
- hasClipboardButton
120
- className={b('fqdn')}
121
- />
122
- {nodeRef && (
123
- <Button
124
- size="s"
125
- href={nodeRef}
126
- className={b('external-button')}
127
- target="_blank"
128
- >
129
- <IconWrapper name="external" />
130
- </Button>
131
- )}
132
- </div>
133
- </Popover>
134
- </div>
135
- );
98
+ return <NodeHostWrapper node={row} getNodeRef={getNodeRef} />;
136
99
  },
137
100
  align: DataTable.LEFT,
138
101
  },
@@ -16,7 +16,7 @@ import {STRUCTURE} from '../../Node/NodePages';
16
16
  import {DiskStateProgressBar, EDiskStateSeverity} from '../DiskStateProgressBar';
17
17
  import {VDiskPopup} from '../VDiskPopup';
18
18
 
19
- import type {IUnavailableDonor} from '../utils/types';
19
+ import type {UnavailableDonor} from '../utils/types';
20
20
  import {NOT_AVAILABLE_SEVERITY} from '../utils';
21
21
 
22
22
  import './VDisk.scss';
@@ -49,13 +49,12 @@ const getColorSeverity = (color?: EFlag) => {
49
49
  };
50
50
 
51
51
  interface VDiskProps {
52
- data?: TVDiskStateInfo | IUnavailableDonor;
53
- poolName?: string;
52
+ data?: TVDiskStateInfo | UnavailableDonor;
54
53
  nodes?: NodesMap;
55
54
  compact?: boolean;
56
55
  }
57
56
 
58
- export const VDisk = ({data = {}, poolName, nodes, compact}: VDiskProps) => {
57
+ export const VDisk = ({data = {}, nodes, compact}: VDiskProps) => {
59
58
  const isFullData = isFullVDiskData(data);
60
59
 
61
60
  const [severity, setSeverity] = useState(
@@ -125,13 +124,7 @@ export const VDisk = ({data = {}, poolName, nodes, compact}: VDiskProps) => {
125
124
 
126
125
  return (
127
126
  <React.Fragment>
128
- <VDiskPopup
129
- data={data}
130
- poolName={poolName}
131
- nodes={nodes}
132
- anchorRef={anchor}
133
- open={isPopupVisible}
134
- />
127
+ <VDiskPopup data={data} nodes={nodes} anchorRef={anchor} open={isPopupVisible} />
135
128
  <div className={b()} ref={anchor} onMouseEnter={showPopup} onMouseLeave={hidePopup}>
136
129
  {data.NodeId && isFullData ? (
137
130
  <InternalLink
@@ -13,7 +13,7 @@ import {stringifyVdiskId} from '../../../utils';
13
13
  import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
14
14
  import {isFullVDiskData} from '../../../utils/storage';
15
15
 
16
- import type {IUnavailableDonor} from '../utils/types';
16
+ import type {UnavailableDonor} from '../utils/types';
17
17
 
18
18
  import {preparePDiskData} from '../PDiskPopup';
19
19
 
@@ -21,13 +21,13 @@ import './VDiskPopup.scss';
21
21
 
22
22
  const b = cn('vdisk-storage-popup');
23
23
 
24
- const prepareUnavailableVDiskData = (data: IUnavailableDonor, poolName?: string) => {
25
- const {NodeId, PDiskId, VSlotId} = data;
24
+ const prepareUnavailableVDiskData = (data: UnavailableDonor) => {
25
+ const {NodeId, PDiskId, VSlotId, StoragePoolName} = data;
26
26
 
27
27
  const vdiskData: InfoViewerItem[] = [{label: 'State', value: 'not available'}];
28
28
 
29
- if (poolName) {
30
- vdiskData.push({label: 'StoragePool', value: poolName});
29
+ if (StoragePoolName) {
30
+ vdiskData.push({label: 'StoragePool', value: StoragePoolName});
31
31
  }
32
32
 
33
33
  vdiskData.push(
@@ -39,7 +39,7 @@ const prepareUnavailableVDiskData = (data: IUnavailableDonor, poolName?: string)
39
39
  return vdiskData;
40
40
  };
41
41
 
42
- const prepareVDiskData = (data: TVDiskStateInfo, poolName?: string) => {
42
+ const prepareVDiskData = (data: TVDiskStateInfo) => {
43
43
  const {
44
44
  VDiskId,
45
45
  VDiskState,
@@ -51,6 +51,7 @@ const prepareVDiskData = (data: TVDiskStateInfo, poolName?: string) => {
51
51
  AllocatedSize,
52
52
  ReadThroughput,
53
53
  WriteThroughput,
54
+ StoragePoolName,
54
55
  } = data;
55
56
 
56
57
  const vdiskData: InfoViewerItem[] = [
@@ -58,8 +59,8 @@ const prepareVDiskData = (data: TVDiskStateInfo, poolName?: string) => {
58
59
  {label: 'State', value: VDiskState ?? 'not available'},
59
60
  ];
60
61
 
61
- if (poolName) {
62
- vdiskData.push({label: 'StoragePool', value: poolName});
62
+ if (StoragePoolName) {
63
+ vdiskData.push({label: 'StoragePool', value: StoragePoolName});
63
64
  }
64
65
 
65
66
  if (SatisfactionRank && SatisfactionRank.FreshRank?.Flag !== EFlag.Green) {
@@ -128,20 +129,16 @@ const prepareVDiskData = (data: TVDiskStateInfo, poolName?: string) => {
128
129
  };
129
130
 
130
131
  interface VDiskPopupProps extends PopupProps {
131
- data: TVDiskStateInfo | IUnavailableDonor;
132
- poolName?: string;
132
+ data: TVDiskStateInfo | UnavailableDonor;
133
133
  nodes?: NodesMap;
134
134
  }
135
135
 
136
- export const VDiskPopup = ({data, poolName, nodes, ...props}: VDiskPopupProps) => {
136
+ export const VDiskPopup = ({data, nodes, ...props}: VDiskPopupProps) => {
137
137
  const isFullData = isFullVDiskData(data);
138
138
 
139
139
  const vdiskInfo = useMemo(
140
- () =>
141
- isFullData
142
- ? prepareVDiskData(data, poolName)
143
- : prepareUnavailableVDiskData(data, poolName),
144
- [data, poolName, isFullData],
140
+ () => (isFullData ? prepareVDiskData(data) : prepareUnavailableVDiskData(data)),
141
+ [data, isFullData],
145
142
  );
146
143
  const pdiskInfo = useMemo(
147
144
  () => isFullData && data.PDisk && preparePDiskData(data.PDisk, nodes),
@@ -1,5 +1,6 @@
1
1
  import {TVSlotId} from '../../../types/api/vdisk';
2
2
 
3
- export interface IUnavailableDonor extends TVSlotId {
3
+ export interface UnavailableDonor extends TVSlotId {
4
4
  DonorMode?: boolean;
5
+ StoragePoolName?: string;
5
6
  }
@@ -89,4 +89,8 @@
89
89
  line-height: var(--yc-text-body-2-line-height);
90
90
  text-transform: uppercase;
91
91
  }
92
+
93
+ &__host {
94
+ width: 300px;
95
+ }
92
96
  }
@@ -1,7 +1,13 @@
1
1
  import DataTable, {Column} from '@gravity-ui/react-data-table';
2
2
 
3
+ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
4
+ import {InternalLink} from '../../../components/InternalLink/InternalLink';
5
+
3
6
  import type {ITabletPreparedHistoryItem} from '../../../types/store/tablet';
4
7
  import {calcUptime} from '../../../utils';
8
+ import {getDefaultNodePath} from '../../Node/NodePages';
9
+
10
+ import {b} from '../Tablet';
5
11
 
6
12
  const columns: Column<ITabletPreparedHistoryItem>[] = [
7
13
  {
@@ -9,12 +15,6 @@ const columns: Column<ITabletPreparedHistoryItem>[] = [
9
15
  align: DataTable.RIGHT,
10
16
  render: ({row}) => row.generation,
11
17
  },
12
- {
13
- name: 'Node ID',
14
- align: DataTable.RIGHT,
15
- sortable: false,
16
- render: ({row}) => row.nodeId,
17
- },
18
18
  {
19
19
  name: 'Change time',
20
20
  align: DataTable.RIGHT,
@@ -33,6 +33,28 @@ const columns: Column<ITabletPreparedHistoryItem>[] = [
33
33
  return row.leader ? 'leader' : row.followerId;
34
34
  },
35
35
  },
36
+ {
37
+ name: 'Node ID',
38
+ align: DataTable.RIGHT,
39
+ sortable: false,
40
+ render: ({row}) => {
41
+ return <InternalLink to={getDefaultNodePath(row.nodeId)}>{row.nodeId}</InternalLink>;
42
+ },
43
+ },
44
+ {
45
+ name: 'Node FQDN',
46
+ sortable: false,
47
+ render: ({row}) => {
48
+ if (!row.fqdn) {
49
+ return <span>—</span>;
50
+ }
51
+ return (
52
+ <div className={b('host')}>
53
+ <EntityStatus name={row.fqdn} showStatus={false} hasClipboardButton />
54
+ </div>
55
+ );
56
+ },
57
+ },
36
58
  ];
37
59
 
38
60
  const TABLE_SETTINGS = {
@@ -80,7 +80,7 @@
80
80
  }
81
81
  &_degraded,
82
82
  &_yellow {
83
- color: var(--yc-color-text-warning-medium);
83
+ color: var(--yc-color-text-warning);
84
84
  background-color: var(--yc-color-base-warning);
85
85
  }
86
86