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.
- package/CHANGELOG.md +23 -0
- package/dist/components/LabelWithPopover/LabelWithPopover.tsx +10 -4
- package/dist/components/TabletsStatistic/TabletsStatistic.scss +1 -1
- package/dist/containers/App/App.scss +7 -4
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +3 -12
- package/dist/containers/Storage/VDisk/VDisk.tsx +4 -11
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +13 -16
- package/dist/containers/Storage/utils/types.ts +2 -1
- package/dist/containers/Tablet/Tablet.scss +4 -0
- package/dist/containers/Tablet/TabletTable/TabletTable.tsx +28 -6
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +4 -3
- package/dist/containers/Tenant/QueryEditor/Issues/Issues.scss +1 -1
- package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +1 -1
- package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +1 -1
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +12 -0
- package/dist/containers/UserSettings/UserSettings.tsx +19 -17
- package/dist/services/api.ts +9 -9
- package/dist/store/reducers/node.js +5 -1
- package/dist/store/reducers/nodesList.ts +2 -7
- package/dist/store/reducers/storage.js +12 -0
- package/dist/store/reducers/tablet.ts +16 -2
- package/dist/types/store/tablet.ts +1 -0
- package/dist/utils/createToast.tsx +3 -3
- package/dist/utils/nodes.ts +11 -0
- 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:
|
6
|
+
text: ReactNode;
|
7
7
|
popoverContent: ReactNode;
|
8
8
|
className?: string;
|
9
|
+
contentClassName?: string;
|
9
10
|
}
|
10
11
|
|
11
|
-
export const LabelWithPopover = ({
|
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
|
);
|
@@ -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
|
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 {
|
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 |
|
53
|
-
poolName?: string;
|
52
|
+
data?: TVDiskStateInfo | UnavailableDonor;
|
54
53
|
nodes?: NodesMap;
|
55
54
|
compact?: boolean;
|
56
55
|
}
|
57
56
|
|
58
|
-
export const VDisk = ({data = {},
|
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 {
|
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:
|
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 (
|
30
|
-
vdiskData.push({label: 'StoragePool', value:
|
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
|
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 (
|
62
|
-
vdiskData.push({label: 'StoragePool', value:
|
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 |
|
132
|
-
poolName?: string;
|
132
|
+
data: TVDiskStateInfo | UnavailableDonor;
|
133
133
|
nodes?: NodesMap;
|
134
134
|
}
|
135
135
|
|
136
|
-
export const VDiskPopup = ({data,
|
136
|
+
export const VDiskPopup = ({data, nodes, ...props}: VDiskPopupProps) => {
|
137
137
|
const isFullData = isFullVDiskData(data);
|
138
138
|
|
139
139
|
const vdiskInfo = useMemo(
|
140
|
-
() =>
|
141
|
-
|
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,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 = {
|
@@ -86,9 +86,10 @@ const prepareTableGeneralInfo = (PartitionConfig: TPartitionConfig, TTLSettings?
|
|
86
86
|
|
87
87
|
const generalTableInfo: InfoViewerItem[] = [];
|
88
88
|
|
89
|
-
const partitioningBySize =
|
90
|
-
|
91
|
-
|
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'
|
@@ -61,7 +61,7 @@ export const QueryEditorControls = ({
|
|
61
61
|
</Button>
|
62
62
|
<DropdownMenu
|
63
63
|
items={querySelectorMenuItems}
|
64
|
-
|
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
|
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
|
-
<
|
50
|
-
{
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
<
|
63
|
-
{
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
|
package/dist/services/api.ts
CHANGED
@@ -287,7 +287,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
287
287
|
stats,
|
288
288
|
timeout: 600000,
|
289
289
|
},
|
290
|
-
|
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
|
-
|
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
|
-
|
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}`),
|
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
|
-
|
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
|
-
|
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
|
-
|
371
|
+
{},
|
372
372
|
);
|
373
373
|
}
|
374
374
|
logout() {
|
375
|
-
return this.post(this.getPath('/logout'),
|
375
|
+
return this.post(this.getPath('/logout'), {}, {});
|
376
376
|
}
|
377
377
|
whoami() {
|
378
|
-
return this.get<TUserToken>(this.getPath('/viewer/json/whoami'),
|
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] =
|
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
|
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([
|
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: ([
|
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;
|
@@ -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.
|
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
|
-
|
19
|
+
autoHiding: type === 'success' ? 5000 : false,
|
20
20
|
});
|
21
21
|
}
|
22
22
|
|
package/dist/utils/nodes.ts
CHANGED
@@ -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
|
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.
|
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
|
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": "^
|
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",
|