ydb-embedded-ui 4.22.0 → 4.24.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 +20 -0
- package/dist/components/ProgressViewer/ProgressViewer.tsx +1 -1
- package/dist/containers/Cluster/Cluster.tsx +2 -0
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +14 -5
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +104 -24
- package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.tsx +1 -1
- package/dist/containers/Cluster/i18n/en.json +16 -0
- package/dist/containers/Cluster/i18n/index.ts +11 -0
- package/dist/containers/Cluster/i18n/ru.json +16 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +18 -3
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +18 -3
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +17 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +20 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +18 -3
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +2 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +19 -2
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +8 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/getSectionTitle.tsx +28 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +17 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +17 -1
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx +19 -11
- package/dist/services/api.ts +1 -2
- package/dist/store/reducers/cluster/__test__/parseGroupsStatsQueryResponse.test.ts +121 -0
- package/dist/store/reducers/cluster/cluster.ts +46 -2
- package/dist/store/reducers/cluster/types.ts +29 -4
- package/dist/store/reducers/cluster/utils.ts +88 -0
- package/dist/store/reducers/settings/settings.ts +14 -6
- package/dist/types/api/cluster.ts +3 -0
- package/dist/utils/hooks/index.ts +1 -0
- package/dist/utils/hooks/useSearchQuery.ts +9 -0
- package/dist/utils/settings.ts +4 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.24.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.23.0...v4.24.0) (2023-12-07)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* always use localStorage if no settingsApi ([#603](https://github.com/ydb-platform/ydb-embedded-ui/issues/603)) ([ff692df](https://github.com/ydb-platform/ydb-embedded-ui/commit/ff692dffa99d278f6b261bbf1aac0ee24c661a6d))
|
9
|
+
|
10
|
+
## [4.23.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.22.0...v4.23.0) (2023-12-06)
|
11
|
+
|
12
|
+
|
13
|
+
### Features
|
14
|
+
|
15
|
+
* **ClusterInfo:** display groups stats ([#598](https://github.com/ydb-platform/ydb-embedded-ui/issues/598)) ([c31d048](https://github.com/ydb-platform/ydb-embedded-ui/commit/c31d0480a1b91cf01a660fd1d9726c6708f7c252))
|
16
|
+
* **TenantOverview:** add links to sections titles ([#599](https://github.com/ydb-platform/ydb-embedded-ui/issues/599)) ([30401fa](https://github.com/ydb-platform/ydb-embedded-ui/commit/30401fa354d90943bc4af4ddbf65466ce10381f9))
|
17
|
+
|
18
|
+
|
19
|
+
### Bug Fixes
|
20
|
+
|
21
|
+
* **Schema:** display keys in right order ([#596](https://github.com/ydb-platform/ydb-embedded-ui/issues/596)) ([c99b7e2](https://github.com/ydb-platform/ydb-embedded-ui/commit/c99b7e2e97acffc1cab450dfbf758c38b8b6e4d5))
|
22
|
+
|
3
23
|
## [4.22.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.21.1...v4.22.0) (2023-11-27)
|
4
24
|
|
5
25
|
|
@@ -44,7 +44,7 @@ Props description:
|
|
44
44
|
interface ProgressViewerProps {
|
45
45
|
value?: number | string;
|
46
46
|
capacity?: number | string;
|
47
|
-
formatValues?: (value?: number, capacity?: number) => (string | undefined)[];
|
47
|
+
formatValues?: (value?: number, capacity?: number) => (string | number | undefined)[];
|
48
48
|
percents?: boolean;
|
49
49
|
className?: string;
|
50
50
|
size?: ProgressViewerSize;
|
@@ -68,6 +68,7 @@ function Cluster({
|
|
68
68
|
loading: clusterLoading,
|
69
69
|
wasLoaded: clusterWasLoaded,
|
70
70
|
error: clusterError,
|
71
|
+
groupsStats,
|
71
72
|
} = useTypedSelector((state) => state.cluster);
|
72
73
|
const {
|
73
74
|
nodes,
|
@@ -135,6 +136,7 @@ function Cluster({
|
|
135
136
|
<div className={b()} ref={container}>
|
136
137
|
<ClusterInfo
|
137
138
|
cluster={cluster}
|
139
|
+
groupsStats={groupsStats}
|
138
140
|
versionsValues={versionsValues}
|
139
141
|
loading={infoLoading}
|
140
142
|
error={clusterError}
|
@@ -49,10 +49,6 @@
|
|
49
49
|
}
|
50
50
|
}
|
51
51
|
|
52
|
-
&__metric-field {
|
53
|
-
margin-top: -8px;
|
54
|
-
}
|
55
|
-
|
56
52
|
&__system-tablets {
|
57
53
|
display: flex;
|
58
54
|
flex-wrap: wrap;
|
@@ -83,7 +79,6 @@
|
|
83
79
|
margin-left: 15px;
|
84
80
|
padding: 0 !important;
|
85
81
|
}
|
86
|
-
|
87
82
|
&__links {
|
88
83
|
display: flex;
|
89
84
|
flex-flow: row wrap;
|
@@ -91,6 +86,20 @@
|
|
91
86
|
gap: 12px;
|
92
87
|
}
|
93
88
|
|
89
|
+
&__storage-groups-stats {
|
90
|
+
display: flex;
|
91
|
+
flex-direction: column;
|
92
|
+
gap: 11px;
|
93
|
+
}
|
94
|
+
|
95
|
+
&__groups-stats-bar {
|
96
|
+
cursor: pointer;
|
97
|
+
}
|
98
|
+
|
99
|
+
&__groups-stats-popup-content {
|
100
|
+
padding: 12px;
|
101
|
+
}
|
102
|
+
|
94
103
|
&__clipboard-button {
|
95
104
|
display: flex;
|
96
105
|
align-items: center;
|
@@ -10,6 +10,7 @@ import {Tablet} from '../../../components/Tablet';
|
|
10
10
|
import {ResponseError} from '../../../components/Errors/ResponseError';
|
11
11
|
import {ExternalLinkWithIcon} from '../../../components/ExternalLinkWithIcon/ExternalLinkWithIcon';
|
12
12
|
import {IconWrapper as Icon} from '../../../components/Icon/Icon';
|
13
|
+
import {ContentWithPopup} from '../../../components/ContentWithPopup/ContentWithPopup';
|
13
14
|
|
14
15
|
import type {IResponseError} from '../../../types/api/error';
|
15
16
|
import type {AdditionalClusterProps, ClusterLink} from '../../../types/additionalProps';
|
@@ -18,14 +19,21 @@ import type {TClusterInfo} from '../../../types/api/cluster';
|
|
18
19
|
import {backend, customBackend} from '../../../store';
|
19
20
|
import {formatStorageValues} from '../../../utils/dataFormatters/dataFormatters';
|
20
21
|
import {useSetting, useTypedSelector} from '../../../utils/hooks';
|
22
|
+
import {formatBytes, getSizeWithSignificantDigits} from '../../../utils/bytesParsers';
|
21
23
|
import {
|
22
24
|
CLUSTER_DEFAULT_TITLE,
|
23
25
|
CLUSTER_INFO_HIDDEN_KEY,
|
24
26
|
DEVELOPER_UI_TITLE,
|
25
27
|
} from '../../../utils/constants';
|
28
|
+
import type {
|
29
|
+
ClusterGroupsStats,
|
30
|
+
DiskErasureGroupsStats,
|
31
|
+
DiskGroupsStats,
|
32
|
+
} from '../../../store/reducers/cluster/types';
|
26
33
|
|
27
34
|
import {VersionsBar} from '../VersionsBar/VersionsBar';
|
28
35
|
import {ClusterInfoSkeleton} from '../ClusterInfoSkeleton/ClusterInfoSkeleton';
|
36
|
+
import i18n from '../i18n';
|
29
37
|
|
30
38
|
import {compareTablets} from './utils';
|
31
39
|
|
@@ -33,9 +41,85 @@ import './ClusterInfo.scss';
|
|
33
41
|
|
34
42
|
const b = block('cluster-info');
|
35
43
|
|
44
|
+
interface GroupsStatsPopupContentProps {
|
45
|
+
stats: DiskErasureGroupsStats;
|
46
|
+
}
|
47
|
+
|
48
|
+
const GroupsStatsPopupContent = ({stats}: GroupsStatsPopupContentProps) => {
|
49
|
+
const {diskType, erasure, allocatedSize, availableSize} = stats;
|
50
|
+
|
51
|
+
const sizeToConvert = getSizeWithSignificantDigits(Math.max(allocatedSize, availableSize), 2);
|
52
|
+
|
53
|
+
const convertedAllocatedSize = formatBytes({value: allocatedSize, size: sizeToConvert});
|
54
|
+
const convertedAvailableSize = formatBytes({value: availableSize, size: sizeToConvert});
|
55
|
+
|
56
|
+
const usage = Math.round((allocatedSize / (allocatedSize + availableSize)) * 100);
|
57
|
+
|
58
|
+
const info = [
|
59
|
+
{
|
60
|
+
label: i18n('disk-type'),
|
61
|
+
value: diskType,
|
62
|
+
},
|
63
|
+
{
|
64
|
+
label: i18n('erasure'),
|
65
|
+
value: erasure,
|
66
|
+
},
|
67
|
+
{
|
68
|
+
label: i18n('allocated'),
|
69
|
+
value: convertedAllocatedSize,
|
70
|
+
},
|
71
|
+
{
|
72
|
+
label: i18n('available'),
|
73
|
+
value: convertedAvailableSize,
|
74
|
+
},
|
75
|
+
{
|
76
|
+
label: i18n('usage'),
|
77
|
+
value: usage + '%',
|
78
|
+
},
|
79
|
+
];
|
80
|
+
|
81
|
+
return (
|
82
|
+
<InfoViewer dots={true} info={info} className={b('groups-stats-popup-content')} size="s" />
|
83
|
+
);
|
84
|
+
};
|
85
|
+
|
86
|
+
interface DiskGroupsStatsProps {
|
87
|
+
stats: DiskGroupsStats;
|
88
|
+
}
|
89
|
+
|
90
|
+
const DiskGroupsStatsBars = ({stats}: DiskGroupsStatsProps) => {
|
91
|
+
return (
|
92
|
+
<div className={b('storage-groups-stats')}>
|
93
|
+
{Object.values(stats).map((erasureStats) => (
|
94
|
+
<ContentWithPopup
|
95
|
+
placement={['right']}
|
96
|
+
key={erasureStats.erasure}
|
97
|
+
content={<GroupsStatsPopupContent stats={erasureStats} />}
|
98
|
+
>
|
99
|
+
<ProgressViewer
|
100
|
+
className={b('groups-stats-bar')}
|
101
|
+
value={erasureStats.createdGroups}
|
102
|
+
capacity={erasureStats.totalGroups}
|
103
|
+
/>
|
104
|
+
</ContentWithPopup>
|
105
|
+
))}
|
106
|
+
</div>
|
107
|
+
);
|
108
|
+
};
|
109
|
+
|
110
|
+
const getGroupsStatsFields = (groupsStats: ClusterGroupsStats) => {
|
111
|
+
return Object.keys(groupsStats).map((diskType) => {
|
112
|
+
return {
|
113
|
+
label: i18n('storage-groups', {diskType}),
|
114
|
+
value: <DiskGroupsStatsBars stats={groupsStats[diskType]} />,
|
115
|
+
};
|
116
|
+
});
|
117
|
+
};
|
118
|
+
|
36
119
|
const getInfo = (
|
37
120
|
cluster: TClusterInfo,
|
38
121
|
versionsValues: VersionValue[],
|
122
|
+
groupsStats: ClusterGroupsStats,
|
39
123
|
additionalInfo: InfoViewerItem[],
|
40
124
|
links: ClusterLink[],
|
41
125
|
) => {
|
@@ -43,14 +127,14 @@ const getInfo = (
|
|
43
127
|
|
44
128
|
if (cluster.DataCenters) {
|
45
129
|
info.push({
|
46
|
-
label: '
|
130
|
+
label: i18n('dc'),
|
47
131
|
value: <Tags tags={cluster.DataCenters} />,
|
48
132
|
});
|
49
133
|
}
|
50
134
|
|
51
135
|
if (cluster.SystemTablets) {
|
52
136
|
info.push({
|
53
|
-
label: '
|
137
|
+
label: i18n('tablets'),
|
54
138
|
value: (
|
55
139
|
<div className={b('system-tablets')}>
|
56
140
|
{cluster.SystemTablets.sort(compareTablets).map((tablet, tabletIndex) => (
|
@@ -63,46 +147,40 @@ const getInfo = (
|
|
63
147
|
|
64
148
|
if (cluster.Tenants) {
|
65
149
|
info.push({
|
66
|
-
label: '
|
150
|
+
label: i18n('databases'),
|
67
151
|
value: cluster.Tenants,
|
68
152
|
});
|
69
153
|
}
|
70
154
|
|
71
155
|
info.push(
|
72
156
|
{
|
73
|
-
label: '
|
74
|
-
value:
|
75
|
-
<ProgressViewer
|
76
|
-
className={b('metric-field')}
|
77
|
-
value={cluster?.NodesAlive}
|
78
|
-
capacity={cluster?.NodesTotal}
|
79
|
-
/>
|
80
|
-
),
|
157
|
+
label: i18n('nodes'),
|
158
|
+
value: <ProgressViewer value={cluster?.NodesAlive} capacity={cluster?.NodesTotal} />,
|
81
159
|
},
|
82
160
|
{
|
83
|
-
label: '
|
84
|
-
value:
|
85
|
-
<ProgressViewer
|
86
|
-
className={b('metric-field')}
|
87
|
-
value={cluster?.LoadAverage}
|
88
|
-
capacity={cluster?.NumberOfCpus}
|
89
|
-
/>
|
90
|
-
),
|
161
|
+
label: i18n('load'),
|
162
|
+
value: <ProgressViewer value={cluster?.LoadAverage} capacity={cluster?.NumberOfCpus} />,
|
91
163
|
},
|
92
164
|
{
|
93
|
-
label: '
|
165
|
+
label: i18n('storage-size'),
|
94
166
|
value: (
|
95
167
|
<ProgressViewer
|
96
|
-
className={b('metric-field')}
|
97
168
|
value={cluster?.StorageUsed}
|
98
169
|
capacity={cluster?.StorageTotal}
|
99
170
|
formatValues={formatStorageValues}
|
100
171
|
/>
|
101
172
|
),
|
102
173
|
},
|
174
|
+
);
|
175
|
+
|
176
|
+
if (Object.keys(groupsStats).length) {
|
177
|
+
info.push(...getGroupsStatsFields(groupsStats));
|
178
|
+
}
|
179
|
+
|
180
|
+
info.push(
|
103
181
|
...additionalInfo,
|
104
182
|
{
|
105
|
-
label: '
|
183
|
+
label: i18n('links'),
|
106
184
|
value: (
|
107
185
|
<div className={b('links')}>
|
108
186
|
{links.map(({title, url}) => (
|
@@ -112,7 +190,7 @@ const getInfo = (
|
|
112
190
|
),
|
113
191
|
},
|
114
192
|
{
|
115
|
-
label: '
|
193
|
+
label: i18n('versions'),
|
116
194
|
value: <VersionsBar versionsValues={versionsValues} />,
|
117
195
|
},
|
118
196
|
);
|
@@ -123,6 +201,7 @@ const getInfo = (
|
|
123
201
|
interface ClusterInfoProps {
|
124
202
|
cluster?: TClusterInfo;
|
125
203
|
versionsValues?: VersionValue[];
|
204
|
+
groupsStats?: ClusterGroupsStats;
|
126
205
|
loading?: boolean;
|
127
206
|
error?: IResponseError;
|
128
207
|
additionalClusterProps?: AdditionalClusterProps;
|
@@ -131,6 +210,7 @@ interface ClusterInfoProps {
|
|
131
210
|
export const ClusterInfo = ({
|
132
211
|
cluster = {},
|
133
212
|
versionsValues = [],
|
213
|
+
groupsStats = {},
|
134
214
|
loading,
|
135
215
|
error,
|
136
216
|
additionalClusterProps = {},
|
@@ -151,7 +231,7 @@ export const ClusterInfo = ({
|
|
151
231
|
|
152
232
|
const {info = [], links = []} = additionalClusterProps;
|
153
233
|
|
154
|
-
const clusterInfo = getInfo(cluster, versionsValues, info, [
|
234
|
+
const clusterInfo = getInfo(cluster, versionsValues, groupsStats, info, [
|
155
235
|
{title: DEVELOPER_UI_TITLE, url: internalLink},
|
156
236
|
...links,
|
157
237
|
]);
|
@@ -18,7 +18,7 @@ interface ClusterInfoSkeletonProps {
|
|
18
18
|
rows?: number;
|
19
19
|
}
|
20
20
|
|
21
|
-
export const ClusterInfoSkeleton = ({rows =
|
21
|
+
export const ClusterInfoSkeleton = ({rows = 8, className}: ClusterInfoSkeletonProps) => (
|
22
22
|
<div className={b(null, className)}>
|
23
23
|
{[...new Array(rows)].map((_, index) => (
|
24
24
|
<div className={b('row')} key={`skeleton-row-${index}`}>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"disk-type": "Disk Type",
|
3
|
+
"erasure": "Erasure",
|
4
|
+
"allocated": "Allocated",
|
5
|
+
"available": "Available",
|
6
|
+
"usage": "Usage",
|
7
|
+
"dc": "DC",
|
8
|
+
"tablets": "Tablets",
|
9
|
+
"databases": "Databases",
|
10
|
+
"nodes": "Nodes",
|
11
|
+
"load": "Load",
|
12
|
+
"storage-size": "Storage size",
|
13
|
+
"storage-groups": "Storage groups, {{diskType}}",
|
14
|
+
"links": "Links",
|
15
|
+
"versions": "Versions"
|
16
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import {i18n, Lang} from '../../../utils/i18n';
|
2
|
+
|
3
|
+
import en from './en.json';
|
4
|
+
import ru from './ru.json';
|
5
|
+
|
6
|
+
const COMPONENT = 'ydb-cluster';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"disk-type": "Тип диска",
|
3
|
+
"erasure": "Режим",
|
4
|
+
"allocated": "Использовано",
|
5
|
+
"available": "Доступно",
|
6
|
+
"usage": "Потребление",
|
7
|
+
"dc": "ДЦ",
|
8
|
+
"tablets": "Таблетки",
|
9
|
+
"databases": "Базы данных",
|
10
|
+
"nodes": "Узлы",
|
11
|
+
"load": "Нагрузка",
|
12
|
+
"storage-size": "Размер хранилища",
|
13
|
+
"storage-groups": "Группы хранения, {{diskType}}",
|
14
|
+
"links": "Ссылки",
|
15
|
+
"versions": "Версии"
|
16
|
+
}
|
@@ -1,16 +1,20 @@
|
|
1
1
|
import {useDispatch} from 'react-redux';
|
2
2
|
import {useCallback} from 'react';
|
3
3
|
|
4
|
-
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
|
4
|
+
import {useAutofetcher, useSearchQuery, useTypedSelector} from '../../../../../utils/hooks';
|
5
5
|
import {
|
6
6
|
getTopNodesByCpu,
|
7
7
|
selectTopNodesByCpu,
|
8
8
|
setDataWasNotLoaded,
|
9
9
|
} from '../../../../../store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu';
|
10
|
+
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
|
10
11
|
import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
|
11
12
|
import {getTopNodesByCpuColumns} from '../../../../Nodes/getNodesColumns';
|
12
|
-
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
13
13
|
|
14
|
+
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
|
15
|
+
|
16
|
+
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
17
|
+
import {getSectionTitle} from '../getSectionTitle';
|
14
18
|
import i18n from '../i18n';
|
15
19
|
|
16
20
|
interface TopNodesByCpuProps {
|
@@ -21,6 +25,8 @@ interface TopNodesByCpuProps {
|
|
21
25
|
export function TopNodesByCpu({path, additionalNodesProps}: TopNodesByCpuProps) {
|
22
26
|
const dispatch = useDispatch();
|
23
27
|
|
28
|
+
const query = useSearchQuery();
|
29
|
+
|
24
30
|
const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByCpu);
|
25
31
|
const {autorefresh} = useTypedSelector((state) => state.schema);
|
26
32
|
const topNodes = useTypedSelector(selectTopNodesByCpu);
|
@@ -39,11 +45,20 @@ export function TopNodesByCpu({path, additionalNodesProps}: TopNodesByCpuProps)
|
|
39
45
|
|
40
46
|
useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
|
41
47
|
|
48
|
+
const title = getSectionTitle({
|
49
|
+
entity: i18n('nodes'),
|
50
|
+
postfix: i18n('by-pools-usage'),
|
51
|
+
link: getTenantPath({
|
52
|
+
...query,
|
53
|
+
[TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.nodes,
|
54
|
+
}),
|
55
|
+
});
|
56
|
+
|
42
57
|
return (
|
43
58
|
<TenantOverviewTableLayout
|
44
59
|
data={topNodes || []}
|
45
60
|
columns={columns}
|
46
|
-
title=
|
61
|
+
title={title}
|
47
62
|
loading={loading}
|
48
63
|
wasLoaded={wasLoaded}
|
49
64
|
error={error}
|
@@ -1,16 +1,20 @@
|
|
1
1
|
import {useDispatch} from 'react-redux';
|
2
2
|
import {useCallback} from 'react';
|
3
3
|
|
4
|
-
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
|
4
|
+
import {useAutofetcher, useSearchQuery, useTypedSelector} from '../../../../../utils/hooks';
|
5
5
|
import {
|
6
6
|
getTopNodesByLoad,
|
7
7
|
selectTopNodesByLoad,
|
8
8
|
setDataWasNotLoaded,
|
9
9
|
} from '../../../../../store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad';
|
10
|
+
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
|
10
11
|
import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
|
11
12
|
import {getTopNodesByLoadColumns} from '../../../../Nodes/getNodesColumns';
|
12
|
-
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
13
13
|
|
14
|
+
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
|
15
|
+
|
16
|
+
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
17
|
+
import {getSectionTitle} from '../getSectionTitle';
|
14
18
|
import i18n from '../i18n';
|
15
19
|
|
16
20
|
interface TopNodesByLoadProps {
|
@@ -21,6 +25,8 @@ interface TopNodesByLoadProps {
|
|
21
25
|
export function TopNodesByLoad({path, additionalNodesProps}: TopNodesByLoadProps) {
|
22
26
|
const dispatch = useDispatch();
|
23
27
|
|
28
|
+
const query = useSearchQuery();
|
29
|
+
|
24
30
|
const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByLoad);
|
25
31
|
const {autorefresh} = useTypedSelector((state) => state.schema);
|
26
32
|
const topNodes = useTypedSelector(selectTopNodesByLoad);
|
@@ -39,11 +45,20 @@ export function TopNodesByLoad({path, additionalNodesProps}: TopNodesByLoadProps
|
|
39
45
|
|
40
46
|
useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
|
41
47
|
|
48
|
+
const title = getSectionTitle({
|
49
|
+
entity: i18n('nodes'),
|
50
|
+
postfix: i18n('by-load'),
|
51
|
+
link: getTenantPath({
|
52
|
+
...query,
|
53
|
+
[TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.nodes,
|
54
|
+
}),
|
55
|
+
});
|
56
|
+
|
42
57
|
return (
|
43
58
|
<TenantOverviewTableLayout
|
44
59
|
data={topNodes || []}
|
45
60
|
columns={columns}
|
46
|
-
title=
|
61
|
+
title={title}
|
47
62
|
loading={loading}
|
48
63
|
wasLoaded={wasLoaded}
|
49
64
|
error={error}
|
@@ -3,6 +3,7 @@ import {useHistory, useLocation} from 'react-router';
|
|
3
3
|
import {useCallback} from 'react';
|
4
4
|
|
5
5
|
import {
|
6
|
+
TENANT_DIAGNOSTICS_TABS_IDS,
|
6
7
|
TENANT_PAGE,
|
7
8
|
TENANT_PAGES_IDS,
|
8
9
|
TENANT_QUERY_TABS_ID,
|
@@ -14,9 +15,13 @@ import {
|
|
14
15
|
import {changeUserInput} from '../../../../../store/reducers/executeQuery';
|
15
16
|
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
|
16
17
|
import {parseQuery} from '../../../../../routes';
|
18
|
+
|
17
19
|
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
|
18
20
|
import {getTenantOverviewTopQueriesColumns} from '../../TopQueries/getTopQueriesColumns';
|
21
|
+
|
19
22
|
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
23
|
+
import {getSectionTitle} from '../getSectionTitle';
|
24
|
+
import i18n from '../i18n';
|
20
25
|
|
21
26
|
interface TopQueriesProps {
|
22
27
|
path: string;
|
@@ -27,6 +32,8 @@ export function TopQueries({path}: TopQueriesProps) {
|
|
27
32
|
const location = useLocation();
|
28
33
|
const history = useHistory();
|
29
34
|
|
35
|
+
const query = parseQuery(location);
|
36
|
+
|
30
37
|
const {autorefresh} = useTypedSelector((state) => state.schema);
|
31
38
|
|
32
39
|
const {
|
@@ -68,12 +75,21 @@ export function TopQueries({path}: TopQueriesProps) {
|
|
68
75
|
[dispatch, history, location],
|
69
76
|
);
|
70
77
|
|
78
|
+
const title = getSectionTitle({
|
79
|
+
entity: i18n('queries'),
|
80
|
+
postfix: i18n('by-cpu-time'),
|
81
|
+
link: getTenantPath({
|
82
|
+
...query,
|
83
|
+
[TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.topQueries,
|
84
|
+
}),
|
85
|
+
});
|
86
|
+
|
71
87
|
return (
|
72
88
|
<TenantOverviewTableLayout
|
73
89
|
data={data || []}
|
74
90
|
columns={columns}
|
75
91
|
onRowClick={handleRowClick}
|
76
|
-
title=
|
92
|
+
title={title}
|
77
93
|
loading={loading}
|
78
94
|
wasLoaded={wasLoaded}
|
79
95
|
error={error}
|
@@ -2,12 +2,20 @@ import {useDispatch} from 'react-redux';
|
|
2
2
|
import {useLocation} from 'react-router';
|
3
3
|
|
4
4
|
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
|
5
|
+
import {parseQuery} from '../../../../../routes';
|
6
|
+
|
5
7
|
import {
|
6
8
|
sendTenantOverviewTopShardsQuery,
|
7
9
|
setDataWasNotLoaded,
|
8
10
|
} from '../../../../../store/reducers/tenantOverview/topShards/tenantOverviewTopShards';
|
11
|
+
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
|
9
12
|
import {getTopShardsColumns} from '../../TopShards/getTopShardsColumns';
|
13
|
+
|
14
|
+
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
|
15
|
+
|
10
16
|
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
17
|
+
import {getSectionTitle} from '../getSectionTitle';
|
18
|
+
import i18n from '../i18n';
|
11
19
|
|
12
20
|
interface TopShardsProps {
|
13
21
|
path: string;
|
@@ -17,6 +25,8 @@ export const TopShards = ({path}: TopShardsProps) => {
|
|
17
25
|
const dispatch = useDispatch();
|
18
26
|
const location = useLocation();
|
19
27
|
|
28
|
+
const query = parseQuery(location);
|
29
|
+
|
20
30
|
const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
|
21
31
|
|
22
32
|
const {
|
@@ -39,11 +49,20 @@ export const TopShards = ({path}: TopShardsProps) => {
|
|
39
49
|
|
40
50
|
const columns = getTopShardsColumns(path, location);
|
41
51
|
|
52
|
+
const title = getSectionTitle({
|
53
|
+
entity: i18n('shards'),
|
54
|
+
postfix: i18n('by-cpu-usage'),
|
55
|
+
link: getTenantPath({
|
56
|
+
...query,
|
57
|
+
[TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.topShards,
|
58
|
+
}),
|
59
|
+
});
|
60
|
+
|
42
61
|
return (
|
43
62
|
<TenantOverviewTableLayout
|
44
63
|
data={data || []}
|
45
64
|
columns={columns}
|
46
|
-
title=
|
65
|
+
title={title}
|
47
66
|
loading={loading}
|
48
67
|
wasLoaded={wasLoaded}
|
49
68
|
error={error}
|
@@ -1,16 +1,20 @@
|
|
1
1
|
import {useDispatch} from 'react-redux';
|
2
2
|
import {useCallback} from 'react';
|
3
3
|
|
4
|
-
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
|
4
|
+
import {useAutofetcher, useTypedSelector, useSearchQuery} from '../../../../../utils/hooks';
|
5
5
|
import {
|
6
6
|
getTopNodesByMemory,
|
7
7
|
selectTopNodesByMemory,
|
8
8
|
setDataWasNotLoaded,
|
9
9
|
} from '../../../../../store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory';
|
10
|
+
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
|
10
11
|
import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
|
11
12
|
import {getTopNodesByMemoryColumns} from '../../../../Nodes/getNodesColumns';
|
12
|
-
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
13
13
|
|
14
|
+
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
|
15
|
+
|
16
|
+
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
17
|
+
import {getSectionTitle} from '../getSectionTitle';
|
14
18
|
import i18n from '../i18n';
|
15
19
|
|
16
20
|
interface TopNodesByMemoryProps {
|
@@ -21,6 +25,8 @@ interface TopNodesByMemoryProps {
|
|
21
25
|
export function TopNodesByMemory({path, additionalNodesProps}: TopNodesByMemoryProps) {
|
22
26
|
const dispatch = useDispatch();
|
23
27
|
|
28
|
+
const query = useSearchQuery();
|
29
|
+
|
24
30
|
const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByMemory);
|
25
31
|
const {autorefresh} = useTypedSelector((state) => state.schema);
|
26
32
|
const topNodes = useTypedSelector(selectTopNodesByMemory);
|
@@ -41,11 +47,20 @@ export function TopNodesByMemory({path, additionalNodesProps}: TopNodesByMemoryP
|
|
41
47
|
|
42
48
|
useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
|
43
49
|
|
50
|
+
const title = getSectionTitle({
|
51
|
+
entity: i18n('nodes'),
|
52
|
+
postfix: i18n('by-memory'),
|
53
|
+
link: getTenantPath({
|
54
|
+
...query,
|
55
|
+
[TenantTabsGroups.diagnosticsTab]: TENANT_DIAGNOSTICS_TABS_IDS.nodes,
|
56
|
+
}),
|
57
|
+
});
|
58
|
+
|
44
59
|
return (
|
45
60
|
<TenantOverviewTableLayout
|
46
61
|
data={topNodes || []}
|
47
62
|
columns={columns}
|
48
|
-
title=
|
63
|
+
title={title}
|
49
64
|
loading={loading}
|
50
65
|
wasLoaded={wasLoaded}
|
51
66
|
error={error}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import type {ReactNode} from 'react';
|
1
2
|
import cn from 'bem-cn-lite';
|
2
3
|
|
3
4
|
import DataTable from '@gravity-ui/react-data-table';
|
@@ -14,7 +15,7 @@ import {ResponseError} from '../../../../components/Errors/ResponseError';
|
|
14
15
|
const b = cn('tenant-overview');
|
15
16
|
|
16
17
|
interface TenantOverviewTableLayoutProps<T> extends Omit<DataTableProps<T>, 'theme'> {
|
17
|
-
title:
|
18
|
+
title: ReactNode;
|
18
19
|
loading?: boolean;
|
19
20
|
wasLoaded?: boolean;
|
20
21
|
error?: IResponseError;
|