ydb-embedded-ui 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/assets/icons/shield.svg +3 -0
  3. package/dist/components/NodesViewer/NodesViewer.js +1 -1
  4. package/dist/containers/App/App.scss +5 -1
  5. package/dist/containers/Nodes/Nodes.js +1 -1
  6. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +7 -5
  7. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -11
  8. package/dist/containers/Storage/Pdisk/Pdisk.scss +15 -8
  9. package/dist/containers/Storage/Pdisk/Pdisk.tsx +22 -14
  10. package/dist/containers/Storage/Storage.js +29 -48
  11. package/dist/containers/Storage/StorageGroups/StorageGroups.scss +1 -4
  12. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +27 -2
  13. package/dist/containers/Storage/StorageGroups/i18n/en.json +2 -1
  14. package/dist/containers/Storage/StorageGroups/i18n/ru.json +2 -1
  15. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +14 -12
  16. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -5
  17. package/dist/containers/Storage/Vdisk/Vdisk.js +36 -23
  18. package/dist/containers/Storage/Vdisk/Vdisk.scss +6 -0
  19. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +7 -0
  20. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +25 -11
  21. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +34 -19
  22. package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +1 -1
  23. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +27 -20
  24. package/dist/containers/Tenant/Tenant.tsx +12 -9
  25. package/dist/containers/Tenants/Tenants.js +1 -1
  26. package/dist/store/reducers/olapStats.js +13 -0
  27. package/dist/store/reducers/schema.js +42 -0
  28. package/dist/store/reducers/storage.js +26 -16
  29. package/dist/store/reducers/tenant.js +3 -1
  30. package/dist/styles/mixins.scss +1 -1
  31. package/dist/types/api/storage.ts +35 -10
  32. package/dist/types/store/storage.ts +1 -0
  33. package/dist/utils/hooks/useAutofetcher.ts +9 -3
  34. package/package.json +1 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.2.1...v2.3.0) (2022-10-24)
