ydb-embedded-ui 4.3.0 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +17 -0
- package/dist/containers/App/Content.js +2 -8
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +1 -1
- package/dist/containers/Cluster/Cluster.scss +4 -0
- package/dist/containers/Cluster/Cluster.tsx +14 -8
- package/dist/{components → containers}/ClusterInfo/ClusterInfo.scss +39 -0
- package/dist/containers/ClusterInfo/ClusterInfo.tsx +207 -0
- package/dist/containers/ClusterInfo/utils.ts +13 -0
- package/dist/containers/Header/Header.tsx +9 -16
- package/dist/containers/Nodes/Nodes.tsx +4 -6
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +2 -3
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/Headers.tsx +4 -4
- package/dist/containers/Tenant/Diagnostics/Partitions/Partitions.scss +4 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/Partitions.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/Partitions/PartitionsControls/PartitionsControls.tsx +20 -26
- package/dist/containers/Tenant/Diagnostics/Partitions/i18n/en.json +1 -1
- package/dist/containers/Tenant/Diagnostics/Partitions/i18n/ru.json +1 -1
- package/dist/containers/UserSettings/Setting.tsx +82 -0
- package/dist/containers/UserSettings/UserSettings.tsx +61 -99
- package/dist/containers/Versions/GroupedNodesTree/GroupedNodesTree.scss +59 -0
- package/dist/containers/Versions/GroupedNodesTree/GroupedNodesTree.tsx +98 -0
- package/dist/containers/Versions/NodesTable/NodesTable.tsx +150 -0
- package/dist/containers/Versions/NodesTreeTitle/NodesTreeTitle.scss +55 -0
- package/dist/containers/Versions/NodesTreeTitle/NodesTreeTitle.tsx +62 -0
- package/dist/containers/Versions/Versions.scss +32 -0
- package/dist/containers/Versions/Versions.tsx +121 -0
- package/dist/containers/Versions/groupNodes.ts +124 -0
- package/dist/containers/Versions/types.ts +16 -0
- package/dist/routes.ts +0 -6
- package/dist/services/api.ts +3 -0
- package/dist/store/reducers/cluster/cluster.ts +4 -0
- package/dist/store/reducers/cluster/types.ts +3 -2
- package/dist/store/reducers/clusterNodes/clusterNodes.tsx +64 -0
- package/dist/store/reducers/clusterNodes/types.ts +22 -0
- package/dist/store/reducers/index.ts +2 -8
- package/dist/store/reducers/partitions/partitions.ts +2 -2
- package/dist/store/reducers/partitions/types.ts +1 -1
- package/dist/types/additionalProps.ts +5 -0
- package/dist/types/versions.ts +9 -0
- package/dist/utils/constants.ts +0 -11
- package/dist/utils/hooks/useSetting.ts +5 -3
- package/dist/utils/versions/getVersionsColors.ts +98 -0
- package/dist/utils/versions/index.ts +3 -0
- package/dist/utils/versions/parseNodesToVersionsValues.ts +28 -0
- package/dist/utils/versions/parseVersion.ts +23 -0
- package/package.json +1 -1
- package/dist/components/ClusterInfo/ClusterInfo.tsx +0 -239
- package/dist/components/FullGroupViewer/FullGroupViewer.js +0 -147
- package/dist/components/FullGroupViewer/FullGroupViewer.scss +0 -35
- package/dist/components/GroupTreeViewer/GroupTreeViewer.js +0 -87
- package/dist/components/GroupTreeViewer/GroupTreeViewer.scss +0 -16
- package/dist/components/GroupViewer/GroupViewer.js +0 -100
- package/dist/components/GroupViewer/GroupViewer.scss +0 -45
- package/dist/components/PDiskViewer/PDiskViewer.js +0 -79
- package/dist/components/PDiskViewer/PDiskViewer.scss +0 -46
- package/dist/components/TabletsViewer/TabletsViewer.js +0 -44
- package/dist/components/TabletsViewer/TabletsViewer.scss +0 -40
- package/dist/components/VerticalBars/VerticalBars.scss +0 -15
- package/dist/components/VerticalBars/VerticalBars.tsx +0 -38
- package/dist/components/VerticalBars/index.ts +0 -1
- package/dist/containers/Group/Group.js +0 -97
- package/dist/containers/Group/Group.scss +0 -6
- package/dist/containers/Header/Host/Host.js +0 -66
- package/dist/containers/Header/Host/Host.scss +0 -50
- package/dist/containers/Pdisk/Pdisk.js +0 -156
- package/dist/containers/Pdisk/Pdisk.scss +0 -42
- package/dist/containers/Pool/Pool.js +0 -170
- package/dist/containers/Pool/Pool.scss +0 -35
- package/dist/containers/Vdisk/Vdisk.js +0 -158
- package/dist/containers/Vdisk/Vdisk.scss +0 -42
- package/dist/containers/VdiskPdiskNode/VdiskPdiskNode.js +0 -526
- package/dist/containers/VdiskPdiskNode/VdiskPdiskNode.scss +0 -60
- package/dist/store/reducers/group.js +0 -49
- package/dist/store/reducers/pdisk.js +0 -51
- package/dist/store/reducers/pool.js +0 -42
- package/dist/store/reducers/vdisk.js +0 -49
@@ -0,0 +1,62 @@
|
|
1
|
+
import block from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import {Progress} from '@gravity-ui/uikit';
|
4
|
+
|
5
|
+
import type {VersionValue} from '../../../types/versions';
|
6
|
+
import type {PreparedClusterNode} from '../../../store/reducers/clusterNodes/types';
|
7
|
+
import type {GroupedNodesItem} from '../types';
|
8
|
+
|
9
|
+
import './NodesTreeTitle.scss';
|
10
|
+
|
11
|
+
const b = block('ydb-versions-nodes-tree-title');
|
12
|
+
|
13
|
+
interface NodesTreeTitleProps {
|
14
|
+
title?: string;
|
15
|
+
nodes?: PreparedClusterNode[];
|
16
|
+
items?: GroupedNodesItem[];
|
17
|
+
versionColor?: string;
|
18
|
+
versionsValues?: VersionValue[];
|
19
|
+
}
|
20
|
+
|
21
|
+
export const NodesTreeTitle = ({
|
22
|
+
title,
|
23
|
+
nodes,
|
24
|
+
items,
|
25
|
+
versionColor,
|
26
|
+
versionsValues,
|
27
|
+
}: NodesTreeTitleProps) => {
|
28
|
+
let nodesAmount;
|
29
|
+
if (items) {
|
30
|
+
nodesAmount = items.reduce((acc, curr) => {
|
31
|
+
if (!curr.nodes) {
|
32
|
+
return acc;
|
33
|
+
}
|
34
|
+
return acc + curr.nodes.length;
|
35
|
+
}, 0);
|
36
|
+
} else {
|
37
|
+
nodesAmount = nodes ? nodes.length : 0;
|
38
|
+
}
|
39
|
+
|
40
|
+
return (
|
41
|
+
<div className={b('overview')}>
|
42
|
+
<div className={b('overview-container')}>
|
43
|
+
{versionColor ? (
|
44
|
+
<div className={b('version-color')} style={{background: versionColor}} />
|
45
|
+
) : null}
|
46
|
+
<span className={b('overview-title')}>{title}</span>
|
47
|
+
</div>
|
48
|
+
<div className={b('overview-info')}>
|
49
|
+
<div>
|
50
|
+
<span className={b('info-value')}>{nodesAmount}</span>
|
51
|
+
<span className={b('info-label', {margin: 'left'})}>Nodes</span>
|
52
|
+
</div>
|
53
|
+
{versionsValues ? (
|
54
|
+
<div className={b('version-progress')}>
|
55
|
+
<span className={b('info-label', {margin: 'right'})}>Versions</span>
|
56
|
+
<Progress view="thin" value={100} stack={versionsValues} />
|
57
|
+
</div>
|
58
|
+
) : null}
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
);
|
62
|
+
};
|
@@ -0,0 +1,32 @@
|
|
1
|
+
@import '../../styles/mixins.scss';
|
2
|
+
|
3
|
+
.ydb-versions {
|
4
|
+
$_: &;
|
5
|
+
|
6
|
+
&__content {
|
7
|
+
padding: 20px;
|
8
|
+
}
|
9
|
+
|
10
|
+
&__controls {
|
11
|
+
display: flex;
|
12
|
+
align-items: center;
|
13
|
+
|
14
|
+
padding: 0 0 20px;
|
15
|
+
|
16
|
+
#{$_} {
|
17
|
+
&__label {
|
18
|
+
margin-right: 10px;
|
19
|
+
|
20
|
+
font-weight: 500;
|
21
|
+
}
|
22
|
+
|
23
|
+
&__checkbox {
|
24
|
+
margin: 0;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
& > * {
|
29
|
+
margin-right: 25px;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,121 @@
|
|
1
|
+
import {useState} from 'react';
|
2
|
+
import block from 'bem-cn-lite';
|
3
|
+
|
4
|
+
import {Checkbox, RadioButton} from '@gravity-ui/uikit';
|
5
|
+
|
6
|
+
import type {PreparedClusterNode} from '../../store/reducers/clusterNodes/types';
|
7
|
+
import type {VersionToColorMap} from '../../types/versions';
|
8
|
+
import {getGroupedStorageNodes, getGroupedTenantNodes, getOtherNodes} from './groupNodes';
|
9
|
+
import {GroupedNodesTree} from './GroupedNodesTree/GroupedNodesTree';
|
10
|
+
import {GroupByValue} from './types';
|
11
|
+
|
12
|
+
import './Versions.scss';
|
13
|
+
|
14
|
+
const b = block('ydb-versions');
|
15
|
+
|
16
|
+
interface VersionsProps {
|
17
|
+
nodes?: PreparedClusterNode[];
|
18
|
+
versionToColor?: VersionToColorMap;
|
19
|
+
}
|
20
|
+
|
21
|
+
export const Versions = ({nodes = [], versionToColor}: VersionsProps) => {
|
22
|
+
const [groupByValue, setGroupByValue] = useState<GroupByValue>(GroupByValue.VERSION);
|
23
|
+
const [expanded, setExpanded] = useState(false);
|
24
|
+
|
25
|
+
const handleGroupByValueChange = (value: string) => {
|
26
|
+
setGroupByValue(value as GroupByValue);
|
27
|
+
};
|
28
|
+
|
29
|
+
const renderGroupControl = () => {
|
30
|
+
return (
|
31
|
+
<div className={b('group')}>
|
32
|
+
<span className={b('label')}>Group by:</span>
|
33
|
+
<RadioButton value={groupByValue} onUpdate={handleGroupByValueChange}>
|
34
|
+
<RadioButton.Option value={GroupByValue.TENANT}>
|
35
|
+
{GroupByValue.TENANT}
|
36
|
+
</RadioButton.Option>
|
37
|
+
<RadioButton.Option value={GroupByValue.VERSION}>
|
38
|
+
{GroupByValue.VERSION}
|
39
|
+
</RadioButton.Option>
|
40
|
+
</RadioButton>
|
41
|
+
</div>
|
42
|
+
);
|
43
|
+
};
|
44
|
+
const renderControls = () => {
|
45
|
+
return (
|
46
|
+
<div className={b('controls')}>
|
47
|
+
{renderGroupControl()}
|
48
|
+
<Checkbox
|
49
|
+
className={b('checkbox')}
|
50
|
+
onChange={() => setExpanded((value) => !value)}
|
51
|
+
checked={expanded}
|
52
|
+
>
|
53
|
+
All expanded
|
54
|
+
</Checkbox>
|
55
|
+
</div>
|
56
|
+
);
|
57
|
+
};
|
58
|
+
const renderGroupedNodes = () => {
|
59
|
+
const tenantNodes = getGroupedTenantNodes(nodes, versionToColor, groupByValue);
|
60
|
+
const storageNodes = getGroupedStorageNodes(nodes, versionToColor);
|
61
|
+
const otherNodes = getOtherNodes(nodes, versionToColor);
|
62
|
+
const storageNodesContent = storageNodes?.length ? (
|
63
|
+
<>
|
64
|
+
<h3>Storage nodes</h3>
|
65
|
+
{storageNodes.map(({title, nodes: itemNodes, items, versionColor}, index) => (
|
66
|
+
<GroupedNodesTree
|
67
|
+
key={`storage-nodes-${index}`}
|
68
|
+
title={title}
|
69
|
+
nodes={itemNodes}
|
70
|
+
items={items}
|
71
|
+
versionColor={versionColor}
|
72
|
+
/>
|
73
|
+
))}
|
74
|
+
</>
|
75
|
+
) : null;
|
76
|
+
const tenantNodesContent = tenantNodes?.length ? (
|
77
|
+
<>
|
78
|
+
<h3>Database nodes</h3>
|
79
|
+
{renderControls()}
|
80
|
+
{tenantNodes.map(
|
81
|
+
({title, nodes: itemNodes, items, versionColor, versionsValues}, index) => (
|
82
|
+
<GroupedNodesTree
|
83
|
+
key={`tenant-nodes-${index}`}
|
84
|
+
title={title}
|
85
|
+
nodes={itemNodes}
|
86
|
+
items={items}
|
87
|
+
expanded={expanded}
|
88
|
+
versionColor={versionColor}
|
89
|
+
versionsValues={versionsValues}
|
90
|
+
/>
|
91
|
+
),
|
92
|
+
)}
|
93
|
+
</>
|
94
|
+
) : null;
|
95
|
+
const otherNodesContent = otherNodes?.length ? (
|
96
|
+
<>
|
97
|
+
<h3>Other nodes</h3>
|
98
|
+
{otherNodes.map(
|
99
|
+
({title, nodes: itemNodes, items, versionColor, versionsValues}, index) => (
|
100
|
+
<GroupedNodesTree
|
101
|
+
key={`other-nodes-${index}`}
|
102
|
+
title={title}
|
103
|
+
nodes={itemNodes}
|
104
|
+
items={items}
|
105
|
+
versionColor={versionColor}
|
106
|
+
versionsValues={versionsValues}
|
107
|
+
/>
|
108
|
+
),
|
109
|
+
)}
|
110
|
+
</>
|
111
|
+
) : null;
|
112
|
+
return (
|
113
|
+
<div className={b('versions')}>
|
114
|
+
{storageNodesContent}
|
115
|
+
{tenantNodesContent}
|
116
|
+
{otherNodesContent}
|
117
|
+
</div>
|
118
|
+
);
|
119
|
+
};
|
120
|
+
return <div className={b('content')}>{renderGroupedNodes()}</div>;
|
121
|
+
};
|
@@ -0,0 +1,124 @@
|
|
1
|
+
import {groupBy} from 'lodash';
|
2
|
+
|
3
|
+
import type {VersionToColorMap} from '../../types/versions';
|
4
|
+
import type {PreparedClusterNode} from '../../store/reducers/clusterNodes/types';
|
5
|
+
import {getMinorVersion, parseNodesToVersionsValues} from '../../utils/versions';
|
6
|
+
|
7
|
+
import {GroupByValue, GroupedNodesItem} from './types';
|
8
|
+
|
9
|
+
const sortByTitle = (a: GroupedNodesItem, b: GroupedNodesItem) =>
|
10
|
+
a.title?.localeCompare(b.title || '') || -1;
|
11
|
+
|
12
|
+
export const getGroupedTenantNodes = (
|
13
|
+
nodes: PreparedClusterNode[] | undefined,
|
14
|
+
versionToColor: VersionToColorMap | undefined,
|
15
|
+
groupByValue: GroupByValue,
|
16
|
+
): GroupedNodesItem[] | undefined => {
|
17
|
+
if (!nodes || !nodes.length) {
|
18
|
+
return undefined;
|
19
|
+
}
|
20
|
+
|
21
|
+
if (groupByValue === GroupByValue.VERSION) {
|
22
|
+
const dividedByVersion = groupBy(nodes, 'Version');
|
23
|
+
|
24
|
+
return Object.keys(dividedByVersion)
|
25
|
+
.map<GroupedNodesItem | null>((version) => {
|
26
|
+
const filteredNodes = dividedByVersion[version].filter(({Tenants}) =>
|
27
|
+
Boolean(Tenants),
|
28
|
+
);
|
29
|
+
const dividedByTenant = groupBy(filteredNodes, 'Tenants');
|
30
|
+
|
31
|
+
const items = Object.keys(dividedByTenant)
|
32
|
+
.map((tenant) => {
|
33
|
+
return {
|
34
|
+
title: tenant,
|
35
|
+
nodes: dividedByTenant[tenant],
|
36
|
+
};
|
37
|
+
})
|
38
|
+
.sort(sortByTitle);
|
39
|
+
|
40
|
+
if (!items.length) {
|
41
|
+
return null;
|
42
|
+
}
|
43
|
+
|
44
|
+
return {
|
45
|
+
title: version,
|
46
|
+
items: items,
|
47
|
+
versionColor: versionToColor?.get(getMinorVersion(version)),
|
48
|
+
};
|
49
|
+
})
|
50
|
+
.filter((item): item is GroupedNodesItem => Boolean(item));
|
51
|
+
} else {
|
52
|
+
const filteredNodes = nodes.filter(({Tenants}) => Boolean(Tenants));
|
53
|
+
const dividedByTenant = groupBy(filteredNodes, 'Tenants');
|
54
|
+
|
55
|
+
return Object.keys(dividedByTenant)
|
56
|
+
.map<GroupedNodesItem | null>((tenant) => {
|
57
|
+
const versionsValues = parseNodesToVersionsValues(
|
58
|
+
dividedByTenant[tenant],
|
59
|
+
versionToColor,
|
60
|
+
);
|
61
|
+
|
62
|
+
const dividedByVersion = groupBy(dividedByTenant[tenant], 'Version');
|
63
|
+
const preparedItems = Object.keys(dividedByVersion).map((version) => {
|
64
|
+
return {
|
65
|
+
title: version,
|
66
|
+
nodes: dividedByVersion[version],
|
67
|
+
versionColor: versionToColor?.get(getMinorVersion(version)),
|
68
|
+
};
|
69
|
+
});
|
70
|
+
|
71
|
+
if (!preparedItems.length) {
|
72
|
+
return null;
|
73
|
+
}
|
74
|
+
|
75
|
+
return {
|
76
|
+
title: tenant,
|
77
|
+
items: preparedItems,
|
78
|
+
versionsValues,
|
79
|
+
};
|
80
|
+
})
|
81
|
+
.filter((item): item is GroupedNodesItem => Boolean(item))
|
82
|
+
.sort(sortByTitle);
|
83
|
+
}
|
84
|
+
};
|
85
|
+
|
86
|
+
export const getGroupedStorageNodes = (
|
87
|
+
nodes: PreparedClusterNode[] | undefined,
|
88
|
+
versionToColor: VersionToColorMap | undefined,
|
89
|
+
): GroupedNodesItem[] | undefined => {
|
90
|
+
if (!nodes || !nodes.length) {
|
91
|
+
return undefined;
|
92
|
+
}
|
93
|
+
|
94
|
+
const storageNodes = nodes.filter(({Roles}) => Roles?.includes('Storage'));
|
95
|
+
const storageNodesDividedByVersion = groupBy(storageNodes, 'Version');
|
96
|
+
|
97
|
+
return Object.keys(storageNodesDividedByVersion).map((version) => {
|
98
|
+
return {
|
99
|
+
title: version,
|
100
|
+
nodes: storageNodesDividedByVersion[version],
|
101
|
+
versionColor: versionToColor?.get(getMinorVersion(version)),
|
102
|
+
};
|
103
|
+
});
|
104
|
+
};
|
105
|
+
|
106
|
+
export const getOtherNodes = (
|
107
|
+
nodes: PreparedClusterNode[] | undefined,
|
108
|
+
versionToColor: VersionToColorMap | undefined,
|
109
|
+
): GroupedNodesItem[] | undefined => {
|
110
|
+
if (!nodes || !nodes.length) {
|
111
|
+
return undefined;
|
112
|
+
}
|
113
|
+
|
114
|
+
const otherNodes = nodes.filter(({Roles}) => !Roles);
|
115
|
+
const otherNodesDividedByVersion = groupBy(otherNodes, 'Version');
|
116
|
+
|
117
|
+
return Object.keys(otherNodesDividedByVersion).map((version) => {
|
118
|
+
return {
|
119
|
+
title: version,
|
120
|
+
nodes: otherNodesDividedByVersion[version],
|
121
|
+
versionColor: versionToColor?.get(getMinorVersion(version)),
|
122
|
+
};
|
123
|
+
});
|
124
|
+
};
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import type {VersionValue} from '../../types/versions';
|
2
|
+
import type {PreparedClusterNode} from '../../store/reducers/clusterNodes/types';
|
3
|
+
|
4
|
+
export interface GroupedNodesItem {
|
5
|
+
title?: string;
|
6
|
+
nodes?: PreparedClusterNode[];
|
7
|
+
items?: GroupedNodesItem[];
|
8
|
+
versionColor?: string;
|
9
|
+
versionsValues?: VersionValue[];
|
10
|
+
}
|
11
|
+
|
12
|
+
export enum GroupByValue {
|
13
|
+
VERSION = 'Version',
|
14
|
+
TENANT = 'Database',
|
15
|
+
STORAGE = 'Storage',
|
16
|
+
}
|
package/dist/routes.ts
CHANGED
@@ -8,14 +8,8 @@ const routes = {
|
|
8
8
|
cluster: '/cluster/:activeTab?',
|
9
9
|
tenant: '/tenant',
|
10
10
|
node: '/node/:id/:activeTab?',
|
11
|
-
pdisk: '/pdisk/:id',
|
12
|
-
group: '/group/:id',
|
13
|
-
vdisk: '/vdisk',
|
14
|
-
network: '/network',
|
15
|
-
pool: '/pool/:poolName',
|
16
11
|
tablet: '/tablet/:id',
|
17
12
|
tabletsFilters: '/tabletsFilters',
|
18
|
-
clusterPage: '/clusters/:name',
|
19
13
|
auth: '/auth',
|
20
14
|
};
|
21
15
|
|
package/dist/services/api.ts
CHANGED
@@ -50,6 +50,9 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
50
50
|
tablets: true,
|
51
51
|
});
|
52
52
|
}
|
53
|
+
getClusterNodes() {
|
54
|
+
return this.get<TEvSystemStateResponse>(this.getPath('/viewer/json/sysinfo'), {});
|
55
|
+
}
|
53
56
|
getNodeInfo(id?: string) {
|
54
57
|
return this.get<TEvSystemStateResponse>(this.getPath('/viewer/json/sysinfo?enums=true'), {
|
55
58
|
node_id: id,
|
@@ -2,12 +2,13 @@ import {FETCH_CLUSTER} from './cluster';
|
|
2
2
|
|
3
3
|
import type {TClusterInfo} from '../../../types/api/cluster';
|
4
4
|
import type {ApiRequestAction} from '../../utils';
|
5
|
+
import type {IResponseError} from '../../../types/api/error';
|
5
6
|
|
6
7
|
export interface ClusterState {
|
7
8
|
loading: boolean;
|
8
9
|
wasLoaded: boolean;
|
9
10
|
data?: TClusterInfo;
|
10
|
-
error?:
|
11
|
+
error?: IResponseError;
|
11
12
|
}
|
12
13
|
|
13
|
-
export type ClusterAction = ApiRequestAction<typeof FETCH_CLUSTER, TClusterInfo,
|
14
|
+
export type ClusterAction = ApiRequestAction<typeof FETCH_CLUSTER, TClusterInfo, IResponseError>;
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import {Reducer} from 'redux';
|
2
|
+
|
3
|
+
import {createRequestActionTypes, createApiRequest} from '../../utils';
|
4
|
+
|
5
|
+
import type {ClusterNodesAction, ClusterNodesState, PreparedClusterNode} from './types';
|
6
|
+
|
7
|
+
import '../../../services/api';
|
8
|
+
import {calcUptime} from '../../../utils';
|
9
|
+
|
10
|
+
export const FETCH_CLUSTER_NODES = createRequestActionTypes('cluster', 'FETCH_CLUSTER_NODES');
|
11
|
+
|
12
|
+
const initialState = {loading: false, wasLoaded: false};
|
13
|
+
|
14
|
+
const clusterNodes: Reducer<ClusterNodesState, ClusterNodesAction> = (
|
15
|
+
state = initialState,
|
16
|
+
action,
|
17
|
+
) => {
|
18
|
+
switch (action.type) {
|
19
|
+
case FETCH_CLUSTER_NODES.REQUEST: {
|
20
|
+
return {
|
21
|
+
...state,
|
22
|
+
loading: true,
|
23
|
+
};
|
24
|
+
}
|
25
|
+
case FETCH_CLUSTER_NODES.SUCCESS: {
|
26
|
+
const {data = []} = action;
|
27
|
+
|
28
|
+
return {
|
29
|
+
...state,
|
30
|
+
nodes: data,
|
31
|
+
loading: false,
|
32
|
+
wasLoaded: true,
|
33
|
+
error: undefined,
|
34
|
+
};
|
35
|
+
}
|
36
|
+
case FETCH_CLUSTER_NODES.FAILURE: {
|
37
|
+
return {
|
38
|
+
...state,
|
39
|
+
error: action.error,
|
40
|
+
loading: false,
|
41
|
+
};
|
42
|
+
}
|
43
|
+
default:
|
44
|
+
return state;
|
45
|
+
}
|
46
|
+
};
|
47
|
+
|
48
|
+
export function getClusterNodes() {
|
49
|
+
return createApiRequest({
|
50
|
+
request: window.api.getClusterNodes(),
|
51
|
+
actions: FETCH_CLUSTER_NODES,
|
52
|
+
dataHandler: (data): PreparedClusterNode[] => {
|
53
|
+
const {SystemStateInfo: nodes = []} = data;
|
54
|
+
return nodes.map((node) => {
|
55
|
+
return {
|
56
|
+
...node,
|
57
|
+
uptime: calcUptime(node.StartTime),
|
58
|
+
};
|
59
|
+
});
|
60
|
+
},
|
61
|
+
});
|
62
|
+
}
|
63
|
+
|
64
|
+
export default clusterNodes;
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import type {IResponseError} from '../../../types/api/error';
|
2
|
+
import type {TSystemStateInfo} from '../../../types/api/nodes';
|
3
|
+
import type {ApiRequestAction} from '../../utils';
|
4
|
+
|
5
|
+
import {FETCH_CLUSTER_NODES} from './clusterNodes';
|
6
|
+
|
7
|
+
export interface PreparedClusterNode extends TSystemStateInfo {
|
8
|
+
uptime: string;
|
9
|
+
}
|
10
|
+
|
11
|
+
export interface ClusterNodesState {
|
12
|
+
loading: boolean;
|
13
|
+
wasLoaded: boolean;
|
14
|
+
nodes?: PreparedClusterNode[];
|
15
|
+
error?: IResponseError;
|
16
|
+
}
|
17
|
+
|
18
|
+
export type ClusterNodesAction = ApiRequestAction<
|
19
|
+
typeof FETCH_CLUSTER_NODES,
|
20
|
+
PreparedClusterNode[],
|
21
|
+
IResponseError
|
22
|
+
>;
|
@@ -2,19 +2,16 @@ import {combineReducers} from 'redux';
|
|
2
2
|
|
3
3
|
import nodes from './nodes';
|
4
4
|
import cluster from './cluster/cluster';
|
5
|
+
import clusterNodes from './clusterNodes/clusterNodes';
|
5
6
|
import tenant from './tenant';
|
6
7
|
import storage from './storage';
|
7
8
|
import node from './node';
|
8
|
-
import pdisk from './pdisk';
|
9
|
-
import vdisk from './vdisk';
|
10
|
-
import group from './group';
|
11
9
|
import tooltip from './tooltip';
|
12
10
|
import tablets from './tablets';
|
13
11
|
import heatmap from './heatmap';
|
14
12
|
import schema from './schema';
|
15
13
|
import host from './host';
|
16
14
|
import network from './network';
|
17
|
-
import pool from './pool';
|
18
15
|
import tenants from './tenants/tenants';
|
19
16
|
import tablet from './tablet';
|
20
17
|
import topic from './topic';
|
@@ -42,19 +39,16 @@ export const rootReducer = {
|
|
42
39
|
singleClusterMode,
|
43
40
|
nodes,
|
44
41
|
cluster,
|
42
|
+
clusterNodes,
|
45
43
|
tenant,
|
46
44
|
storage,
|
47
45
|
node,
|
48
|
-
pdisk,
|
49
|
-
vdisk,
|
50
|
-
group,
|
51
46
|
tooltip,
|
52
47
|
tablets,
|
53
48
|
schema,
|
54
49
|
olapStats,
|
55
50
|
host,
|
56
51
|
network,
|
57
|
-
pool,
|
58
52
|
tenants,
|
59
53
|
tablet,
|
60
54
|
topic,
|
@@ -15,7 +15,7 @@ const SET_DATA_WAS_NOT_LOADED = 'partitions/SET_DATA_WAS_NOT_LOADED';
|
|
15
15
|
const initialState = {
|
16
16
|
loading: false,
|
17
17
|
wasLoaded: false,
|
18
|
-
selectedConsumer:
|
18
|
+
selectedConsumer: '',
|
19
19
|
};
|
20
20
|
|
21
21
|
const partitions: Reducer<PartitionsState, PartitionsAction> = (state = initialState, action) => {
|
@@ -63,7 +63,7 @@ const partitions: Reducer<PartitionsState, PartitionsAction> = (state = initialS
|
|
63
63
|
}
|
64
64
|
};
|
65
65
|
|
66
|
-
export const setSelectedConsumer = (value
|
66
|
+
export const setSelectedConsumer = (value: string) => {
|
67
67
|
return {
|
68
68
|
type: SET_SELECTED_CONSUMER,
|
69
69
|
data: value,
|
@@ -36,7 +36,7 @@ export interface PreparedPartitionData {
|
|
36
36
|
export interface PartitionsState {
|
37
37
|
loading: boolean;
|
38
38
|
wasLoaded: boolean;
|
39
|
-
selectedConsumer: string
|
39
|
+
selectedConsumer: string;
|
40
40
|
partitions?: PreparedPartitionData[];
|
41
41
|
error?: IResponseError;
|
42
42
|
}
|
package/dist/utils/constants.ts
CHANGED
@@ -2,9 +2,6 @@ import DataTable from '@gravity-ui/react-data-table';
|
|
2
2
|
|
3
3
|
const SECOND = 1000;
|
4
4
|
|
5
|
-
export const GROUP_AUTO_RELOAD_INTERVAL = 10 * SECOND;
|
6
|
-
export const PDISK_AUTO_RELOAD_INTERVAL = 10 * SECOND;
|
7
|
-
export const VDISK_AUTO_RELOAD_INTERVAL = 10 * SECOND;
|
8
5
|
export const AUTO_RELOAD_INTERVAL = 10 * SECOND;
|
9
6
|
// by agreement, display all byte values in decimal scale
|
10
7
|
// values in data are always in bytes, never in higher units,
|
@@ -13,7 +10,6 @@ export const KILOBYTE = 1_000;
|
|
13
10
|
export const MEGABYTE = 1_000_000;
|
14
11
|
export const GIGABYTE = 1_000_000_000;
|
15
12
|
export const TERABYTE = 1_000_000_000_000;
|
16
|
-
export const GROUP = 'group';
|
17
13
|
|
18
14
|
export const MINUTE_IN_SECONDS = 60;
|
19
15
|
export const HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS;
|
@@ -43,8 +39,6 @@ export const TABLET_COLORS = {
|
|
43
39
|
Active: 'lightgreen',
|
44
40
|
};
|
45
41
|
|
46
|
-
export const TxAllocator = 'TxAllocator';
|
47
|
-
|
48
42
|
export const TABLET_SYMBOLS = {
|
49
43
|
OldTxProxy: 'P',
|
50
44
|
TxProxy: 'P',
|
@@ -72,11 +66,6 @@ export const getTabletLabel = (type?: string) => {
|
|
72
66
|
|
73
67
|
export const LOAD_AVERAGE_TIME_INTERVALS = ['1 min', '5 min', '15 min'];
|
74
68
|
|
75
|
-
export const PDISK_CATEGORIES = {
|
76
|
-
0: 'HDD',
|
77
|
-
1: 'SSD',
|
78
|
-
};
|
79
|
-
|
80
69
|
export const COLORS_PRIORITY = {
|
81
70
|
green: 5,
|
82
71
|
yellow: 4,
|
@@ -5,16 +5,18 @@ import {getParsedSettingValue, setSettingValue} from '../../store/reducers/setti
|
|
5
5
|
|
6
6
|
import {useTypedSelector} from './useTypedSelector';
|
7
7
|
|
8
|
-
export const useSetting = <T>(key: string, defaultValue
|
8
|
+
export const useSetting = <T>(key: string, defaultValue?: T): [T, (value: T) => void] => {
|
9
9
|
const dispatch = useDispatch();
|
10
10
|
|
11
11
|
const settingValue: T = useTypedSelector(
|
12
|
-
(state) => getParsedSettingValue(state, key)
|
12
|
+
(state) => getParsedSettingValue(state, key) ?? defaultValue,
|
13
13
|
);
|
14
14
|
|
15
15
|
const setValue = useCallback(
|
16
16
|
(value: T) => {
|
17
|
-
|
17
|
+
const preparedValue = typeof value === 'string' ? value : JSON.stringify(value);
|
18
|
+
|
19
|
+
dispatch(setSettingValue(key, preparedValue));
|
18
20
|
},
|
19
21
|
[dispatch, key],
|
20
22
|
);
|