ydb-embedded-ui 4.0.0 → 4.2.0

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