4
+
5
+
6
+ ### Features
7
+
8
+ * **PDisk:** display type on disk progressbar ([00bcbf5](https://github.com/ydb-platform/ydb-embedded-ui/commit/00bcbf5d439ca3bb4834fd5f191c65f0ac62585f))
9
+ * **Storage:** display media type for groups ([cdff5e9](https://github.com/ydb-platform/ydb-embedded-ui/commit/cdff5e9882f3f1f8769a3aeaf3e53c05f3ce1c07))
10
+ * **Storage:** display shield icon for encrypted groups ([d0a4442](https://github.com/ydb-platform/ydb-embedded-ui/commit/d0a4442dc100c312dcc54afcf685057cc587211d))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **Diagnostics:** fix tabs reset on page reload ([68d2971](https://github.com/ydb-platform/ydb-embedded-ui/commit/68d297165aea1360d1081349d8133804004f8fe0))
16
+ * **Storage:** prevent loading reset on cancelled fetch ([625159a](https://github.com/ydb-platform/ydb-embedded-ui/commit/625159a396e1ab84fe9da94d047da67fdd03b30f))
17
+ * **Storage:** shrink tooltip active area on FQDN ([7c33d5a](https://github.com/ydb-platform/ydb-embedded-ui/commit/7c33d5afb561efa64f90ce5b93edd30f7d27c247))
18
+ * **Tenant:** prevent selected tab reset on tree navigation ([a4e633a](https://github.com/ydb-platform/ydb-embedded-ui/commit/a4e633aa45c803503fe69e52f0f2cfac4c6aae0d))
19
+ * **Tenant:** show loader when fetching overview data ([ae77495](https://github.com/ydb-platform/ydb-embedded-ui/commit/ae77495faa687652040a1f2965700184220778b4))
20
+ * use correct prop for textinputs value ([de97ba1](https://github.com/ydb-platform/ydb-embedded-ui/commit/de97ba17ba8da54a626509cf08f147f9fcc67004))
21
+ * **useAutofetcher:** pass argument to indicate background fetch ([4063cb1](https://github.com/ydb-platform/ydb-embedded-ui/commit/4063cb1411338d351b612fc46c06bcc708fe32f1))
22
+
23
+ ## [2.2.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.2.0...v2.2.1) (2022-10-19)
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * revert prettier config, fix build ([c47dddf](https://github.com/ydb-platform/ydb-embedded-ui/commit/c47dddf834eadfd5642af62e0cc94f7567ec68fd))
29
+
3
30
  ## [2.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.1.0...v2.2.0) (2022-10-14)
4
31
 
5
32
 
@@ -0,0 +1,3 @@
1
+ <svg viewBox="0 0 18 18" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M8.69222 1.56606C8.88795 1.47798 9.11205 1.47798 9.30778 1.56606L15.3078 4.26613C15.5769 4.38725 15.75 4.65494 15.75 4.95007V7.24592C15.75 11.1569 13.413 14.6895 9.81353 16.2192L9.29335 16.4403C9.1059 16.5199 8.8941 16.5199 8.70665 16.4403L8.18647 16.2192C4.58703 14.6895 2.25 11.1569 2.25 7.24592V4.95007C2.25 4.65494 2.42309 4.38725 2.69222 4.26613L8.69222 1.56606ZM3.75 5.43501V7.24592C3.75 10.5552 5.72748 13.5443 8.77317 14.8387L9 14.9351L9.22683 14.8387C12.2725 13.5443 14.25 10.5552 14.25 7.24592V5.43501L9 3.07244L3.75 5.43501ZM9.75 8.79933C10.1984 8.53997 10.5 8.05521 10.5 7.5C10.5 6.67157 9.82843 6 9 6C8.17157 6 7.5 6.67157 7.5 7.5C7.5 8.05521 7.80165 8.53997 8.25 8.79933V11.25C8.25 11.6642 8.58579 12 9 12C9.41421 12 9.75 11.6642 9.75 11.25V8.79933Z"/>
3
+ </svg>
@@ -103,7 +103,7 @@ class NodesViewer extends React.PureComponent {
103
103
  className={b('search')}
104
104
  size="s"
105
105
  placeholder="Host name…"
106
- text={searchQuery}
106
+ value={searchQuery}
107
107
  onUpdate={handleSearchQuery}
108
108
  hasClear
109
109
  autoFocus
@@ -31,6 +31,10 @@ body,
31
31
  --data-table-row-height: 40px;
32
32
  }
33
33
 
34
+ .yc-root {
35
+ --ydb-data-table-color-hover: var(--yc-color-base-float-hover);
36
+ }
37
+
34
38
  .yc-select__label {
35
39
  font-weight: 600;
36
40
  }
@@ -130,7 +134,7 @@ body,
130
134
  }
131
135
 
132
136
  .yc-root .data-table_highlight-rows .data-table__row:hover {
133
- background: var(--yc-color-base-float-hover);
137
+ background: var(--ydb-data-table-color-hover);
134
138
  }
135
139
 
136
140
  .yc-table-column-setup__item {
@@ -84,7 +84,7 @@ class Nodes extends React.Component {
84
84
  <TextInput
85
85
  className={b('search')}
86
86
  placeholder="Host name"
87
- text={searchQuery}
87
+ value={searchQuery}
88
88
  onUpdate={this.handleSearchQueryChange}
89
89
  hasClear
90
90
  autoFocus
@@ -1,18 +1,20 @@
1
1
  .storage-disk-progress-bar {
2
+ $block: &;
3
+
2
4
  $border-width: 2px;
3
5
  $outer-border-radius: 4px;
4
6
  $inner-border-radius: $outer-border-radius - $border-width;
5
7
 
6
- $block: &;
7
8
  position: relative;
8
9
 
9
- display: inline-block;
10
+ display: block;
10
11
 
11
- width: 100%;
12
+ min-width: 50px;
12
13
  height: var(--yc-text-body-2-line-height);
13
14
 
14
- vertical-align: top;
15
+ text-align: center;
15
16
 
17
+ color: var(--yc-color-text-primary);
16
18
  border: $border-width solid var(--yc-color-infographics-misc-heavy);
17
19
  border-radius: $outer-border-radius;
18
20
  background-color: var(--yc-color-infographics-misc-light);
@@ -82,7 +84,7 @@
82
84
  }
83
85
  }
84
86
  &__filled-title {
85
- position: absolute;
87
+ position: relative;
86
88
  z-index: 2;
87
89
 
88
90
  font-size: var(--yc-text-body-1-font-size);
@@ -5,8 +5,6 @@ import cn from 'bem-cn-lite';
5
5
  import {INVERTED_DISKS_KEY} from '../../../utils/constants';
6
6
  import {getSettingValue} from '../../../store/reducers/settings';
7
7
 
8
- import InternalLink from '../../../components/InternalLink/InternalLink';
9
-
10
8
  import './DiskStateProgressBar.scss';
11
9
 
12
10
  const b = cn('storage-disk-progress-bar');
@@ -23,13 +21,11 @@ export const diskProgressColors = {
23
21
  interface DiskStateProgressBarProps {
24
22
  diskAllocatedPercent?: number;
25
23
  severity?: keyof typeof diskProgressColors;
26
- href?: string;
27
24
  }
28
25
 
29
26
  function DiskStateProgressBar({
30
27
  diskAllocatedPercent = -1,
31
28
  severity,
32
- href,
33
29
  }: DiskStateProgressBarProps) {
34
30
  const inverted = useSelector((state) => getSettingValue(state, INVERTED_DISKS_KEY));
35
31
 
@@ -63,13 +59,7 @@ function DiskStateProgressBar({
63
59
  aria-valuemax={100}
64
60
  aria-valuenow={diskAllocatedPercent}
65
61
  >
66
- {href ? (
67
- <InternalLink to={href} className={b('link')}>
68
- {renderAllocatedPercent()}
69
- </InternalLink>
70
- ) : (
71
- renderAllocatedPercent()
72
- )}
62
+ {renderAllocatedPercent()}
73
63
  </div>
74
64
  );
75
65
  }
@@ -1,18 +1,25 @@
1
1
  .pdisk-storage {
2
- display: flex;
3
- flex-grow: 1;
4
- align-items: center;
2
+ position: relative;
5
3
 
6
- max-width: 200px;
7
- margin-right: 10px;
4
+ min-width: 120px;
8
5
 
9
- cursor: pointer;
6
+ border-radius: 4px; // to match interactive area with disk shape
10
7
 
11
- &:last-child {
12
- margin-right: 0px;
8
+ &__content {
9
+ border-radius: 4px; // to match interactive area with disk shape
13
10
  }
14
11
 
15
12
  &__popup-wrapper {
16
13
  padding: 12px;
17
14
  }
15
+
16
+ &__media-type {
17
+ position: absolute;
18
+ top: 0;
19
+ right: 4px;
20
+
21
+ font-size: var(--yc-text-body-1-font-size);
22
+
23
+ color: var(--yc-color-text-secondary);
24
+ }
18
25
  }
@@ -1,21 +1,23 @@
1
1
  import React, {useEffect, useState, useRef, useMemo} from 'react';
2
2
  import cn from 'bem-cn-lite';
3
+
3
4
  import {Popup} from '@gravity-ui/uikit';
4
5
 
5
- import type {RequiredField} from '../../../types';
6
- //@ts-ignore
7
- import {bytesToGB} from '../../../utils/utils';
8
- //@ts-ignore
6
+ import {InfoViewer} from '../../../components/InfoViewer';
7
+ import InternalLink from '../../../components/InternalLink/InternalLink';
8
+
9
9
  import routes, {createHref} from '../../../routes';
10
- //@ts-ignore
10
+ import type {RequiredField} from '../../../types';
11
+ import {TPDiskStateInfo, TPDiskState} from '../../../types/api/storage';
11
12
  import {getPDiskId} from '../../../utils';
12
13
  import {getPDiskType} from '../../../utils/pdisk';
13
- import {TPDiskStateInfo, TPDiskState} from '../../../types/api/storage';
14
- import {InfoViewer} from '../../../components/InfoViewer';
14
+ import {bytesToGB} from '../../../utils/utils';
15
+
16
+ import {STRUCTURE} from '../../Node/NodePages';
17
+
15
18
  import DiskStateProgressBar, {
16
19
  diskProgressColors,
17
20
  } from '../DiskStateProgressBar/DiskStateProgressBar';
18
- import {STRUCTURE} from '../../Node/NodePages';
19
21
 
20
22
  import {colorSeverity, NOT_AVAILABLE_SEVERITY} from '../utils';
21
23
 
@@ -123,8 +125,9 @@ function Pdisk(props: PDiskProps) {
123
125
  const {AvailableSize, TotalSize} = props;
124
126
 
125
127
  if (!AvailableSize || !TotalSize) {
126
- return;
128
+ return undefined;
127
129
  }
130
+
128
131
  return !isNaN(Number(AvailableSize)) && !isNaN(Number(TotalSize))
129
132
  ? Math.round(((Number(TotalSize) - Number(AvailableSize)) * 100) / Number(TotalSize))
130
133
  : undefined;
@@ -134,15 +137,20 @@ function Pdisk(props: PDiskProps) {
134
137
  <React.Fragment>
135
138
  {renderPopup()}
136
139
  <div className={b()} ref={anchor} onMouseEnter={showPopup} onMouseLeave={hidePopup}>
137
- <DiskStateProgressBar
138
- diskAllocatedPercent={pdiskAllocatedPercent}
139
- severity={severity as keyof typeof diskProgressColors}
140
- href={createHref(
140
+ <InternalLink
141
+ to={createHref(
141
142
  routes.node,
142
143
  {id: props.NodeId, activeTab: STRUCTURE},
143
144
  {pdiskId: props.PDiskId || ''},
144
145
  )}
145
- />
146
+ className={b('content')}
147
+ >
148
+ <DiskStateProgressBar
149
+ diskAllocatedPercent={pdiskAllocatedPercent}
150
+ severity={severity as keyof typeof diskProgressColors}
151
+ />
152
+ <div className={b('media-type')}>{getPDiskType(props)}</div>
153
+ </InternalLink>
146
154
  </div>
147
155
  </React.Fragment>
148
156
  );
@@ -68,14 +68,8 @@ class Storage extends React.Component {
68
68
  };
69
69
 
70
70
  componentDidMount() {
71
- const {
72
- tenant,
73
- nodeId,
74
- setVisibleEntities,
75
- storageType,
76
- setHeader,
77
- getNodesList,
78
- } = this.props;
71
+ const {tenant, nodeId, setVisibleEntities, storageType, setHeader, getNodesList} =
72
+ this.props;
79
73
 
80
74
  this.autofetcher = new AutoFetcher();
81
75
  getNodesList();
@@ -106,12 +100,7 @@ class Storage extends React.Component {
106
100
  }
107
101
 
108
102
  componentDidUpdate(prevProps) {
109
- const {
110
- visibleEntities,
111
- storageType,
112
- autorefresh,
113
- database,
114
- } = this.props;
103
+ const {visibleEntities, storageType, autorefresh, database} = this.props;
115
104
 
116
105
  const startFetch = () => {
117
106
  this.getStorageInfo({
@@ -139,7 +128,10 @@ class Storage extends React.Component {
139
128
  restartAutorefresh();
140
129
  }
141
130
 
142
- if (storageType !== prevProps.storageType || visibleEntities !== prevProps.visibleEntities) {
131
+ if (
132
+ storageType !== prevProps.storageType ||
133
+ visibleEntities !== prevProps.visibleEntities
134
+ ) {
143
135
  startFetch();
144
136
 
145
137
  if (!database || (database && autorefresh)) {
@@ -154,25 +146,22 @@ class Storage extends React.Component {
154
146
  }
155
147
 
156
148
  getStorageInfo(data) {
157
- const {
158
- tenant,
159
- nodeId,
160
- getStorageInfo,
161
- } = this.props;
162
-
163
- getStorageInfo({
164
- tenant,
165
- nodeId,
166
- ...data,
167
- }, {
168
- concurrentId: 'getStorageInfo',
169
- });
149
+ const {tenant, nodeId, getStorageInfo} = this.props;
150
+
151
+ getStorageInfo(
152
+ {
153
+ tenant,
154
+ nodeId,
155
+ ...data,
156
+ },
157
+ {
158
+ concurrentId: 'getStorageInfo',
159
+ },
160
+ );
170
161
  }
171
162
 
172
163
  renderLoader() {
173
- return (
174
- <TableSkeleton className={b('loader')}/>
175
- );
164
+ return <TableSkeleton className={b('loader')} />;
176
165
  }
177
166
 
178
167
  renderDataTable() {
@@ -212,14 +201,8 @@ class Storage extends React.Component {
212
201
  };
213
202
 
214
203
  renderEntitiesCount() {
215
- const {
216
- storageType,
217
- groupsCount,
218
- nodesCount,
219
- flatListStorageEntities,
220
- loading,
221
- wasLoaded,
222
- } = this.props;
204
+ const {storageType, groupsCount, nodesCount, flatListStorageEntities, loading, wasLoaded} =
205
+ this.props;
223
206
 
224
207
  let label = `${storageType === StorageTypes.groups ? 'Groups' : 'Nodes'}: `;
225
208
  const count = storageType === StorageTypes.groups ? groupsCount : nodesCount;
@@ -254,7 +237,11 @@ class Storage extends React.Component {
254
237
  <div className={b('controls')}>
255
238
  <div className={b('search')}>
256
239
  <StorageFilter
257
- placeholder={storageType === StorageTypes.groups ? 'Group ID, Pool name' : 'Node ID, FQDN'}
240
+ placeholder={
241
+ storageType === StorageTypes.groups
242
+ ? 'Group ID, Pool name'
243
+ : 'Node ID, FQDN'
244
+ }
258
245
  onChange={setStorageFilter}
259
246
  value={filter}
260
247
  />
@@ -303,14 +290,8 @@ class Storage extends React.Component {
303
290
  return (
304
291
  <div className={b()}>
305
292
  {this.renderControls()}
306
- {error && (
307
- <div>{error.statusText}</div>
308
- )}
309
- {showLoader ? (
310
- this.renderLoader()
311
- ) : (
312
- this.renderDataTable()
313
- )}
293
+ {error && <div>{error.statusText}</div>}
294
+ {showLoader ? this.renderLoader() : this.renderDataTable()}
314
295
  </div>
315
296
  );
316
297
  }
@@ -23,7 +23,7 @@
23
23
  background: var(--yc-color-base-background);
24
24
 
25
25
  .data-table__row:hover & {
26
- background: var(--yc-color-base-float-hover);
26
+ background: var(--ydb-data-table-color-hover);
27
27
  }
28
28
  }
29
29
  }
@@ -51,7 +51,4 @@
51
51
  &__group-id {
52
52
  font-weight: 500;
53
53
  }
54
- &__tooltip {
55
- word-break: break-all;
56
- }
57
54
  }
@@ -1,7 +1,9 @@
1
1
  import _ from 'lodash';
2
2
  import cn from 'bem-cn-lite';
3
3
  import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-table';
4
- import {Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
4
+ import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
5
+
6
+ import shieldIcon from '../../../assets/icons/shield.svg';
5
7
 
6
8
  import {Stack} from '../../../components/Stack/Stack';
7
9
  //@ts-ignore
@@ -25,6 +27,7 @@ import './StorageGroups.scss';
25
27
 
26
28
  enum TableColumnsIds {
27
29
  PoolName = 'PoolName',
30
+ Type = 'Type',
28
31
  GroupID = 'GroupID',
29
32
  Used = 'Used',
30
33
  Limit = 'Limit',
@@ -49,6 +52,7 @@ interface StorageGroupsProps {
49
52
 
50
53
  const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
51
54
  PoolName: 'Pool Name',
55
+ Type: 'Type',
52
56
  GroupID: 'Group ID',
53
57
  Used: 'Used',
54
58
  Limit: 'Limit',
@@ -100,7 +104,7 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes, onShowAll}:
100
104
  <div className={b('pool-name-wrapper')}>
101
105
  {splitted && (
102
106
  <Popover
103
- content={<span className={b('tooltip')}>{value as string}</span>}
107
+ content={value as string}
104
108
  placement={['right']}
105
109
  behavior={PopoverBehavior.Immediate}
106
110
  >
@@ -114,6 +118,27 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes, onShowAll}:
114
118
  },
115
119
  align: DataTable.LEFT,
116
120
  },
121
+ {
122
+ name: TableColumnsIds.Type,
123
+ header: tableColumnsNames[TableColumnsIds.Type],
124
+ render: ({value, row}) => (
125
+ <>
126
+ <Label>{value as string || '—'}</Label>
127
+ {' '}
128
+ {row.Encryption && (
129
+ <Popover
130
+ content={i18n('encrypted')}
131
+ placement="right"
132
+ behavior={PopoverBehavior.Immediate}
133
+ >
134
+ <Label>
135
+ <Icon data={shieldIcon} />
136
+ </Label>
137
+ </Popover>
138
+ )}
139
+ </>
140
+ ),
141
+ },
117
142
  {
118
143
  name: TableColumnsIds.Missing,
119
144
  header: tableColumnsNames[TableColumnsIds.Missing],
@@ -2,5 +2,6 @@
2
2
  "empty.default": "No such groups",
3
3
  "empty.out_of_space": "No groups with out of space errors",
4
4
  "empty.degraded": "No degraded groups",
5
- "show_all": "Show all groups"
5
+ "show_all": "Show all groups",
6
+ "encrypted": "Encrypted group"
6
7
  }
@@ -2,5 +2,6 @@
2
2
  "empty.default": "Нет групп",
3
3
  "empty.out_of_space": "Нет групп, в которых кончается место",
4
4
  "empty.degraded": "Нет деградировавших групп",
5
- "show_all": "Показать все группы"
5
+ "show_all": "Показать все группы",
6
+ "encrypted": "Зашифрованная группа"
6
7
  }
@@ -7,27 +7,29 @@
7
7
 
8
8
  min-width: 500px;
9
9
  }
10
- &__pool-name-wrapper {
11
- display: flex;
12
- align-items: flex-end;
10
+ &__pdisks-item {
11
+ flex-grow: 1;
12
+
13
+ max-width: 200px;
14
+ margin-right: 10px;
15
+
16
+ &:last-child {
17
+ margin-right: 0px;
18
+ }
19
+ }
20
+ &__fqdn-wrapper {
21
+ width: 330px;
13
22
  }
14
- &__pool-name {
23
+ &__fqdn {
15
24
  display: inline-block;
16
25
  overflow: hidden;
17
26
 
18
- width: 330px;
19
27
  max-width: 330px;
20
28
 
29
+ vertical-align: top;
21
30
  text-overflow: ellipsis;
22
31
  }
23
32
  &__group-id {
24
33
  font-weight: 500;
25
34
  }
26
- &__tooltip-wrapper {
27
- display: flex;
28
- align-items: center;
29
- }
30
- &__tooltip {
31
- word-break: break-all;
32
- }
33
35
  }
@@ -1,9 +1,9 @@
1
1
  import _ from 'lodash';
2
2
  import cn from 'bem-cn-lite';
3
+
3
4
  import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-table';
4
5
  import {Popover, PopoverBehavior} from '@gravity-ui/uikit';
5
6
 
6
- //@ts-ignore
7
7
  import {VisibleEntities} from '../../../store/reducers/storage';
8
8
 
9
9
  import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
@@ -75,13 +75,13 @@ function StorageNodes({data, tableSettings, visibleEntities, onShowAll}: Storage
75
75
  width: 350,
76
76
  render: ({value}) => {
77
77
  return (
78
- <div className={b('tooltip-wrapper')}>
78
+ <div className={b('fqdn-wrapper')}>
79
79
  <Popover
80
- content={<span className={b('tooltip')}>{value as string}</span>}
80
+ content={value as string}
81
81
  placement={['right']}
82
82
  behavior={PopoverBehavior.Immediate}
83
83
  >
84
- <span className={b('pool-name')}>{value as string}</span>
84
+ <span className={b('fqdn')}>{value as string}</span>
85
85
  </Popover>
86
86
  </div>
87
87
  );
@@ -108,7 +108,9 @@ function StorageNodes({data, tableSettings, visibleEntities, onShowAll}: Storage
108
108
  render: ({value, row}) => (
109
109
  <div className={b('pdisks-wrapper')}>
110
110
  {_.map(value as any, (el) => (
111
- <Pdisk key={el.PDiskId} {...el} NodeId={row.NodeId} />
111
+ <div className={b('pdisks-item')}>
112
+ <Pdisk key={el.PDiskId} {...el} NodeId={row.NodeId} />
113
+ </div>
112
114
  ))}
113
115
  </div>
114
116
  ),
@@ -1,17 +1,22 @@
1
1
  import React, {useEffect, useState, useRef, useMemo} from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import cn from 'bem-cn-lite';
4
+
4
5
  import {Label, Popup} from '@gravity-ui/uikit';
5
6
 
6
- import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
7
+ import InternalLink from '../../../components/InternalLink/InternalLink';
8
+ import {InfoViewer} from '../../../components/InfoViewer';
9
+
7
10
  import routes, {createHref} from '../../../routes';
8
11
  import {stringifyVdiskId, getPDiskId} from '../../../utils';
9
12
  import {getPDiskType} from '../../../utils/pdisk';
10
- import {InfoViewer} from '../../../components/InfoViewer';
13
+ import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
14
+
15
+ import {STRUCTURE} from '../../Node/NodePages';
16
+
11
17
  import DiskStateProgressBar, {
12
18
  diskProgressColors,
13
19
  } from '../DiskStateProgressBar/DiskStateProgressBar';
14
- import {STRUCTURE} from '../../Node/NodePages';
15
20
 
16
21
  import {colorSeverity, NOT_AVAILABLE_SEVERITY} from '../utils';
17
22
 
@@ -225,33 +230,41 @@ function Vdisk(props) {
225
230
  const available = AvailableSize ? AvailableSize : PDisk?.AvailableSize;
226
231
 
227
232
  if (!available) {
228
- return;
233
+ return undefined;
229
234
  }
230
- return !isNaN(Number(AllocatedSize))
231
- ? (Number(AllocatedSize) * 100) / (Number(available) + Number(AllocatedSize))
232
- : undefined;
235
+
236
+ return isNaN(Number(AllocatedSize))
237
+ ? undefined
238
+ : (Number(AllocatedSize) * 100) / (Number(available) + Number(AllocatedSize));
233
239
  }, [props.AllocatedSize, props.AvailableSize, props.PDisk?.AvailableSize]);
234
240
 
235
241
  return (
236
242
  <React.Fragment>
237
243
  {renderPopup()}
238
244
  <div className={b()} ref={anchor} onMouseEnter={showPopup} onMouseLeave={hidePopup}>
239
- <DiskStateProgressBar
240
- diskAllocatedPercent={vdiskAllocatedPercent}
241
- severity={severity}
242
- href={
243
- props.NodeId
244
- ? createHref(
245
- routes.node,
246
- {id: props.NodeId, activeTab: STRUCTURE},
247
- {
248
- pdiskId: props.PDisk?.PDiskId,
249
- vdiskId: stringifyVdiskId(props.VDiskId),
250
- },
251
- )
252
- : undefined
253
- }
254
- />
245
+ {props.NodeId ? (
246
+ <InternalLink
247
+ to={createHref(
248
+ routes.node,
249
+ {id: props.NodeId, activeTab: STRUCTURE},
250
+ {
251
+ pdiskId: props.PDisk?.PDiskId,
252
+ vdiskId: stringifyVdiskId(props.VDiskId),
253
+ },
254
+ )}
255
+ className={b('content')}
256
+ >
257
+ <DiskStateProgressBar
258
+ diskAllocatedPercent={vdiskAllocatedPercent}
259
+ severity={severity}
260
+ />
261
+ </InternalLink>
262
+ ) : (
263
+ <DiskStateProgressBar
264
+ diskAllocatedPercent={vdiskAllocatedPercent}
265
+ severity={severity}
266
+ />
267
+ )}
255
268
  </div>
256
269
  </React.Fragment>
257
270
  );
@@ -1,4 +1,10 @@
1
1
  .vdisk-storage {
2
+ border-radius: 4px; // to match interactive area with disk shape
3
+
4
+ &__content {
5
+ border-radius: 4px; // to match interactive area with disk shape
6
+ }
7
+
2
8
  &__popup-wrapper {
3
9
  padding: 12px;
4
10