ydb-embedded-ui 4.4.2 → 4.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/components/ContentWithPopup/ContentWithPopup.tsx +51 -0
  3. package/dist/components/CriticalActionDialog/CriticalActionDialog.tsx +3 -0
  4. package/dist/components/ExternalLinkWithIcon/ExternalLinkWithIcon.scss +7 -0
  5. package/dist/components/ExternalLinkWithIcon/ExternalLinkWithIcon.tsx +24 -0
  6. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -2
  7. package/dist/components/PoolBar/PoolBar.scss +6 -1
  8. package/dist/components/PoolBar/PoolBar.tsx +39 -0
  9. package/dist/components/PoolsGraph/PoolsGraph.scss +1 -1
  10. package/dist/components/PoolsGraph/PoolsGraph.tsx +23 -0
  11. package/dist/components/Tablet/Tablet.scss +4 -1
  12. package/dist/components/Tablet/Tablet.tsx +11 -35
  13. package/dist/components/{Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.scss → TooltipsContent/NodeEndpointsTooltipContent/NodeEndpointsTooltipContent.scss} +1 -1
  14. package/dist/components/{Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.tsx → TooltipsContent/NodeEndpointsTooltipContent/NodeEndpointsTooltipContent.tsx} +3 -3
  15. package/dist/components/TooltipsContent/PoolTooltipContent/PoolTooltipContent.tsx +24 -0
  16. package/dist/components/TooltipsContent/TabletTooltipContent/TabletTooltipContent.tsx +34 -0
  17. package/dist/components/TooltipsContent/index.ts +3 -0
  18. package/dist/containers/Cluster/Cluster.tsx +14 -10
  19. package/dist/containers/{ClusterInfo → Cluster/ClusterInfo}/ClusterInfo.scss +8 -40
  20. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +223 -0
  21. package/dist/containers/{ClusterInfo → Cluster/ClusterInfo}/utils.ts +1 -1
  22. package/dist/containers/Cluster/VersionsBar/VersionsBar.scss +27 -0
  23. package/dist/containers/Cluster/VersionsBar/VersionsBar.tsx +33 -0
  24. package/dist/containers/Header/Header.tsx +3 -6
  25. package/dist/containers/Nodes/Nodes.tsx +0 -11
  26. package/dist/containers/Nodes/getNodesColumns.tsx +3 -20
  27. package/dist/containers/Tablet/Tablet.scss +4 -0
  28. package/dist/containers/Tablet/Tablet.tsx +2 -1
  29. package/dist/containers/Tablet/TabletControls/TabletControls.tsx +19 -27
  30. package/dist/containers/Tablets/Tablets.tsx +1 -17
  31. package/dist/containers/TabletsFilters/TabletsFilters.js +2 -14
  32. package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +2 -2
  33. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +37 -38
  34. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -28
  35. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +4 -14
  36. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +5 -3
  37. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +2 -3
  38. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +3 -3
  39. package/dist/containers/Tenant/Tenant.tsx +14 -15
  40. package/dist/containers/Tenant/TenantPages.tsx +3 -6
  41. package/dist/containers/Tenant/utils/schemaActions.ts +4 -4
  42. package/dist/containers/Tenants/Tenants.js +3 -17
  43. package/dist/containers/Versions/NodesTable/NodesTable.tsx +4 -34
  44. package/dist/routes.ts +1 -1
  45. package/dist/store/reducers/index.ts +1 -1
  46. package/dist/store/reducers/tenant/constants.ts +19 -0
  47. package/dist/store/reducers/{tenant.js → tenant/tenant.ts} +27 -36
  48. package/dist/store/reducers/tenant/types.ts +25 -0
  49. package/dist/types/additionalProps.ts +11 -0
  50. package/dist/utils/index.js +2 -1
  51. package/dist/utils/tooltip.js +8 -80
  52. package/package.json +2 -1
  53. package/dist/components/Breadcrumbs/Breadcrumbs.js +0 -25
  54. package/dist/components/Breadcrumbs/Breadcrumbs.scss +0 -5
  55. package/dist/components/Collapse/Collapse.js +0 -84
  56. package/dist/components/Collapse/Collapse.scss +0 -70
  57. package/dist/components/PoolBar/PoolBar.js +0 -52
  58. package/dist/components/PoolsGraph/PoolsGraph.js +0 -33
  59. 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
+ };
@@ -1,4 +1,4 @@
1
- import {TTabletStateInfo, EType} from '../../types/api/tablet';
1
+ import {TTabletStateInfo, EType} from '../../../types/api/tablet';
2
2
 
3
3
  export const compareTablets = (tablet1: TTabletStateInfo, tablet2: TTabletStateInfo) => {
4
4
  if (tablet1.Type === EType.TxAllocator) {
@@ -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, Link} from '@gravity-ui/uikit';
5
+ import {Breadcrumbs, BreadcrumbsItem} from '@gravity-ui/uikit';
6
6
 
7
7
  import Divider from '../../components/Divider/Divider';
8
- import {Icon} from '../../components/Icon';
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
- <Link href={link} target="_blank">
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
  },
@@ -52,6 +52,10 @@
52
52
  text-transform: uppercase;
53
53
  }
54
54
 
55
+ &__loader {
56
+ width: 25px;
57
+ }
58
+
55
59
  .info-viewer__items {
56
60
  grid-template-columns: auto;
57
61
  }
@@ -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 [isTabletActionsDisabled, setIsTabletActionsDisabled] = useState(false);
28
+ const [isTabletActionLoading, setIsTabletActionLoading] = useState(false);
28
29
 
29
30
  // Enable controls after data update
30
31
  useEffect(() => {
31
- setIsTabletActionsDisabled(false);
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
- setIsTabletActionsDisabled(true);
50
+ setIsTabletActionLoading(true);
50
51
  return window.api.killTablet(TabletId);
51
52
  };
52
53
  const _onStopClick = () => {
53
- setIsTabletActionsDisabled(true);
54
+ setIsTabletActionLoading(true);
54
55
  return window.api.stopTablet(TabletId, HiveId);
55
56
  };
56
57
  const _onResumeClick = () => {
57
- setIsTabletActionsDisabled(true);
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
- if (isTabletActionsDisabled) {
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
- return tablet.State === ETabletState.Stopped || tablet.State === ETabletState.Deleted;
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
- disabled={isDisabledKill()}
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, hideTooltip, showTooltip, size} = this.props;
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]: GeneralPagesIds.partitions,
45
+ [TenantTabsGroups.generalTab]: TENANT_DIAGNOSTICS_TABS_IDS.partitions,
46
46
  selectedConsumer: row.name,
47
47
  })}
48
48
  >