ydb-embedded-ui 4.3.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.4.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.3.0...v4.4.0) (2023-05-25)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* add Versions ([#394](https://github.com/ydb-platform/ydb-embedded-ui/issues/394)) ([d5abb58](https://github.com/ydb-platform/ydb-embedded-ui/commit/d5abb586a127135c5756a3aa5076060c0dce3fba))
|
9
|
+
* remove unsupported pages ([b2bc3b2](https://github.com/ydb-platform/ydb-embedded-ui/commit/b2bc3b22029679769bb0de73f2c33827028de8a8))
|
10
|
+
|
11
|
+
|
12
|
+
### Bug Fixes
|
13
|
+
|
14
|
+
* **ClusterInfo:** do not show response error on cancelled requests ([83501b5](https://github.com/ydb-platform/ydb-embedded-ui/commit/83501b50f0c266ba654858767ca89a2a3fa891ed))
|
15
|
+
* **Cluster:** remove padding from cluster page ([8138823](https://github.com/ydb-platform/ydb-embedded-ui/commit/8138823a9d5d3dbd1f086fb0bb23265d7faa8025))
|
16
|
+
* **Partitions:** fix columns titles ([4fe21a0](https://github.com/ydb-platform/ydb-embedded-ui/commit/4fe21a0dc149c7bca0611c74990756fbdc5fb273))
|
17
|
+
* **Partitions:** update Select empty value ([a7df6d1](https://github.com/ydb-platform/ydb-embedded-ui/commit/a7df6d1c86224a4534fac048cebc61b6f5a78fde))
|
18
|
+
* **UserSettings:** separate Setting, enable additional settings ([#396](https://github.com/ydb-platform/ydb-embedded-ui/issues/396)) ([e8a17a1](https://github.com/ydb-platform/ydb-embedded-ui/commit/e8a17a160c82212a181b1ef4e3b9f223db29907e))
|
19
|
+
|
3
20
|
## [4.3.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.2.1...v4.3.0) (2023-05-18)
|
4
21
|
|
5
22
|
|
@@ -10,16 +10,13 @@ import routes, {createHref, CLUSTER_PAGES} from '../../routes';
|
|
10
10
|
import Cluster from '../Cluster/Cluster';
|
11
11
|
import Tenant from '../Tenant/Tenant';
|
12
12
|
import Node from '../Node/Node';
|
13
|
-
import Pdisk from '../Pdisk/Pdisk';
|
14
|
-
import Group from '../Group/Group';
|
15
|
-
import Pool from '../Pool/Pool';
|
16
13
|
import {Tablet} from '../Tablet';
|
17
14
|
import TabletsFilters from '../TabletsFilters/TabletsFilters';
|
18
15
|
import ReduxTooltip from '../ReduxTooltip/ReduxTooltip';
|
19
16
|
import Header from '../Header/Header';
|
20
17
|
import AppIcons from '../AppIcons/AppIcons';
|
21
18
|
|
22
|
-
import {
|
19
|
+
import {getParsedSettingValue} from '../../store/reducers/settings';
|
23
20
|
import {THEME_KEY} from '../../utils/constants';
|
24
21
|
|
25
22
|
import './App.scss';
|
@@ -42,10 +39,7 @@ export function Content(props) {
|
|
42
39
|
<Switch>
|
43
40
|
<Route path={routes.cluster} component={Cluster} />
|
44
41
|
<Route path={routes.tenant} component={Tenant} />
|
45
|
-
<Route path={routes.pdisk} component={Pdisk} />
|
46
42
|
<Route path={routes.node} component={Node} />
|
47
|
-
<Route path={routes.group} component={Group} />
|
48
|
-
<Route path={routes.pool} component={Pool} />
|
49
43
|
<Route path={routes.tablet} component={Tablet} />
|
50
44
|
<Route path={routes.tabletsFilters} component={TabletsFilters} />
|
51
45
|
<Redirect
|
@@ -106,7 +100,7 @@ ContentWrapper.propTypes = {
|
|
106
100
|
|
107
101
|
function mapStateToProps(state) {
|
108
102
|
return {
|
109
|
-
theme:
|
103
|
+
theme: getParsedSettingValue(state, THEME_KEY),
|
110
104
|
isAuthenticated: state.authentication.isAuthenticated,
|
111
105
|
singleClusterMode: state.singleClusterMode,
|
112
106
|
};
|
@@ -19,7 +19,7 @@ import userChecked from '../../assets/icons/user-check.svg';
|
|
19
19
|
import settingsIcon from '../../assets/icons/settings.svg';
|
20
20
|
import supportIcon from '../../assets/icons/support.svg';
|
21
21
|
|
22
|
-
import UserSettings from '../UserSettings/UserSettings';
|
22
|
+
import {UserSettings} from '../UserSettings/UserSettings';
|
23
23
|
|
24
24
|
import routes, {createHref, CLUSTER_PAGES} from '../../routes';
|
25
25
|
|
@@ -1,15 +1,15 @@
|
|
1
|
+
import {useRouteMatch} from 'react-router';
|
1
2
|
import cn from 'bem-cn-lite';
|
2
|
-
|
3
|
+
|
4
|
+
import type {AdditionalVersionsProps} from '../../types/additionalProps';
|
5
|
+
import routes, {CLUSTER_PAGES} from '../../routes';
|
6
|
+
|
7
|
+
import {ClusterInfo} from '../ClusterInfo/ClusterInfo';
|
3
8
|
import Tenants from '../Tenants/Tenants';
|
4
|
-
//@ts-ignore
|
5
9
|
import {Nodes} from '../Nodes/Nodes';
|
6
|
-
//@ts-ignore
|
7
10
|
import Storage from '../Storage/Storage';
|
8
|
-
import routes, {CLUSTER_PAGES} from '../../routes';
|
9
11
|
|
10
12
|
import './Cluster.scss';
|
11
|
-
import {useRouteMatch} from 'react-router';
|
12
|
-
import ClusterInfo from '../../components/ClusterInfo/ClusterInfo';
|
13
13
|
|
14
14
|
const b = cn('cluster');
|
15
15
|
|
@@ -17,6 +17,7 @@ interface ClusterProps {
|
|
17
17
|
additionalClusterInfo?: any;
|
18
18
|
additionalTenantsInfo?: any;
|
19
19
|
additionalNodesInfo?: any;
|
20
|
+
additionalVersionsProps?: AdditionalVersionsProps;
|
20
21
|
}
|
21
22
|
|
22
23
|
function Cluster(props: ClusterProps) {
|
@@ -35,7 +36,12 @@ function Cluster(props: ClusterProps) {
|
|
35
36
|
return <Storage {...props} />;
|
36
37
|
}
|
37
38
|
case CLUSTER_PAGES.cluster.id: {
|
38
|
-
return
|
39
|
+
return (
|
40
|
+
<ClusterInfo
|
41
|
+
additionalClusterInfo={props.additionalClusterInfo}
|
42
|
+
additionalVersionsProps={props.additionalVersionsProps}
|
43
|
+
/>
|
44
|
+
);
|
39
45
|
}
|
40
46
|
default: {
|
41
47
|
return null;
|
@@ -43,7 +49,7 @@ function Cluster(props: ClusterProps) {
|
|
43
49
|
}
|
44
50
|
};
|
45
51
|
|
46
|
-
return <div className={b()}>{renderRoutes()}</div>;
|
52
|
+
return <div className={b({tab: activeTab})}>{renderRoutes()}</div>;
|
47
53
|
}
|
48
54
|
|
49
55
|
export default Cluster;
|
@@ -1,7 +1,25 @@
|
|
1
1
|
@import '../../styles/mixins';
|
2
2
|
|
3
3
|
.cluster-info {
|
4
|
+
$_: &;
|
5
|
+
$progress_width: 100%;
|
6
|
+
|
7
|
+
display: flex;
|
8
|
+
flex: 1 1 auto;
|
9
|
+
flex-direction: column;
|
10
|
+
|
4
11
|
width: 100%;
|
12
|
+
|
13
|
+
font-size: var(--yc-text-body-2-font-size);
|
14
|
+
line-height: var(--yc-text-body-2-line-height);
|
15
|
+
|
16
|
+
&__header {
|
17
|
+
padding: 20px;
|
18
|
+
|
19
|
+
border-bottom: 1px solid var(--yc-color-line-generic);
|
20
|
+
background: var(--yc-color-base-background);
|
21
|
+
}
|
22
|
+
|
5
23
|
&__loader {
|
6
24
|
display: flex;
|
7
25
|
justify-content: center;
|
@@ -69,4 +87,25 @@
|
|
69
87
|
|
70
88
|
margin-left: 5px;
|
71
89
|
}
|
90
|
+
&__progress-label {
|
91
|
+
margin: 0 10px 0 0;
|
92
|
+
|
93
|
+
font-weight: 200;
|
94
|
+
}
|
95
|
+
|
96
|
+
&__version-progress {
|
97
|
+
display: flex;
|
98
|
+
align-items: center;
|
99
|
+
|
100
|
+
width: $progress_width;
|
101
|
+
margin-top: 20px;
|
102
|
+
|
103
|
+
& .yc-progress {
|
104
|
+
width: $progress_width;
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
& .yc-progress__stack {
|
109
|
+
cursor: pointer;
|
110
|
+
}
|
72
111
|
}
|
@@ -0,0 +1,207 @@
|
|
1
|
+
import {useCallback, useEffect, useMemo} from 'react';
|
2
|
+
import {useDispatch} from 'react-redux';
|
3
|
+
import {useLocation} from 'react-router';
|
4
|
+
import block from 'bem-cn-lite';
|
5
|
+
import qs from 'qs';
|
6
|
+
|
7
|
+
import {Link, Progress} from '@gravity-ui/uikit';
|
8
|
+
|
9
|
+
import EntityStatus from '../../components/EntityStatus/EntityStatus';
|
10
|
+
import ProgressViewer from '../../components/ProgressViewer/ProgressViewer';
|
11
|
+
import InfoViewer, {InfoViewerItem} from '../../components/InfoViewer/InfoViewer';
|
12
|
+
import {Tags} from '../../components/Tags';
|
13
|
+
import {Tablet} from '../../components/Tablet';
|
14
|
+
import {Icon} from '../../components/Icon';
|
15
|
+
import {Loader} from '../../components/Loader';
|
16
|
+
import {ResponseError} from '../../components/Errors/ResponseError';
|
17
|
+
|
18
|
+
import type {AdditionalVersionsProps} from '../../types/additionalProps';
|
19
|
+
import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
|
20
|
+
import {getClusterInfo} from '../../store/reducers/cluster/cluster';
|
21
|
+
import {getClusterNodes} from '../../store/reducers/clusterNodes/clusterNodes';
|
22
|
+
import {backend, customBackend} from '../../store';
|
23
|
+
import {setHeader} from '../../store/reducers/header';
|
24
|
+
import {formatStorageValues} from '../../utils';
|
25
|
+
import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
|
26
|
+
import {parseVersionsToVersionToColorMap, parseNodesToVersionsValues} from '../../utils/versions';
|
27
|
+
import routes, {CLUSTER_PAGES, createHref} from '../../routes';
|
28
|
+
|
29
|
+
import {Versions} from '../Versions/Versions';
|
30
|
+
|
31
|
+
import {compareTablets} from './utils';
|
32
|
+
|
33
|
+
import './ClusterInfo.scss';
|
34
|
+
|
35
|
+
const b = block('cluster-info');
|
36
|
+
|
37
|
+
interface ClusterInfoProps {
|
38
|
+
clusterTitle?: string;
|
39
|
+
additionalClusterInfo?: InfoViewerItem[];
|
40
|
+
additionalVersionsProps?: AdditionalVersionsProps;
|
41
|
+
}
|
42
|
+
|
43
|
+
export const ClusterInfo = ({
|
44
|
+
clusterTitle,
|
45
|
+
additionalClusterInfo = [],
|
46
|
+
additionalVersionsProps,
|
47
|
+
}: ClusterInfoProps) => {
|
48
|
+
const dispatch = useDispatch();
|
49
|
+
const location = useLocation();
|
50
|
+
|
51
|
+
const queryParams = qs.parse(location.search, {
|
52
|
+
ignoreQueryPrefix: true,
|
53
|
+
});
|
54
|
+
const {clusterName} = queryParams;
|
55
|
+
|
56
|
+
const {data: cluster, loading, wasLoaded, error} = useTypedSelector((state) => state.cluster);
|
57
|
+
const {
|
58
|
+
nodes,
|
59
|
+
loading: nodesLoading,
|
60
|
+
wasLoaded: nodesWasLoaded,
|
61
|
+
error: nodesError,
|
62
|
+
} = useTypedSelector((state) => state.clusterNodes);
|
63
|
+
const singleClusterMode = useTypedSelector((state) => state.singleClusterMode);
|
64
|
+
|
65
|
+
useEffect(() => {
|
66
|
+
dispatch(
|
67
|
+
setHeader([
|
68
|
+
{
|
69
|
+
text: CLUSTER_PAGES.cluster.title,
|
70
|
+
link: createHref(routes.cluster, {activeTab: CLUSTER_PAGES.cluster.id}),
|
71
|
+
},
|
72
|
+
]),
|
73
|
+
);
|
74
|
+
}, [dispatch]);
|
75
|
+
|
76
|
+
const fetchData = useCallback(() => {
|
77
|
+
dispatch(getClusterInfo(clusterName ? String(clusterName) : undefined));
|
78
|
+
dispatch(getClusterNodes());
|
79
|
+
}, [dispatch, clusterName]);
|
80
|
+
|
81
|
+
useAutofetcher(fetchData, [fetchData], true);
|
82
|
+
|
83
|
+
const versionToColor = useMemo(() => {
|
84
|
+
if (additionalVersionsProps?.getVersionToColorMap) {
|
85
|
+
return additionalVersionsProps?.getVersionToColorMap();
|
86
|
+
}
|
87
|
+
return parseVersionsToVersionToColorMap(cluster?.Versions);
|
88
|
+
}, [additionalVersionsProps, cluster]);
|
89
|
+
|
90
|
+
const versionsValues = useMemo(() => {
|
91
|
+
return parseNodesToVersionsValues(nodes, versionToColor);
|
92
|
+
}, [nodes, versionToColor]);
|
93
|
+
|
94
|
+
const onShowTooltip = (...args: Parameters<typeof showTooltip>) => {
|
95
|
+
dispatch(showTooltip(...args));
|
96
|
+
};
|
97
|
+
|
98
|
+
const onHideTooltip = () => {
|
99
|
+
dispatch(hideTooltip());
|
100
|
+
};
|
101
|
+
|
102
|
+
const getInfo = () => {
|
103
|
+
let link = backend + '/internal';
|
104
|
+
|
105
|
+
if (singleClusterMode && !customBackend) {
|
106
|
+
link = `/internal`;
|
107
|
+
}
|
108
|
+
|
109
|
+
const info: InfoViewerItem[] = [
|
110
|
+
{
|
111
|
+
label: 'Nodes',
|
112
|
+
value: (
|
113
|
+
<ProgressViewer
|
114
|
+
className={b('metric-field')}
|
115
|
+
value={cluster?.NodesAlive}
|
116
|
+
capacity={cluster?.NodesTotal}
|
117
|
+
/>
|
118
|
+
),
|
119
|
+
},
|
120
|
+
{
|
121
|
+
label: 'Load',
|
122
|
+
value: (
|
123
|
+
<ProgressViewer
|
124
|
+
className={b('metric-field')}
|
125
|
+
value={cluster?.LoadAverage}
|
126
|
+
capacity={cluster?.NumberOfCpus}
|
127
|
+
/>
|
128
|
+
),
|
129
|
+
},
|
130
|
+
{
|
131
|
+
label: 'Storage',
|
132
|
+
value: (
|
133
|
+
<ProgressViewer
|
134
|
+
className={b('metric-field')}
|
135
|
+
value={cluster?.StorageUsed}
|
136
|
+
capacity={cluster?.StorageTotal}
|
137
|
+
formatValues={formatStorageValues}
|
138
|
+
/>
|
139
|
+
),
|
140
|
+
},
|
141
|
+
{
|
142
|
+
label: 'Versions',
|
143
|
+
value: <div>{cluster?.Versions?.join(', ')}</div>,
|
144
|
+
},
|
145
|
+
...additionalClusterInfo,
|
146
|
+
{
|
147
|
+
label: 'Internal viewer',
|
148
|
+
value: (
|
149
|
+
<Link href={link} target="_blank">
|
150
|
+
<Icon name="external" viewBox={'0 0 16 16'} width={16} height={16} />
|
151
|
+
</Link>
|
152
|
+
),
|
153
|
+
},
|
154
|
+
];
|
155
|
+
|
156
|
+
return info;
|
157
|
+
};
|
158
|
+
|
159
|
+
if ((loading && !wasLoaded) || (nodesLoading && !nodesWasLoaded)) {
|
160
|
+
return <Loader size="l" />;
|
161
|
+
}
|
162
|
+
|
163
|
+
if (error || nodesError) {
|
164
|
+
return <ResponseError error={error || nodesError} />;
|
165
|
+
}
|
166
|
+
|
167
|
+
return (
|
168
|
+
<div className={b()}>
|
169
|
+
<div className={b('header')}>
|
170
|
+
<div className="info">
|
171
|
+
<div className={b('common')}>
|
172
|
+
<div className={b('url')}>
|
173
|
+
<EntityStatus
|
174
|
+
size="m"
|
175
|
+
status={cluster?.Overall}
|
176
|
+
name={clusterTitle ?? cluster?.Name ?? 'Unknown cluster'}
|
177
|
+
/>
|
178
|
+
</div>
|
179
|
+
|
180
|
+
{cluster?.DataCenters && <Tags tags={cluster?.DataCenters} />}
|
181
|
+
|
182
|
+
<div className={b('system-tablets')}>
|
183
|
+
{cluster?.SystemTablets &&
|
184
|
+
cluster.SystemTablets.sort(compareTablets).map(
|
185
|
+
(tablet, tabletIndex) => (
|
186
|
+
<Tablet
|
187
|
+
onMouseEnter={onShowTooltip}
|
188
|
+
onMouseLeave={onHideTooltip}
|
189
|
+
key={tabletIndex}
|
190
|
+
tablet={tablet}
|
191
|
+
/>
|
192
|
+
),
|
193
|
+
)}
|
194
|
+
</div>
|
195
|
+
</div>
|
196
|
+
<InfoViewer dots={true} info={getInfo()} />
|
197
|
+
</div>
|
198
|
+
<div className={b('version-progress')}>
|
199
|
+
<h3 className={b('progress-label')}>Versions</h3>
|
200
|
+
<Progress value={100} stack={versionsValues} />
|
201
|
+
</div>
|
202
|
+
</div>
|
203
|
+
|
204
|
+
<Versions nodes={nodes} versionToColor={versionToColor} />
|
205
|
+
</div>
|
206
|
+
);
|
207
|
+
};
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import {TTabletStateInfo, EType} from '../../types/api/tablet';
|
2
|
+
|
3
|
+
export const compareTablets = (tablet1: TTabletStateInfo, tablet2: TTabletStateInfo) => {
|
4
|
+
if (tablet1.Type === EType.TxAllocator) {
|
5
|
+
return 1;
|
6
|
+
}
|
7
|
+
|
8
|
+
if (tablet2.Type === EType.TxAllocator) {
|
9
|
+
return -1;
|
10
|
+
}
|
11
|
+
|
12
|
+
return 0;
|
13
|
+
};
|
@@ -1,16 +1,16 @@
|
|
1
1
|
import React, {useEffect} from 'react';
|
2
|
-
import {useDispatch
|
2
|
+
import {useDispatch} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
|
-
import {useHistory
|
4
|
+
import {useHistory} from 'react-router';
|
5
5
|
import {Breadcrumbs, BreadcrumbsItem, Link} from '@gravity-ui/uikit';
|
6
6
|
|
7
7
|
import Divider from '../../components/Divider/Divider';
|
8
8
|
import {Icon} from '../../components/Icon';
|
9
9
|
|
10
|
-
import {
|
11
|
-
import {getClusterInfo} from '../../store/reducers/cluster/cluster';
|
10
|
+
import {backend, customBackend} from '../../store';
|
12
11
|
import {getHostInfo} from '../../store/reducers/host';
|
13
12
|
import {HeaderItemType} from '../../store/reducers/header';
|
13
|
+
import {useTypedSelector} from '../../utils/hooks';
|
14
14
|
|
15
15
|
import './Header.scss';
|
16
16
|
|
@@ -31,26 +31,19 @@ interface HeaderProps {
|
|
31
31
|
|
32
32
|
function Header({clusterName}: HeaderProps) {
|
33
33
|
const dispatch = useDispatch();
|
34
|
-
|
34
|
+
|
35
35
|
const {singleClusterMode, header}: {singleClusterMode: boolean; header: HeaderItemType[]} =
|
36
|
-
|
36
|
+
useTypedSelector((state) => state);
|
37
|
+
const {data: host} = useTypedSelector((state) => state.host);
|
37
38
|
|
38
|
-
const location = useLocation();
|
39
39
|
const history = useHistory();
|
40
40
|
|
41
|
-
const {pathname} = location;
|
42
|
-
|
43
41
|
useEffect(() => {
|
44
|
-
const isClustersPage = pathname.includes('/clusters');
|
45
|
-
|
46
|
-
if (!isClustersPage && !clusterName && !singleClusterMode) {
|
47
|
-
dispatch(getClusterInfo(clusterNameLocation));
|
48
|
-
}
|
49
42
|
dispatch(getHostInfo());
|
50
|
-
}, []);
|
43
|
+
}, [dispatch]);
|
51
44
|
|
52
45
|
const renderHeader = () => {
|
53
|
-
const clusterNameFinal = singleClusterMode ? host
|
46
|
+
const clusterNameFinal = singleClusterMode ? host?.ClusterName : clusterName;
|
54
47
|
|
55
48
|
let link = backend + '/internal';
|
56
49
|
|
@@ -21,7 +21,7 @@ import {
|
|
21
21
|
DEFAULT_TABLE_SETTINGS,
|
22
22
|
USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
|
23
23
|
} from '../../utils/constants';
|
24
|
-
import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
|
24
|
+
import {useAutofetcher, useSetting, useTypedSelector} from '../../utils/hooks';
|
25
25
|
import {AdditionalNodesInfo, isUnavailableNode, NodesUptimeFilterValues} from '../../utils/nodes';
|
26
26
|
|
27
27
|
import {setHeader} from '../../store/reducers/header';
|
@@ -33,7 +33,7 @@ import {
|
|
33
33
|
resetNodesState,
|
34
34
|
getComputeNodes,
|
35
35
|
} from '../../store/reducers/nodes';
|
36
|
-
import {changeFilter
|
36
|
+
import {changeFilter} from '../../store/reducers/settings';
|
37
37
|
import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
|
38
38
|
|
39
39
|
import {isDatabaseEntityType} from '../Tenant/utils/schema';
|
@@ -72,14 +72,12 @@ export const Nodes = ({path, type, className, additionalNodesInfo = {}}: NodesPr
|
|
72
72
|
|
73
73
|
const nodes = useTypedSelector(getFilteredPreparedNodesList);
|
74
74
|
|
75
|
-
const useNodesEndpoint =
|
76
|
-
getSettingValue(state, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY),
|
77
|
-
);
|
75
|
+
const [useNodesEndpoint] = useSetting(USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY);
|
78
76
|
|
79
77
|
const fetchNodes = useCallback(() => {
|
80
78
|
// For not DB entities we always use /compute endpoint instead of /nodes
|
81
79
|
// since /nodes can return data only for tenants
|
82
|
-
if (path && (
|
80
|
+
if (path && (useNodesEndpoint || !isDatabaseEntityType(type))) {
|
83
81
|
dispatch(getComputeNodes(path));
|
84
82
|
} else {
|
85
83
|
dispatch(getNodes({tenant: path}));
|
@@ -1,9 +1,8 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import {useSelector} from 'react-redux';
|
3
2
|
import cn from 'bem-cn-lite';
|
4
3
|
|
5
4
|
import {INVERTED_DISKS_KEY} from '../../../utils/constants';
|
6
|
-
import {
|
5
|
+
import {useSetting} from '../../../utils/hooks';
|
7
6
|
|
8
7
|
import './DiskStateProgressBar.scss';
|
9
8
|
|
@@ -35,7 +34,7 @@ export function DiskStateProgressBar({
|
|
35
34
|
severity,
|
36
35
|
compact,
|
37
36
|
}: DiskStateProgressBarProps) {
|
38
|
-
const inverted =
|
37
|
+
const [inverted] = useSetting<boolean | undefined>(INVERTED_DISKS_KEY);
|
39
38
|
|
40
39
|
const renderAllocatedPercent = () => {
|
41
40
|
if (compact) {
|
@@ -28,16 +28,16 @@ export const ReadSessionHeader = () => (
|
|
28
28
|
export const WriteLagsHeader = () => (
|
29
29
|
<LabelWithPopover
|
30
30
|
className={b('lags')}
|
31
|
-
text={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.
|
32
|
-
popoverContent={<LagPopoverContent text={i18n('lagsPopover.
|
31
|
+
text={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.WRITE_LAGS]}
|
32
|
+
popoverContent={<LagPopoverContent text={i18n('lagsPopover.writeLags')} type="write" />}
|
33
33
|
/>
|
34
34
|
);
|
35
35
|
|
36
36
|
export const ReadLagsHeader = () => (
|
37
37
|
<LabelWithPopover
|
38
38
|
className={b('lags')}
|
39
|
-
text={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.
|
40
|
-
popoverContent={<LagPopoverContent text={i18n('lagsPopover.
|
39
|
+
text={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.READ_LAGS]}
|
40
|
+
popoverContent={<LagPopoverContent text={i18n('lagsPopover.readLags')} type="read" />}
|
41
41
|
/>
|
42
42
|
);
|
43
43
|
|
@@ -113,7 +113,7 @@ export const Partitions = ({path}: PartitionsProps) => {
|
|
113
113
|
selectedConsumer && consumers && !consumers.includes(selectedConsumer);
|
114
114
|
|
115
115
|
if (isTopicWithoutConsumers || wrongSelectedConsumer) {
|
116
|
-
dispatch(setSelectedConsumer());
|
116
|
+
dispatch(setSelectedConsumer(''));
|
117
117
|
}
|
118
118
|
}, [dispatch, topicWasLoaded, selectedConsumer, consumers]);
|
119
119
|
|
@@ -125,7 +125,7 @@ export const Partitions = ({path}: PartitionsProps) => {
|
|
125
125
|
setHiddenColumns(newHiddenColumns);
|
126
126
|
};
|
127
127
|
|
128
|
-
const handleSelectedConsumerChange = (value
|
128
|
+
const handleSelectedConsumerChange = (value: string) => {
|
129
129
|
dispatch(setSelectedConsumer(value));
|
130
130
|
};
|
131
131
|
|
package/dist/containers/Tenant/Diagnostics/Partitions/PartitionsControls/PartitionsControls.tsx
CHANGED
@@ -2,7 +2,7 @@ import {useEffect, useMemo, useState} from 'react';
|
|
2
2
|
import {escapeRegExp} from 'lodash/fp';
|
3
3
|
|
4
4
|
import {TableColumnSetupItem} from '@gravity-ui/uikit/build/esm/components/Table/hoc/withTableSettings/withTableSettings';
|
5
|
-
import {Select, TableColumnSetup} from '@gravity-ui/uikit';
|
5
|
+
import {Select, SelectOption, TableColumnSetup} from '@gravity-ui/uikit';
|
6
6
|
|
7
7
|
import type {ValueOf} from '../../../../../types/common';
|
8
8
|
|
@@ -15,8 +15,8 @@ import {b} from '../Partitions';
|
|
15
15
|
|
16
16
|
interface PartitionsControlsProps {
|
17
17
|
consumers: string[] | undefined;
|
18
|
-
selectedConsumer: string
|
19
|
-
onSelectedConsumerChange: (consumer: string
|
18
|
+
selectedConsumer: string;
|
19
|
+
onSelectedConsumerChange: (consumer: string) => void;
|
20
20
|
selectDisabled: boolean;
|
21
21
|
partitions: PreparedPartitionDataWithHosts[] | undefined;
|
22
22
|
onSearchChange: (filteredPartitions: PreparedPartitionDataWithHosts[]) => void;
|
@@ -39,9 +39,6 @@ export const PartitionsControls = ({
|
|
39
39
|
const [generalSearchValue, setGeneralSearchValue] = useState('');
|
40
40
|
const [partitionIdSearchValue, setPartitionIdSearchValue] = useState('');
|
41
41
|
|
42
|
-
// Manual select control to enforce single-select behaviour for multiple select type
|
43
|
-
const [consumerSelectOpen, setConsumerSelectOpen] = useState(false);
|
44
|
-
|
45
42
|
useEffect(() => {
|
46
43
|
if (!partitions) {
|
47
44
|
return;
|
@@ -83,16 +80,17 @@ export const PartitionsControls = ({
|
|
83
80
|
onSearchChange(filteredPartitions);
|
84
81
|
}, [partitionIdSearchValue, generalSearchValue, partitions, onSearchChange]);
|
85
82
|
|
86
|
-
const consumersToSelect = useMemo(
|
87
|
-
|
88
|
-
consumers
|
83
|
+
const consumersToSelect = useMemo(() => {
|
84
|
+
const options =
|
85
|
+
consumers && consumers.length
|
89
86
|
? consumers.map((consumer) => ({
|
90
87
|
value: consumer,
|
91
88
|
content: consumer,
|
92
89
|
}))
|
93
|
-
:
|
94
|
-
|
95
|
-
|
90
|
+
: [];
|
91
|
+
|
92
|
+
return [{value: '', content: i18n('controls.consumerSelector.emptyOption')}, ...options];
|
93
|
+
}, [consumers]);
|
96
94
|
|
97
95
|
const columnsToSelect = useMemo(() => {
|
98
96
|
return initialColumnsIds.map((id) => {
|
@@ -106,10 +104,7 @@ export const PartitionsControls = ({
|
|
106
104
|
}, [initialColumnsIds, hiddenColumns]);
|
107
105
|
|
108
106
|
const handleConsumerSelectChange = (value: string[]) => {
|
109
|
-
|
110
|
-
// The second value is currently chosen consumer
|
111
|
-
onSelectedConsumerChange(value[1]);
|
112
|
-
setConsumerSelectOpen(false);
|
107
|
+
onSelectedConsumerChange(value[0]);
|
113
108
|
};
|
114
109
|
|
115
110
|
const handlePartitionIdSearchChange = (value: string) => {
|
@@ -137,25 +132,24 @@ export const PartitionsControls = ({
|
|
137
132
|
onHiddenColumnsChange(result);
|
138
133
|
};
|
139
134
|
|
135
|
+
const renderOption = (option: SelectOption) => {
|
136
|
+
return (
|
137
|
+
<div className={b('select-option', {empty: option.value === ''})}>{option.content}</div>
|
138
|
+
);
|
139
|
+
};
|
140
|
+
|
140
141
|
return (
|
141
142
|
<div className={b('controls')}>
|
142
143
|
<Select
|
143
144
|
className={b('consumer-select')}
|
144
|
-
placeholder={i18n('controls.consumerSelector.placeholder')}
|
145
145
|
label={i18n('controls.consumerSelector')}
|
146
146
|
options={consumersToSelect}
|
147
|
-
value={[selectedConsumer
|
147
|
+
value={[selectedConsumer]}
|
148
148
|
onUpdate={handleConsumerSelectChange}
|
149
149
|
filterable={consumers && consumers.length > 5}
|
150
150
|
disabled={selectDisabled || !consumers || !consumers.length}
|
151
|
-
|
152
|
-
|
153
|
-
// Although only one value could be selected
|
154
|
-
// Multiple type Select is used
|
155
|
-
// The reason - we need Select to be able to work with no value
|
156
|
-
// And it is easier to make multiple Select close on value change
|
157
|
-
// Than to enable single select to work with empty values
|
158
|
-
multiple
|
151
|
+
renderOption={renderOption}
|
152
|
+
renderSelectedOption={renderOption}
|
159
153
|
/>
|
160
154
|
<Search
|
161
155
|
onChange={handlePartitionIdSearchChange}
|