ydb-embedded-ui 4.4.2 → 4.5.1
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 +14 -0
- package/dist/components/ContentWithPopup/ContentWithPopup.tsx +51 -0
- package/dist/components/CriticalActionDialog/CriticalActionDialog.tsx +3 -0
- package/dist/components/ExternalLinkWithIcon/ExternalLinkWithIcon.scss +7 -0
- package/dist/components/ExternalLinkWithIcon/ExternalLinkWithIcon.tsx +24 -0
- package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -2
- package/dist/components/PoolBar/PoolBar.scss +6 -1
- package/dist/components/PoolBar/PoolBar.tsx +39 -0
- package/dist/components/PoolsGraph/PoolsGraph.scss +1 -1
- package/dist/components/PoolsGraph/PoolsGraph.tsx +23 -0
- package/dist/components/Tablet/Tablet.scss +4 -1
- package/dist/components/Tablet/Tablet.tsx +11 -35
- package/dist/components/{Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.scss → TooltipsContent/NodeEndpointsTooltipContent/NodeEndpointsTooltipContent.scss} +1 -1
- package/dist/components/{Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.tsx → TooltipsContent/NodeEndpointsTooltipContent/NodeEndpointsTooltipContent.tsx} +3 -3
- package/dist/components/TooltipsContent/PoolTooltipContent/PoolTooltipContent.tsx +24 -0
- package/dist/components/TooltipsContent/TabletTooltipContent/TabletTooltipContent.tsx +34 -0
- package/dist/components/TooltipsContent/index.ts +3 -0
- package/dist/containers/Cluster/Cluster.tsx +14 -10
- package/dist/containers/{ClusterInfo → Cluster/ClusterInfo}/ClusterInfo.scss +8 -40
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +223 -0
- package/dist/containers/{ClusterInfo → Cluster/ClusterInfo}/utils.ts +1 -1
- package/dist/containers/Cluster/VersionsBar/VersionsBar.scss +27 -0
- package/dist/containers/Cluster/VersionsBar/VersionsBar.tsx +33 -0
- package/dist/containers/Header/Header.tsx +3 -6
- package/dist/containers/Nodes/Nodes.tsx +0 -11
- package/dist/containers/Nodes/getNodesColumns.tsx +3 -20
- package/dist/containers/Tablet/Tablet.scss +4 -0
- package/dist/containers/Tablet/Tablet.tsx +2 -1
- package/dist/containers/Tablet/TabletControls/TabletControls.tsx +19 -27
- package/dist/containers/Tablets/Tablets.tsx +1 -17
- package/dist/containers/TabletsFilters/TabletsFilters.js +2 -14
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +37 -38
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -28
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +4 -14
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +5 -3
- package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +2 -3
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +3 -3
- package/dist/containers/Tenant/Tenant.tsx +14 -15
- package/dist/containers/Tenant/TenantPages.tsx +3 -6
- package/dist/containers/Tenant/utils/schemaActions.ts +4 -4
- package/dist/containers/Tenants/Tenants.js +3 -17
- package/dist/containers/Versions/NodesTable/NodesTable.tsx +4 -34
- package/dist/routes.ts +1 -1
- package/dist/store/reducers/index.ts +1 -1
- package/dist/store/reducers/tenant/constants.ts +19 -0
- package/dist/store/reducers/{tenant.js → tenant/tenant.ts} +27 -36
- package/dist/store/reducers/tenant/types.ts +25 -0
- package/dist/types/additionalProps.ts +11 -0
- package/dist/utils/index.js +2 -1
- package/dist/utils/tooltip.js +8 -80
- package/package.json +2 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.js +0 -25
- package/dist/components/Breadcrumbs/Breadcrumbs.scss +0 -5
- package/dist/components/Collapse/Collapse.js +0 -84
- package/dist/components/Collapse/Collapse.scss +0 -70
- package/dist/components/PoolBar/PoolBar.js +0 -52
- package/dist/components/PoolsGraph/PoolsGraph.js +0 -33
- package/dist/containers/ClusterInfo/ClusterInfo.tsx +0 -207
@@ -0,0 +1,223 @@
|
|
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 EntityStatus from '../../../components/EntityStatus/EntityStatus';
|
8
|
+
import ProgressViewer from '../../../components/ProgressViewer/ProgressViewer';
|
9
|
+
import InfoViewer, {InfoViewerItem} from '../../../components/InfoViewer/InfoViewer';
|
10
|
+
import {Tags} from '../../../components/Tags';
|
11
|
+
import {Tablet} from '../../../components/Tablet';
|
12
|
+
import {Loader} from '../../../components/Loader';
|
13
|
+
import {ResponseError} from '../../../components/Errors/ResponseError';
|
14
|
+
import {ExternalLinkWithIcon} from '../../../components/ExternalLinkWithIcon/ExternalLinkWithIcon';
|
15
|
+
|
16
|
+
import type {
|
17
|
+
AdditionalClusterProps,
|
18
|
+
AdditionalVersionsProps,
|
19
|
+
ClusterLink,
|
20
|
+
} from '../../../types/additionalProps';
|
21
|
+
import type {VersionValue} from '../../../types/versions';
|
22
|
+
import type {TClusterInfo} from '../../../types/api/cluster';
|
23
|
+
import {getClusterNodes} from '../../../store/reducers/clusterNodes/clusterNodes';
|
24
|
+
import {getClusterInfo} from '../../../store/reducers/cluster/cluster';
|
25
|
+
import {backend, customBackend} from '../../../store';
|
26
|
+
import {setHeader} from '../../../store/reducers/header';
|
27
|
+
import {formatStorageValues} from '../../../utils';
|
28
|
+
import {useAutofetcher, useTypedSelector} from '../../../utils/hooks';
|
29
|
+
import {
|
30
|
+
parseVersionsToVersionToColorMap,
|
31
|
+
parseNodesToVersionsValues,
|
32
|
+
} from '../../../utils/versions';
|
33
|
+
import routes, {CLUSTER_PAGES, createHref} from '../../../routes';
|
34
|
+
|
35
|
+
import {Versions} from '../../Versions/Versions';
|
36
|
+
import {VersionsBar} from '../VersionsBar/VersionsBar';
|
37
|
+
|
38
|
+
import {compareTablets} from './utils';
|
39
|
+
|
40
|
+
import './ClusterInfo.scss';
|
41
|
+
|
42
|
+
const b = block('cluster-info');
|
43
|
+
|
44
|
+
const getInfo = (
|
45
|
+
cluster: TClusterInfo,
|
46
|
+
versionsValues: VersionValue[],
|
47
|
+
additionalInfo: InfoViewerItem[],
|
48
|
+
links: ClusterLink[],
|
49
|
+
) => {
|
50
|
+
const info: InfoViewerItem[] = [];
|
51
|
+
|
52
|
+
if (cluster.DataCenters) {
|
53
|
+
info.push({
|
54
|
+
label: 'DC',
|
55
|
+
value: <Tags tags={cluster.DataCenters} />,
|
56
|
+
});
|
57
|
+
}
|
58
|
+
|
59
|
+
if (cluster.SystemTablets) {
|
60
|
+
info.push({
|
61
|
+
label: 'Tablets',
|
62
|
+
value: (
|
63
|
+
<div className={b('system-tablets')}>
|
64
|
+
{cluster.SystemTablets.sort(compareTablets).map((tablet, tabletIndex) => (
|
65
|
+
<Tablet key={tabletIndex} tablet={tablet} />
|
66
|
+
))}
|
67
|
+
</div>
|
68
|
+
),
|
69
|
+
});
|
70
|
+
}
|
71
|
+
|
72
|
+
info.push(
|
73
|
+
{
|
74
|
+
label: 'Nodes',
|
75
|
+
value: (
|
76
|
+
<ProgressViewer
|
77
|
+
className={b('metric-field')}
|
78
|
+
value={cluster?.NodesAlive}
|
79
|
+
capacity={cluster?.NodesTotal}
|
80
|
+
/>
|
81
|
+
),
|
82
|
+
},
|
83
|
+
{
|
84
|
+
label: 'Load',
|
85
|
+
value: (
|
86
|
+
<ProgressViewer
|
87
|
+
className={b('metric-field')}
|
88
|
+
value={cluster?.LoadAverage}
|
89
|
+
capacity={cluster?.NumberOfCpus}
|
90
|
+
/>
|
91
|
+
),
|
92
|
+
},
|
93
|
+
{
|
94
|
+
label: 'Storage',
|
95
|
+
value: (
|
96
|
+
<ProgressViewer
|
97
|
+
className={b('metric-field')}
|
98
|
+
value={cluster?.StorageUsed}
|
99
|
+
capacity={cluster?.StorageTotal}
|
100
|
+
formatValues={formatStorageValues}
|
101
|
+
/>
|
102
|
+
),
|
103
|
+
},
|
104
|
+
...additionalInfo,
|
105
|
+
{
|
106
|
+
label: 'Links',
|
107
|
+
value: (
|
108
|
+
<div className={b('links')}>
|
109
|
+
{links.map(({title, url}) => (
|
110
|
+
<ExternalLinkWithIcon key={title} title={title} url={url} />
|
111
|
+
))}
|
112
|
+
</div>
|
113
|
+
),
|
114
|
+
},
|
115
|
+
{
|
116
|
+
label: 'Versions',
|
117
|
+
value: <VersionsBar versionsValues={versionsValues} />,
|
118
|
+
},
|
119
|
+
);
|
120
|
+
|
121
|
+
return info;
|
122
|
+
};
|
123
|
+
|
124
|
+
interface ClusterInfoProps {
|
125
|
+
clusterTitle?: string;
|
126
|
+
additionalClusterProps?: AdditionalClusterProps;
|
127
|
+
additionalVersionsProps?: AdditionalVersionsProps;
|
128
|
+
}
|
129
|
+
|
130
|
+
export const ClusterInfo = ({
|
131
|
+
clusterTitle,
|
132
|
+
additionalClusterProps = {},
|
133
|
+
additionalVersionsProps = {},
|
134
|
+
}: ClusterInfoProps) => {
|
135
|
+
const dispatch = useDispatch();
|
136
|
+
const location = useLocation();
|
137
|
+
|
138
|
+
const queryParams = qs.parse(location.search, {
|
139
|
+
ignoreQueryPrefix: true,
|
140
|
+
});
|
141
|
+
const {clusterName} = queryParams;
|
142
|
+
|
143
|
+
const {
|
144
|
+
data: cluster = {},
|
145
|
+
loading,
|
146
|
+
wasLoaded,
|
147
|
+
error,
|
148
|
+
} = useTypedSelector((state) => state.cluster);
|
149
|
+
const {
|
150
|
+
nodes,
|
151
|
+
loading: nodesLoading,
|
152
|
+
wasLoaded: nodesWasLoaded,
|
153
|
+
error: nodesError,
|
154
|
+
} = useTypedSelector((state) => state.clusterNodes);
|
155
|
+
const singleClusterMode = useTypedSelector((state) => state.singleClusterMode);
|
156
|
+
|
157
|
+
useEffect(() => {
|
158
|
+
dispatch(
|
159
|
+
setHeader([
|
160
|
+
{
|
161
|
+
text: CLUSTER_PAGES.cluster.title,
|
162
|
+
link: createHref(routes.cluster, {activeTab: CLUSTER_PAGES.cluster.id}),
|
163
|
+
},
|
164
|
+
]),
|
165
|
+
);
|
166
|
+
}, [dispatch]);
|
167
|
+
|
168
|
+
const fetchData = useCallback(() => {
|
169
|
+
dispatch(getClusterInfo(clusterName ? String(clusterName) : undefined));
|
170
|
+
dispatch(getClusterNodes());
|
171
|
+
}, [dispatch, clusterName]);
|
172
|
+
|
173
|
+
useAutofetcher(fetchData, [fetchData], true);
|
174
|
+
|
175
|
+
const versionToColor = useMemo(() => {
|
176
|
+
if (additionalVersionsProps?.getVersionToColorMap) {
|
177
|
+
return additionalVersionsProps.getVersionToColorMap();
|
178
|
+
}
|
179
|
+
return parseVersionsToVersionToColorMap(cluster.Versions);
|
180
|
+
}, [additionalVersionsProps, cluster]);
|
181
|
+
|
182
|
+
const versionsValues = useMemo(() => {
|
183
|
+
return parseNodesToVersionsValues(nodes, versionToColor);
|
184
|
+
}, [nodes, versionToColor]);
|
185
|
+
|
186
|
+
if ((loading && !wasLoaded) || (nodesLoading && !nodesWasLoaded)) {
|
187
|
+
return <Loader size="l" />;
|
188
|
+
}
|
189
|
+
|
190
|
+
if (error || nodesError) {
|
191
|
+
return <ResponseError error={error || nodesError} />;
|
192
|
+
}
|
193
|
+
|
194
|
+
let internalLink = backend + '/internal';
|
195
|
+
|
196
|
+
if (singleClusterMode && !customBackend) {
|
197
|
+
internalLink = `/internal`;
|
198
|
+
}
|
199
|
+
|
200
|
+
const {info = [], links = []} = additionalClusterProps;
|
201
|
+
|
202
|
+
const clusterInfo = getInfo(cluster, versionsValues, info, [
|
203
|
+
{title: 'Internal Viewer', url: internalLink},
|
204
|
+
...links,
|
205
|
+
]);
|
206
|
+
|
207
|
+
return (
|
208
|
+
<div className={b()}>
|
209
|
+
<div className={b('header')}>
|
210
|
+
<div className={b('title')}>
|
211
|
+
<EntityStatus
|
212
|
+
size="m"
|
213
|
+
status={cluster.Overall}
|
214
|
+
name={clusterTitle ?? cluster.Name ?? 'Unknown cluster'}
|
215
|
+
/>
|
216
|
+
</div>
|
217
|
+
<InfoViewer dots={true} info={clusterInfo} />
|
218
|
+
</div>
|
219
|
+
|
220
|
+
<Versions nodes={nodes} versionToColor={versionToColor} />
|
221
|
+
</div>
|
222
|
+
);
|
223
|
+
};
|
@@ -0,0 +1,27 @@
|
|
1
|
+
.ydb-cluster-versions-bar {
|
2
|
+
display: flex;
|
3
|
+
flex-direction: column;
|
4
|
+
|
5
|
+
width: 600px;
|
6
|
+
|
7
|
+
& .yc-progress {
|
8
|
+
width: 100%;
|
9
|
+
}
|
10
|
+
|
11
|
+
&__versions {
|
12
|
+
display: flex;
|
13
|
+
flex-flow: row wrap;
|
14
|
+
|
15
|
+
margin-top: 6px;
|
16
|
+
}
|
17
|
+
|
18
|
+
&__version-title {
|
19
|
+
margin-left: 3px;
|
20
|
+
|
21
|
+
white-space: nowrap;
|
22
|
+
}
|
23
|
+
|
24
|
+
& .yc-progress__stack {
|
25
|
+
cursor: pointer;
|
26
|
+
}
|
27
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import block from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import {Progress} from '@gravity-ui/uikit';
|
4
|
+
|
5
|
+
import type {VersionValue} from '../../../types/versions';
|
6
|
+
|
7
|
+
import './VersionsBar.scss';
|
8
|
+
|
9
|
+
const b = block('ydb-cluster-versions-bar');
|
10
|
+
|
11
|
+
interface VersionsBarProps {
|
12
|
+
versionsValues?: VersionValue[];
|
13
|
+
}
|
14
|
+
|
15
|
+
export const VersionsBar = ({versionsValues = []}: VersionsBarProps) => {
|
16
|
+
return (
|
17
|
+
<div className={b()}>
|
18
|
+
<Progress value={100} stack={versionsValues} view="thin" />
|
19
|
+
<div className={b('versions')}>
|
20
|
+
{versionsValues.map((item, index) => (
|
21
|
+
<div
|
22
|
+
className={b('version-title')}
|
23
|
+
style={{color: item.color}}
|
24
|
+
key={item.version}
|
25
|
+
title={item.version}
|
26
|
+
>
|
27
|
+
{`${item.version}${index === versionsValues.length - 1 ? '' : ','}`}
|
28
|
+
</div>
|
29
|
+
))}
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
);
|
33
|
+
};
|
@@ -2,10 +2,10 @@ import React, {useEffect} from 'react';
|
|
2
2
|
import {useDispatch} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
import {useHistory} from 'react-router';
|
5
|
-
import {Breadcrumbs, BreadcrumbsItem
|
5
|
+
import {Breadcrumbs, BreadcrumbsItem} from '@gravity-ui/uikit';
|
6
6
|
|
7
7
|
import Divider from '../../components/Divider/Divider';
|
8
|
-
import {
|
8
|
+
import {ExternalLinkWithIcon} from '../../components/ExternalLinkWithIcon/ExternalLinkWithIcon';
|
9
9
|
|
10
10
|
import {backend, customBackend} from '../../store';
|
11
11
|
import {getHostInfo} from '../../store/reducers/host';
|
@@ -72,10 +72,7 @@ function Header({clusterName}: HeaderProps) {
|
|
72
72
|
</div>
|
73
73
|
|
74
74
|
<div className={b('cluster-name-wrapper')}>
|
75
|
-
<
|
76
|
-
Internal viewer{' '}
|
77
|
-
<Icon name="external" viewBox={'0 0 16 16'} width={16} height={16} />
|
78
|
-
</Link>
|
75
|
+
<ExternalLinkWithIcon title={'Internal Viewer'} url={link} />
|
79
76
|
{clusterNameFinal && (
|
80
77
|
<React.Fragment>
|
81
78
|
<div className={b('divider')}>
|
@@ -31,7 +31,6 @@ import {
|
|
31
31
|
getComputeNodes,
|
32
32
|
} from '../../store/reducers/nodes';
|
33
33
|
import {changeFilter, ProblemFilterValues} from '../../store/reducers/settings/settings';
|
34
|
-
import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
|
35
34
|
|
36
35
|
import {isDatabaseEntityType} from '../Tenant/utils/schema';
|
37
36
|
|
@@ -129,18 +128,8 @@ export const Nodes = ({path, type, className, additionalNodesInfo = {}}: NodesPr
|
|
129
128
|
);
|
130
129
|
};
|
131
130
|
|
132
|
-
const onShowTooltip = (...args: Parameters<typeof showTooltip>) => {
|
133
|
-
dispatch(showTooltip(...args));
|
134
|
-
};
|
135
|
-
|
136
|
-
const onHideTooltip = () => {
|
137
|
-
dispatch(hideTooltip());
|
138
|
-
};
|
139
|
-
|
140
131
|
const renderTable = () => {
|
141
132
|
const columns = getNodesColumns({
|
142
|
-
showTooltip: onShowTooltip,
|
143
|
-
hideTooltip: onHideTooltip,
|
144
133
|
getNodeRef: additionalNodesInfo.getNodeRef,
|
145
134
|
});
|
146
135
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import DataTable, {Column} from '@gravity-ui/react-data-table';
|
2
2
|
import {Popover} from '@gravity-ui/uikit';
|
3
3
|
|
4
|
-
import PoolsGraph from '../../components/PoolsGraph/PoolsGraph';
|
4
|
+
import {PoolsGraph} from '../../components/PoolsGraph/PoolsGraph';
|
5
5
|
import ProgressViewer from '../../components/ProgressViewer/ProgressViewer';
|
6
6
|
import {TabletsStatistic} from '../../components/TabletsStatistic';
|
7
7
|
import {NodeHostWrapper} from '../../components/NodeHostWrapper/NodeHostWrapper';
|
@@ -10,21 +10,13 @@ import type {NodeAddress} from '../../utils/nodes';
|
|
10
10
|
import {formatBytesToGigabyte} from '../../utils/index';
|
11
11
|
|
12
12
|
import type {INodesPreparedEntity} from '../../types/store/nodes';
|
13
|
-
import {showTooltip as externalShowTooltip} from '../../store/reducers/tooltip';
|
14
13
|
|
15
14
|
interface GetNodesColumnsProps {
|
16
|
-
showTooltip: (...args: Parameters<typeof externalShowTooltip>) => void;
|
17
|
-
hideTooltip: VoidFunction;
|
18
15
|
tabletsPath?: string;
|
19
16
|
getNodeRef?: (node?: NodeAddress) => string;
|
20
17
|
}
|
21
18
|
|
22
|
-
export function getNodesColumns({
|
23
|
-
showTooltip,
|
24
|
-
hideTooltip,
|
25
|
-
tabletsPath,
|
26
|
-
getNodeRef,
|
27
|
-
}: GetNodesColumnsProps) {
|
19
|
+
export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps) {
|
28
20
|
const columns: Column<INodesPreparedEntity>[] = [
|
29
21
|
{
|
30
22
|
name: 'NodeId',
|
@@ -96,16 +88,7 @@ export function getNodesColumns({
|
|
96
88
|
}
|
97
89
|
}, 0),
|
98
90
|
defaultOrder: DataTable.DESCENDING,
|
99
|
-
render: ({row}) =>
|
100
|
-
row.PoolStats ? (
|
101
|
-
<PoolsGraph
|
102
|
-
onMouseEnter={showTooltip}
|
103
|
-
onMouseLeave={hideTooltip}
|
104
|
-
pools={row.PoolStats}
|
105
|
-
/>
|
106
|
-
) : (
|
107
|
-
'—'
|
108
|
-
),
|
91
|
+
render: ({row}) => (row.PoolStats ? <PoolsGraph pools={row.PoolStats} /> : '—'),
|
109
92
|
align: DataTable.LEFT,
|
110
93
|
width: '120px',
|
111
94
|
},
|
@@ -108,9 +108,10 @@ export const Tablet = () => {
|
|
108
108
|
<Icon name="external" />
|
109
109
|
</a>
|
110
110
|
{Leader && <Tag text="Leader" type="blue" />}
|
111
|
+
<span className={b('loader')}>{loading && <Loader size="s" />}</span>
|
111
112
|
</div>
|
112
113
|
<TabletInfo tablet={tablet} tenantPath={tenantPath} />
|
113
|
-
<TabletControls tablet={tablet} />
|
114
|
+
<TabletControls tablet={tablet} fetchData={fetchData} />
|
114
115
|
</div>
|
115
116
|
<div className={b('rigth-pane')}>
|
116
117
|
<TabletTable history={history} />
|
@@ -17,18 +17,19 @@ type VisibleDialogType = EVisibleDialogType | null;
|
|
17
17
|
|
18
18
|
interface TabletControlsProps {
|
19
19
|
tablet: TTabletStateInfo;
|
20
|
+
fetchData: VoidFunction;
|
20
21
|
}
|
21
22
|
|
22
|
-
export const TabletControls = ({tablet}: TabletControlsProps) => {
|
23
|
+
export const TabletControls = ({tablet, fetchData}: TabletControlsProps) => {
|
23
24
|
const {TabletId, HiveId} = tablet;
|
24
25
|
|
25
26
|
const [isDialogVisible, setIsDialogVisible] = useState(false);
|
26
27
|
const [visibleDialogType, setVisibleDialogType] = useState<VisibleDialogType>(null);
|
27
|
-
const [
|
28
|
+
const [isTabletActionLoading, setIsTabletActionLoading] = useState(false);
|
28
29
|
|
29
30
|
// Enable controls after data update
|
30
31
|
useEffect(() => {
|
31
|
-
|
32
|
+
setIsTabletActionLoading(false);
|
32
33
|
}, [tablet]);
|
33
34
|
|
34
35
|
const makeShowDialog = (type: VisibleDialogType) => () => {
|
@@ -46,15 +47,15 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
46
47
|
};
|
47
48
|
|
48
49
|
const _onKillClick = () => {
|
49
|
-
|
50
|
+
setIsTabletActionLoading(true);
|
50
51
|
return window.api.killTablet(TabletId);
|
51
52
|
};
|
52
53
|
const _onStopClick = () => {
|
53
|
-
|
54
|
+
setIsTabletActionLoading(true);
|
54
55
|
return window.api.stopTablet(TabletId, HiveId);
|
55
56
|
};
|
56
57
|
const _onResumeClick = () => {
|
57
|
-
|
58
|
+
setIsTabletActionLoading(true);
|
58
59
|
return window.api.resumeTablet(TabletId, HiveId);
|
59
60
|
};
|
60
61
|
|
@@ -62,25 +63,11 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
62
63
|
return HiveId && HiveId !== '0';
|
63
64
|
};
|
64
65
|
|
65
|
-
const isDisabledResume =
|
66
|
-
|
67
|
-
return true;
|
68
|
-
}
|
69
|
-
|
70
|
-
return tablet.State !== ETabletState.Stopped && tablet.State !== ETabletState.Dead;
|
71
|
-
};
|
72
|
-
|
73
|
-
const isDisabledKill = () => {
|
74
|
-
return isTabletActionsDisabled;
|
75
|
-
};
|
76
|
-
|
77
|
-
const isDisabledStop = () => {
|
78
|
-
if (isTabletActionsDisabled) {
|
79
|
-
return true;
|
80
|
-
}
|
66
|
+
const isDisabledResume =
|
67
|
+
tablet.State !== ETabletState.Stopped && tablet.State !== ETabletState.Dead;
|
81
68
|
|
82
|
-
|
83
|
-
|
69
|
+
const isDisabledStop =
|
70
|
+
tablet.State === ETabletState.Stopped || tablet.State === ETabletState.Deleted;
|
84
71
|
|
85
72
|
const renderDialog = () => {
|
86
73
|
if (!isDialogVisible) {
|
@@ -95,6 +82,7 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
95
82
|
text={i18n('dialog.kill')}
|
96
83
|
onClose={hideDialog}
|
97
84
|
onConfirm={_onKillClick}
|
85
|
+
onConfirmActionFinish={fetchData}
|
98
86
|
/>
|
99
87
|
);
|
100
88
|
}
|
@@ -105,6 +93,7 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
105
93
|
text={i18n('dialog.stop')}
|
106
94
|
onClose={hideDialog}
|
107
95
|
onConfirm={_onStopClick}
|
96
|
+
onConfirmActionFinish={fetchData}
|
108
97
|
/>
|
109
98
|
);
|
110
99
|
}
|
@@ -115,6 +104,7 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
115
104
|
text={i18n('dialog.resume')}
|
116
105
|
onClose={hideDialog}
|
117
106
|
onConfirm={_onResumeClick}
|
107
|
+
onConfirmActionFinish={fetchData}
|
118
108
|
/>
|
119
109
|
);
|
120
110
|
}
|
@@ -128,7 +118,7 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
128
118
|
<Button
|
129
119
|
onClick={showKillDialog}
|
130
120
|
view="action"
|
131
|
-
|
121
|
+
loading={isTabletActionLoading}
|
132
122
|
className={b('control')}
|
133
123
|
>
|
134
124
|
{i18n('controls.kill')}
|
@@ -138,7 +128,8 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
138
128
|
<Button
|
139
129
|
onClick={showStopDialog}
|
140
130
|
view="action"
|
141
|
-
disabled={isDisabledStop
|
131
|
+
disabled={isDisabledStop}
|
132
|
+
loading={!isDisabledStop && isTabletActionLoading}
|
142
133
|
className={b('control')}
|
143
134
|
>
|
144
135
|
{i18n('controls.stop')}
|
@@ -146,7 +137,8 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
146
137
|
<Button
|
147
138
|
onClick={showResumeDialog}
|
148
139
|
view="action"
|
149
|
-
disabled={isDisabledResume
|
140
|
+
disabled={isDisabledResume}
|
141
|
+
loading={!isDisabledResume && isTabletActionLoading}
|
150
142
|
className={b('control')}
|
151
143
|
>
|
152
144
|
{i18n('controls.resume')}
|
@@ -12,7 +12,6 @@ import {Loader} from '../../components/Loader';
|
|
12
12
|
import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
|
13
13
|
import {ETabletState, EType, TTabletStateInfo} from '../../types/api/tablet';
|
14
14
|
|
15
|
-
import {showTooltip, hideTooltip} from '../../store/reducers/tooltip';
|
16
15
|
import {
|
17
16
|
getTabletsInfo,
|
18
17
|
clearWasLoadingFlag,
|
@@ -89,23 +88,8 @@ export const Tablets = ({path, nodeId, className}: TabletsProps) => {
|
|
89
88
|
dispatch(setTypeFilter(value as EType[]));
|
90
89
|
};
|
91
90
|
|
92
|
-
const onShowTooltip = (...args: Parameters<typeof showTooltip>) => {
|
93
|
-
dispatch(showTooltip(...args));
|
94
|
-
};
|
95
|
-
|
96
|
-
const onHideTooltip = () => {
|
97
|
-
dispatch(hideTooltip());
|
98
|
-
};
|
99
|
-
|
100
91
|
const renderTablet = (tabletIndex: number) => {
|
101
|
-
return
|
102
|
-
<Tablet
|
103
|
-
onMouseLeave={onHideTooltip}
|
104
|
-
onMouseEnter={onShowTooltip}
|
105
|
-
tablet={tabletsToRender[tabletIndex]}
|
106
|
-
key={tabletIndex}
|
107
|
-
/>
|
108
|
-
);
|
92
|
+
return <Tablet tablet={tabletsToRender[tabletIndex]} key={tabletIndex} />;
|
109
93
|
};
|
110
94
|
|
111
95
|
const renderContent = () => {
|
@@ -12,7 +12,6 @@ import {Tablet} from '../../components/Tablet';
|
|
12
12
|
import {AccessDenied} from '../../components/Errors/403';
|
13
13
|
|
14
14
|
import {tabletColorToTabletState, tabletStates} from '../../utils/tablet';
|
15
|
-
import {showTooltip, hideTooltip} from '../../store/reducers/tooltip';
|
16
15
|
import {
|
17
16
|
getTabletsInfo,
|
18
17
|
clearWasLoadingFlag,
|
@@ -30,8 +29,6 @@ class TabletsFilters extends React.Component {
|
|
30
29
|
static propTypes = {
|
31
30
|
wasLoaded: PropTypes.bool,
|
32
31
|
loading: PropTypes.bool,
|
33
|
-
showTooltip: PropTypes.func,
|
34
|
-
hideTooltip: PropTypes.func,
|
35
32
|
getTabletsInfo: PropTypes.func,
|
36
33
|
timeoutForRequest: PropTypes.number,
|
37
34
|
path: PropTypes.string,
|
@@ -141,17 +138,10 @@ class TabletsFilters extends React.Component {
|
|
141
138
|
};
|
142
139
|
|
143
140
|
renderTablet = (index, key) => {
|
144
|
-
const {filteredTablets,
|
141
|
+
const {filteredTablets, size} = this.props;
|
145
142
|
|
146
143
|
return (
|
147
|
-
<Tablet
|
148
|
-
onMouseLeave={hideTooltip}
|
149
|
-
onMouseEnter={showTooltip}
|
150
|
-
tablet={filteredTablets[index]}
|
151
|
-
key={key}
|
152
|
-
size={size}
|
153
|
-
className={b('tablet')}
|
154
|
-
/>
|
144
|
+
<Tablet tablet={filteredTablets[index]} key={key} size={size} className={b('tablet')} />
|
155
145
|
);
|
156
146
|
};
|
157
147
|
|
@@ -333,8 +323,6 @@ const mapStateToProps = (state) => {
|
|
333
323
|
|
334
324
|
const mapDispatchToProps = {
|
335
325
|
getTabletsInfo,
|
336
|
-
hideTooltip,
|
337
|
-
showTooltip,
|
338
326
|
clearWasLoadingFlag,
|
339
327
|
setStateFilter,
|
340
328
|
setTypeFilter,
|
@@ -3,13 +3,13 @@ import block from 'bem-cn-lite';
|
|
3
3
|
import qs from 'qs';
|
4
4
|
|
5
5
|
import type {IPreparedConsumerData} from '../../../../../types/store/topic';
|
6
|
+
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
|
6
7
|
import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
|
7
8
|
import {InternalLink} from '../../../../../components/InternalLink';
|
8
9
|
import {formatMsToUptime} from '../../../../../utils';
|
9
10
|
import routes, {createHref} from '../../../../../routes';
|
10
11
|
|
11
12
|
import {TenantTabsGroups} from '../../../TenantPages';
|
12
|
-
import {GeneralPagesIds} from '../../DiagnosticsPages';
|
13
13
|
|
14
14
|
import {
|
15
15
|
CONSUMERS_COLUMNS_IDS,
|
@@ -42,7 +42,7 @@ export const columns: Column<IPreparedConsumerData>[] = [
|
|
42
42
|
<InternalLink
|
43
43
|
to={createHref(routes.tenant, undefined, {
|
44
44
|
...queryParams,
|
45
|
-
[TenantTabsGroups.generalTab]:
|
45
|
+
[TenantTabsGroups.generalTab]: TENANT_DIAGNOSTICS_TABS_IDS.partitions,
|
46
46
|
selectedConsumer: row.name,
|
47
47
|
})}
|
48
48
|
>
|