ydb-embedded-ui 4.1.0 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/components/LabelWithPopover/LabelWithPopover.tsx +10 -4
  3. package/dist/components/TabletsStatistic/TabletsStatistic.scss +1 -1
  4. package/dist/containers/App/App.scss +7 -4
  5. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +3 -12
  6. package/dist/containers/Storage/VDisk/VDisk.tsx +4 -11
  7. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +13 -16
  8. package/dist/containers/Storage/utils/types.ts +2 -1
  9. package/dist/containers/Tablet/Tablet.scss +4 -0
  10. package/dist/containers/Tablet/TabletTable/TabletTable.tsx +28 -6
  11. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +1 -1
  12. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +4 -3
  13. package/dist/containers/Tenant/QueryEditor/Issues/Issues.scss +1 -1
  14. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +1 -1
  15. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +1 -1
  16. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +12 -0
  17. package/dist/containers/UserSettings/UserSettings.tsx +19 -17
  18. package/dist/services/api.ts +9 -9
  19. package/dist/store/reducers/node.js +5 -1
  20. package/dist/store/reducers/nodesList.ts +2 -7
  21. package/dist/store/reducers/storage.js +12 -0
  22. package/dist/store/reducers/tablet.ts +16 -2
  23. package/dist/types/store/tablet.ts +1 -0
  24. package/dist/utils/createToast.tsx +3 -3
  25. package/dist/utils/nodes.ts +11 -0
  26. package/package.json +4 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.2.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.2.0...v4.2.1) (2023-05-18)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * export toaster ([b5d12c0](https://github.com/ydb-platform/ydb-embedded-ui/commit/b5d12c0aa39ea3877a9b74071e3124f89a309ca3))
9
+
10
+ ## [4.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.1.0...v4.2.0) (2023-05-16)
11
+
12
+
13
+ ### Features
14
+
15
+ * **Tablet:** display node fqdn in table ([4d8099a](https://github.com/ydb-platform/ydb-embedded-ui/commit/4d8099a454f34fc76886b26ca948895171c57ab8))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **api:** change nulls to empty objects ([0ab14e8](https://github.com/ydb-platform/ydb-embedded-ui/commit/0ab14e883a47aeac2f2bab437f2214a32ccb1c9b))
21
+ * display storage pool in VDisks popups ([5b5dd8a](https://github.com/ydb-platform/ydb-embedded-ui/commit/5b5dd8a4e6cb4bcc1ead78a7c06d2e80a81424cc))
22
+ * fix Select label and values align ([f796730](https://github.com/ydb-platform/ydb-embedded-ui/commit/f7967309fe4a042e7637de212f33b1ebfc6877fc))
23
+ * **Overview:** partitioning by size disabled for 0 SizeToSpit ([1028e7d](https://github.com/ydb-platform/ydb-embedded-ui/commit/1028e7d8d3566f5f5e6b2ebe04112ef135d7b55e))
24
+ * **Schema:** display NotNull columns ([d61eaa4](https://github.com/ydb-platform/ydb-embedded-ui/commit/d61eaa4ccff357c1e9ca6efde855ec46be24a314))
25
+
3
26
  ## [4.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.0.0...v4.1.0) (2023-05-10)
4
27
 
5
28
 
@@ -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
  );
@@ -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 {
@@ -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
  })}
@@ -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
 
@@ -86,9 +86,10 @@ const prepareTableGeneralInfo = (PartitionConfig: TPartitionConfig, TTLSettings?
86
86
 
87
87
  const generalTableInfo: InfoViewerItem[] = [];
88
88
 
89
- const partitioningBySize = PartitioningPolicy.SizeToSplit
90
- ? `Enabled, split size: ${formatBytes(PartitioningPolicy.SizeToSplit)}`
91
- : 'Disabled';
89
+ const partitioningBySize =
90
+ PartitioningPolicy.SizeToSplit && Number(PartitioningPolicy.SizeToSplit) > 0
91
+ ? `Enabled, split size: ${formatBytes(PartitioningPolicy.SizeToSplit)}`
92
+ : 'Disabled';
92
93
 
93
94
  const partitioningByLoad = PartitioningPolicy.SplitByLoadSettings?.Enabled
94
95
  ? 'Enabled'
@@ -106,7 +106,7 @@
106
106
  }
107
107
 
108
108
  &_severity_warning &__icon {
109
- color: var(--yc-color-text-warning-medium);
109
+ color: var(--yc-color-text-warning);
110
110
  }
111
111
 
112
112
  &_severity_info &__icon {
@@ -48,7 +48,7 @@ export const OldQueryEditorControls = ({
48
48
  </Button>
49
49
  <DropdownMenu
50
50
  items={runModeSelectorMenuItems}
51
- popupClassName={b('select-query-action-popup')}
51
+ popupProps={{className: b('select-query-action-popup')}}
52
52
  switcher={
53
53
  <Button
54
54
  view="action"
@@ -61,7 +61,7 @@ export const QueryEditorControls = ({
61
61
  </Button>
62
62
  <DropdownMenu
63
63
  items={querySelectorMenuItems}
64
- popupClassName={b('mode-selector__popup')}
64
+ popupProps={{className: b('mode-selector__popup')}}
65
65
  switcher={
66
66
  <Button className={b('mode-selector__button')}>
67
67
  <span className={b('mode-selector__button-content')}>
@@ -16,6 +16,7 @@ const SchemaViewerColumns = {
16
16
  name: 'Name',
17
17
  key: 'Key',
18
18
  type: 'Type',
19
+ notNull: 'NotNull',
19
20
  };
20
21
 
21
22
  class SchemaViewer extends React.Component {
@@ -59,6 +60,17 @@ class SchemaViewer extends React.Component {
59
60
  name: SchemaViewerColumns.type,
60
61
  width: 100,
61
62
  },
63
+ {
64
+ name: SchemaViewerColumns.notNull,
65
+ width: 100,
66
+ render: ({row}) => {
67
+ if (row.NotNull) {
68
+ return '\u2713';
69
+ }
70
+
71
+ return undefined;
72
+ },
73
+ },
62
74
  ];
63
75
 
64
76
  const tableData = [...keyColumns, ...restColumns];
@@ -2,12 +2,14 @@ import {ReactNode} from 'react';
2
2
  import {connect} from 'react-redux';
3
3
  import cn from 'bem-cn-lite';
4
4
 
5
- import {RadioButton, Switch, HelpPopover} from '@gravity-ui/uikit';
5
+ import {RadioButton, Switch} from '@gravity-ui/uikit';
6
6
  import {Settings} from '@gravity-ui/navigation';
7
7
 
8
8
  import favoriteFilledIcon from '../../assets/icons/star.svg';
9
9
  import flaskIcon from '../../assets/icons/flask.svg';
10
10
 
11
+ import {LabelWithPopover} from '../../components/LabelWithPopover/LabelWithPopover';
12
+
11
13
  import {
12
14
  ENABLE_QUERY_MODES_FOR_EXPLAIN,
13
15
  INVERTED_DISKS_KEY,
@@ -46,27 +48,27 @@ function UserSettings(props: any) {
46
48
 
47
49
  const renderBreakNodesSettingsItem = (title: ReactNode) => {
48
50
  return (
49
- <div className={b('item-with-popup')}>
50
- {title}
51
- <HelpPopover
52
- content="Use /viewer/json/nodes endpoint for Nodes Tab in diagnostics. It returns incorrect data on older versions"
53
- contentClassName={b('popup')}
54
- hasArrow={true}
55
- />
56
- </div>
51
+ <LabelWithPopover
52
+ className={b('item-with-popup')}
53
+ contentClassName={b('popup')}
54
+ text={title}
55
+ popoverContent={
56
+ 'Use /viewer/json/nodes endpoint for Nodes Tab in diagnostics. It returns incorrect data on older versions'
57
+ }
58
+ />
57
59
  );
58
60
  };
59
61
 
60
62
  const renderEnableExplainQueryModesItem = (title: ReactNode) => {
61
63
  return (
62
- <div className={b('item-with-popup')}>
63
- {title}
64
- <HelpPopover
65
- content="Enable script | scan query mode selector for both run and explain. May not work on some versions"
66
- contentClassName={b('popup')}
67
- hasArrow={true}
68
- />
69
- </div>
64
+ <LabelWithPopover
65
+ className={b('item-with-popup')}
66
+ contentClassName={b('popup')}
67
+ text={title}
68
+ popoverContent={
69
+ 'Enable script | scan query mode selector for both run and explain. May not work on some versions'
70
+ }
71
+ />
70
72
  );
71
73
  };
72
74
 
@@ -287,7 +287,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
287
287
  stats,
288
288
  timeout: 600000,
289
289
  },
290
- null,
290
+ {},
291
291
  {
292
292
  concurrentId,
293
293
  timeout: 9 * 60 * 1000,
@@ -307,7 +307,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
307
307
  action: action || 'explain',
308
308
  timeout: 600000,
309
309
  },
310
- null,
310
+ {},
311
311
  );
312
312
  }
313
313
  getExplainQueryAst(query: string, database: string) {
@@ -319,7 +319,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
319
319
  action: 'explain-ast',
320
320
  timeout: 600000,
321
321
  },
322
- null,
322
+ {},
323
323
  );
324
324
  }
325
325
  getHotKeys(path: string, enableSampling: boolean) {
@@ -334,18 +334,18 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
334
334
  });
335
335
  }
336
336
  killTablet(id?: string) {
337
- return this.get<string>(this.getPath(`/tablets?KillTabletID=${id}`), null);
337
+ return this.get<string>(this.getPath(`/tablets?KillTabletID=${id}`), {});
338
338
  }
339
339
  stopTablet(id?: string, hiveId?: string) {
340
340
  return this.get<string>(
341
341
  this.getPath(`/tablets/app?TabletID=${hiveId}&page=StopTablet&tablet=${id}`),
342
- null,
342
+ {},
343
343
  );
344
344
  }
345
345
  resumeTablet(id?: string, hiveId?: string) {
346
346
  return this.get<string>(
347
347
  this.getPath(`/tablets/app?TabletID=${hiveId}&page=ResumeTablet&tablet=${id}`),
348
- null,
348
+ {},
349
349
  );
350
350
  }
351
351
  getTabletDescribe(tenantId: TDomainKey) {
@@ -368,14 +368,14 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
368
368
  user,
369
369
  password,
370
370
  },
371
- null,
371
+ {},
372
372
  );
373
373
  }
374
374
  logout() {
375
- return this.post(this.getPath('/logout'), null, null);
375
+ return this.post(this.getPath('/logout'), {}, {});
376
376
  }
377
377
  whoami() {
378
- return this.get<TUserToken>(this.getPath('/viewer/json/whoami'), null);
378
+ return this.get<TUserToken>(this.getPath('/viewer/json/whoami'), {});
379
379
  }
380
380
  }
381
381
 
@@ -116,7 +116,11 @@ export const selectNodeStructure = createSelector(
116
116
  if (!structure[String(pDiskId)]) {
117
117
  structure[String(pDiskId)] = {vDisks: {}, ...vd.PDisk};
118
118
  }
119
- structure[String(pDiskId)].vDisks[vDiskId] = vd;
119
+ structure[String(pDiskId)].vDisks[vDiskId] = {
120
+ ...vd,
121
+ // VDisk doesn't have its own StoragePoolName when located inside StoragePool data
122
+ StoragePoolName: pool.Name,
123
+ };
120
124
  });
121
125
  });
122
126
  });
@@ -4,10 +4,10 @@ import type {
4
4
  NodesListState,
5
5
  NodesListAction,
6
6
  NodesListRootStateSlice,
7
- NodesMap,
8
7
  } from '../../types/store/nodesList';
9
8
  import '../../services/api';
10
9
  import {createRequestActionTypes, createApiRequest} from '../utils';
10
+ import {prepareNodesMap} from '../../utils/nodes';
11
11
 
12
12
  export const FETCH_NODES_LIST = createRequestActionTypes('nodesList', 'FETCH_NODES_LIST');
13
13
 
@@ -50,11 +50,6 @@ export function getNodesList() {
50
50
  }
51
51
 
52
52
  export const selectNodesMap = (state: NodesListRootStateSlice) =>
53
- state.nodesList.data?.reduce<NodesMap>((nodesMap, node) => {
54
- if (node.Id && node.Host) {
55
- nodesMap.set(node.Id, node.Host);
56
- }
57
- return nodesMap;
58
- }, new Map());
53
+ prepareNodesMap(state.nodesList.data);
59
54
 
60
55
  export default nodesList;
@@ -271,10 +271,22 @@ export const getFlatListStorageGroups = createSelector([getStoragePools], (stora
271
271
  ? currentType
272
272
  : 'Mixed';
273
273
  }, '');
274
+
275
+ // VDisk doesn't have its own StoragePoolName when located inside StoragePool data
276
+ const vDisks = group.VDisks?.map((vdisk) => ({
277
+ ...vdisk,
278
+ StoragePoolName: pool.Name,
279
+ Donors: vdisk.Donors?.map((donor) => ({
280
+ ...donor,
281
+ StoragePoolName: pool.Name,
282
+ })),
283
+ }));
284
+
274
285
  return [
275
286
  ...acc,
276
287
  {
277
288
  ...group,
289
+ VDisks: vDisks,
278
290
  Read: readSpeedBytesPerSec,
279
291
  Write: writeSpeedBytesPerSec,
280
292
  PoolName: pool.Name,
@@ -11,6 +11,7 @@ import type {
11
11
  import '../../services/api';
12
12
 
13
13
  import {createRequestActionTypes, createApiRequest} from '../utils';
14
+ import {prepareNodesMap} from '../../utils/nodes';
14
15
 
15
16
  export const FETCH_TABLET = createRequestActionTypes('TABLET', 'FETCH_TABLET');
16
17
  export const FETCH_TABLET_DESCRIBE = createRequestActionTypes('TABLET', 'FETCH_TABLET_DESCRIBE');
@@ -63,9 +64,19 @@ const tablet: Reducer<ITabletState, ITabletAction> = (state = initialState, acti
63
64
 
64
65
  export const getTablet = (id: string) => {
65
66
  return createApiRequest({
66
- request: Promise.all([window.api.getTablet({id}), window.api.getTabletHistory({id})]),
67
+ request: Promise.all([
68
+ window.api.getTablet({id}),
69
+ window.api.getTabletHistory({id}),
70
+ window.api.getNodesList(),
71
+ ]),
67
72
  actions: FETCH_TABLET,
68
- dataHandler: ([tabletResponseData, historyResponseData]): ITabletHandledResponse => {
73
+ dataHandler: ([
74
+ tabletResponseData,
75
+ historyResponseData,
76
+ nodesList,
77
+ ]): ITabletHandledResponse => {
78
+ const nodesMap = prepareNodesMap(nodesList);
79
+
69
80
  const historyData = Object.keys(historyResponseData).reduce<
70
81
  ITabletPreparedHistoryItem[]
71
82
  >((list, nodeId) => {
@@ -75,6 +86,8 @@ export const getTablet = (id: string) => {
75
86
 
76
87
  const {ChangeTime, Generation, State, Leader, FollowerId} = leaderTablet;
77
88
 
89
+ const fqdn = nodesMap && nodeId ? nodesMap.get(Number(nodeId)) : undefined;
90
+
78
91
  list.push({
79
92
  nodeId,
80
93
  generation: Generation,
@@ -82,6 +95,7 @@ export const getTablet = (id: string) => {
82
95
  state: State,
83
96
  leader: Leader,
84
97
  followerId: FollowerId,
98
+ fqdn,
85
99
  });
86
100
  }
87
101
  return list;
@@ -11,6 +11,7 @@ export interface ITabletPreparedHistoryItem {
11
11
  state: ETabletState | undefined;
12
12
  leader: boolean | undefined;
13
13
  followerId: number | undefined;
14
+ fqdn: string | undefined;
14
15
  }
15
16
 
16
17
  export interface ITabletState {
@@ -1,6 +1,6 @@
1
1
  import {Toaster} from '@gravity-ui/uikit';
2
2
 
3
- const toaster = new Toaster();
3
+ export const toaster = new Toaster();
4
4
 
5
5
  interface CreateToastProps {
6
6
  name?: string;
@@ -10,13 +10,13 @@ interface CreateToastProps {
10
10
  }
11
11
 
12
12
  function createToast({name, title, type, content}: CreateToastProps) {
13
- return toaster.createToast({
13
+ return toaster.add({
14
14
  name: name ?? 'Request succeeded',
15
15
  title: title ?? 'Request succeeded',
16
16
  type: type ?? 'success',
17
17
  content: content,
18
18
  isClosable: true,
19
- allowAutoHiding: type === 'success',
19
+ autoHiding: type === 'success' ? 5000 : false,
20
20
  });
21
21
  }
22
22
 
@@ -1,5 +1,7 @@
1
1
  import type {TSystemStateInfo} from '../types/api/nodes';
2
+ import type {TNodeInfo} from '../types/api/nodesList';
2
3
  import type {INodesPreparedEntity} from '../types/store/nodes';
4
+ import type {NodesMap} from '../types/store/nodesList';
3
5
  import {EFlag} from '../types/api/enums';
4
6
 
5
7
  export enum NodesUptimeFilterValues {
@@ -20,3 +22,12 @@ export type NodeAddress = Pick<TSystemStateInfo, 'Host' | 'Endpoints'>;
20
22
  export interface AdditionalNodesInfo extends Record<string, unknown> {
21
23
  getNodeRef?: (node?: NodeAddress) => string;
22
24
  }
25
+
26
+ export const prepareNodesMap = (nodesList?: TNodeInfo[]) => {
27
+ return nodesList?.reduce<NodesMap>((nodesMap, node) => {
28
+ if (node.Id && node.Host) {
29
+ nodesMap.set(Number(node.Id), node.Host);
30
+ }
31
+ return nodesMap;
32
+ }, new Map());
33
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.1.0",
3
+ "version": "4.2.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -12,7 +12,7 @@
12
12
  "@gravity-ui/axios-wrapper": "^1.3.0",
13
13
  "@gravity-ui/date-utils": "^1.1.1",
14
14
  "@gravity-ui/i18n": "^1.0.0",
15
- "@gravity-ui/navigation": "^0.3.1",
15
+ "@gravity-ui/navigation": "^0.4.0",
16
16
  "@gravity-ui/paranoid": "^1.4.0",
17
17
  "@gravity-ui/react-data-table": "^1.0.3",
18
18
  "axios": "0.19.2",
@@ -39,7 +39,7 @@
39
39
  "reselect": "4.1.6",
40
40
  "sass": "1.32.8",
41
41
  "web-vitals": "1.1.2",
42
- "ydb-ui-components": "^3.0.3"
42
+ "ydb-ui-components": "^3.1.0"
43
43
  },
44
44
  "scripts": {
45
45
  "start": "react-app-rewired start",
@@ -105,7 +105,7 @@
105
105
  "@gravity-ui/prettier-config": "^1.0.1",
106
106
  "@gravity-ui/stylelint-config": "^1.0.1",
107
107
  "@gravity-ui/tsconfig": "^1.0.0",
108
- "@gravity-ui/uikit": "^3.20.2",
108
+ "@gravity-ui/uikit": "^4.11.1",
109
109
  "@playwright/test": "^1.31.1",
110
110
  "@testing-library/jest-dom": "^5.15.0",
111
111
  "@testing-library/react": "^11.2.7",