ydb-embedded-ui 4.19.3 → 4.20.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +16 -0
- package/dist/components/LinkToSchemaObject/LinkToSchemaObject.tsx +20 -0
- package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +3 -2
- package/dist/components/UsageLabel/UsageLabel.scss +6 -0
- package/dist/components/UsageLabel/UsageLabel.tsx +22 -0
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +13 -8
- package/dist/containers/AsideNavigation/i18n/en.json +13 -0
- package/dist/containers/AsideNavigation/i18n/index.ts +11 -0
- package/dist/containers/AsideNavigation/i18n/ru.json +13 -0
- package/dist/containers/Node/NodeStructure/Pdisk.tsx +74 -68
- package/dist/containers/Node/NodeStructure/Vdisk.tsx +9 -33
- package/dist/containers/Nodes/Nodes.tsx +10 -2
- package/dist/containers/Nodes/getNodesColumns.tsx +206 -122
- package/dist/containers/Storage/Storage.tsx +9 -2
- package/dist/containers/Storage/utils/index.ts +1 -22
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -3
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +0 -1
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +4 -2
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +1 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +8 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +11 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/IssuesViewer/IssueTree.tsx +0 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +3 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx +21 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +53 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +53 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +85 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +53 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx +9 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +55 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +40 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +35 -19
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +53 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +15 -7
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -3
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -3
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +0 -2
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +13 -61
- package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +82 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +18 -97
- package/dist/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx +138 -0
- package/dist/containers/Tenant/Info/ExternalTable/ExternalTable.tsx +2 -4
- package/dist/containers/Tenant/Query/ExecuteResult/{ExecuteResult.js → ExecuteResult.tsx} +51 -31
- package/dist/containers/Tenant/Query/Issues/Issues.tsx +4 -6
- package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.tsx +1 -1
- package/dist/containers/Tenant/utils/paneVisibilityToggleHelpers.tsx +1 -1
- package/dist/routes.ts +6 -0
- package/dist/store/reducers/{executeTopQueries.ts → executeTopQueries/executeTopQueries.ts} +23 -75
- package/dist/{types/store/executeTopQueries.ts → store/reducers/executeTopQueries/types.ts} +3 -7
- package/dist/store/reducers/executeTopQueries/utils.ts +36 -0
- package/dist/store/reducers/index.ts +12 -2
- package/dist/store/reducers/nodes/types.ts +1 -0
- package/dist/store/reducers/nodes/utils.ts +16 -6
- package/dist/store/reducers/{shardsWorkload.ts → shardsWorkload/shardsWorkload.ts} +5 -11
- package/dist/{types/store/shardsWorkload.ts → store/reducers/shardsWorkload/types.ts} +3 -7
- package/dist/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts +87 -0
- package/dist/store/reducers/tenantOverview/topNodesByCpu/types.ts +29 -0
- package/dist/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts +87 -0
- package/dist/store/reducers/tenantOverview/topNodesByLoad/types.ts +29 -0
- package/dist/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts +87 -0
- package/dist/store/reducers/tenantOverview/topNodesByMemory/types.ts +29 -0
- package/dist/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts +93 -0
- package/dist/store/reducers/tenantOverview/topQueries/types.ts +14 -0
- package/dist/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts +103 -0
- package/dist/store/reducers/tenantOverview/topShards/types.ts +14 -0
- package/dist/store/reducers/tenantOverview/topShards/utils.ts +3 -0
- package/dist/styles/mixins.scss +4 -0
- package/dist/types/additionalProps.ts +3 -1
- package/dist/types/api/compute.ts +1 -1
- package/dist/types/react-json-inspector.d.ts +21 -0
- package/dist/utils/diagnostics.ts +11 -0
- package/dist/utils/generateEvaluator.ts +21 -0
- package/package.json +1 -1
@@ -0,0 +1,53 @@
|
|
1
|
+
import {useDispatch} from 'react-redux';
|
2
|
+
import {useCallback} from 'react';
|
3
|
+
|
4
|
+
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
|
5
|
+
import {
|
6
|
+
getTopNodesByLoad,
|
7
|
+
selectTopNodesByLoad,
|
8
|
+
setDataWasNotLoaded,
|
9
|
+
} from '../../../../../store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad';
|
10
|
+
import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
|
11
|
+
import {getTopNodesByLoadColumns} from '../../../../Nodes/getNodesColumns';
|
12
|
+
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
13
|
+
|
14
|
+
import i18n from '../i18n';
|
15
|
+
|
16
|
+
interface TopNodesByLoadProps {
|
17
|
+
path: string;
|
18
|
+
additionalNodesProps?: AdditionalNodesProps;
|
19
|
+
}
|
20
|
+
|
21
|
+
export function TopNodesByLoad({path, additionalNodesProps}: TopNodesByLoadProps) {
|
22
|
+
const dispatch = useDispatch();
|
23
|
+
|
24
|
+
const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByLoad);
|
25
|
+
const {autorefresh} = useTypedSelector((state) => state.schema);
|
26
|
+
const topNodes = useTypedSelector(selectTopNodesByLoad);
|
27
|
+
const columns = getTopNodesByLoadColumns(additionalNodesProps?.getNodeRef);
|
28
|
+
|
29
|
+
const fetchNodes = useCallback(
|
30
|
+
(isBackground) => {
|
31
|
+
if (!isBackground) {
|
32
|
+
dispatch(setDataWasNotLoaded());
|
33
|
+
}
|
34
|
+
|
35
|
+
dispatch(getTopNodesByLoad({tenant: path}));
|
36
|
+
},
|
37
|
+
[dispatch, path],
|
38
|
+
);
|
39
|
+
|
40
|
+
useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
|
41
|
+
|
42
|
+
return (
|
43
|
+
<TenantOverviewTableLayout
|
44
|
+
data={topNodes || []}
|
45
|
+
columns={columns}
|
46
|
+
title="Top nodes by load"
|
47
|
+
loading={loading}
|
48
|
+
wasLoaded={wasLoaded}
|
49
|
+
error={error}
|
50
|
+
emptyDataMessage={i18n('top-nodes.empty-data')}
|
51
|
+
/>
|
52
|
+
);
|
53
|
+
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
import qs from 'qs';
|
2
|
+
import {useDispatch} from 'react-redux';
|
3
|
+
import {useHistory, useLocation} from 'react-router';
|
4
|
+
import {useCallback} from 'react';
|
5
|
+
|
6
|
+
import {
|
7
|
+
TENANT_PAGE,
|
8
|
+
TENANT_PAGES_IDS,
|
9
|
+
TENANT_QUERY_TABS_ID,
|
10
|
+
} from '../../../../../store/reducers/tenant/constants';
|
11
|
+
import {
|
12
|
+
fetchTenantOverviewTopQueries,
|
13
|
+
setDataWasNotLoaded,
|
14
|
+
} from '../../../../../store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries';
|
15
|
+
import {changeUserInput} from '../../../../../store/reducers/executeQuery';
|
16
|
+
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
|
17
|
+
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
|
18
|
+
import {getTenantOverviewTopQueriesColumns} from '../../TopQueries/getTopQueriesColumns';
|
19
|
+
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
20
|
+
|
21
|
+
interface TopQueriesProps {
|
22
|
+
path: string;
|
23
|
+
}
|
24
|
+
|
25
|
+
export function TopQueries({path}: TopQueriesProps) {
|
26
|
+
const dispatch = useDispatch();
|
27
|
+
const location = useLocation();
|
28
|
+
const history = useHistory();
|
29
|
+
|
30
|
+
const {autorefresh} = useTypedSelector((state) => state.schema);
|
31
|
+
|
32
|
+
const {
|
33
|
+
loading,
|
34
|
+
wasLoaded,
|
35
|
+
error,
|
36
|
+
data: {result: data = undefined} = {},
|
37
|
+
} = useTypedSelector((state) => state.tenantOverviewTopQueries);
|
38
|
+
const columns = getTenantOverviewTopQueriesColumns();
|
39
|
+
|
40
|
+
useAutofetcher(
|
41
|
+
(isBackground) => {
|
42
|
+
if (!isBackground) {
|
43
|
+
dispatch(setDataWasNotLoaded());
|
44
|
+
}
|
45
|
+
|
46
|
+
dispatch(fetchTenantOverviewTopQueries(path));
|
47
|
+
},
|
48
|
+
[dispatch, path],
|
49
|
+
autorefresh,
|
50
|
+
);
|
51
|
+
|
52
|
+
const handleRowClick = useCallback(
|
53
|
+
(row) => {
|
54
|
+
const {QueryText: input} = row;
|
55
|
+
|
56
|
+
dispatch(changeUserInput({input}));
|
57
|
+
|
58
|
+
const queryParams = qs.parse(location.search, {
|
59
|
+
ignoreQueryPrefix: true,
|
60
|
+
});
|
61
|
+
|
62
|
+
const queryPath = getTenantPath({
|
63
|
+
...queryParams,
|
64
|
+
[TENANT_PAGE]: TENANT_PAGES_IDS.query,
|
65
|
+
[TenantTabsGroups.queryTab]: TENANT_QUERY_TABS_ID.newQuery,
|
66
|
+
});
|
67
|
+
|
68
|
+
history.push(queryPath);
|
69
|
+
},
|
70
|
+
[dispatch, history, location],
|
71
|
+
);
|
72
|
+
|
73
|
+
return (
|
74
|
+
<TenantOverviewTableLayout
|
75
|
+
data={data || []}
|
76
|
+
columns={columns}
|
77
|
+
onRowClick={handleRowClick}
|
78
|
+
title="Top queries by cpu time"
|
79
|
+
loading={loading}
|
80
|
+
wasLoaded={wasLoaded}
|
81
|
+
error={error}
|
82
|
+
tableClassNameModifiers={{'top-queries': true}}
|
83
|
+
/>
|
84
|
+
);
|
85
|
+
}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import {useDispatch} from 'react-redux';
|
2
|
+
import {useLocation} from 'react-router';
|
3
|
+
|
4
|
+
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
|
5
|
+
import {
|
6
|
+
sendTenantOverviewTopShardsQuery,
|
7
|
+
setDataWasNotLoaded,
|
8
|
+
} from '../../../../../store/reducers/tenantOverview/topShards/tenantOverviewTopShards';
|
9
|
+
import {getTopShardsColumns} from '../../TopShards/getTopShardsColumns';
|
10
|
+
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
11
|
+
|
12
|
+
interface TopShardsProps {
|
13
|
+
path: string;
|
14
|
+
}
|
15
|
+
|
16
|
+
export const TopShards = ({path}: TopShardsProps) => {
|
17
|
+
const dispatch = useDispatch();
|
18
|
+
const location = useLocation();
|
19
|
+
|
20
|
+
const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
|
21
|
+
|
22
|
+
const {
|
23
|
+
loading,
|
24
|
+
data: {result: data = undefined} = {},
|
25
|
+
error,
|
26
|
+
wasLoaded,
|
27
|
+
} = useTypedSelector((state) => state.tenantOverviewTopShards);
|
28
|
+
|
29
|
+
useAutofetcher(
|
30
|
+
(isBackground) => {
|
31
|
+
if (!isBackground) {
|
32
|
+
dispatch(setDataWasNotLoaded());
|
33
|
+
}
|
34
|
+
dispatch(sendTenantOverviewTopShardsQuery(path, currentSchemaPath));
|
35
|
+
},
|
36
|
+
[dispatch, path, currentSchemaPath],
|
37
|
+
autorefresh,
|
38
|
+
);
|
39
|
+
|
40
|
+
const columns = getTopShardsColumns(path, location);
|
41
|
+
|
42
|
+
return (
|
43
|
+
<TenantOverviewTableLayout
|
44
|
+
data={data || []}
|
45
|
+
columns={columns}
|
46
|
+
title="Top shards by cpu usage"
|
47
|
+
loading={loading}
|
48
|
+
wasLoaded={wasLoaded}
|
49
|
+
error={error}
|
50
|
+
tableClassNameModifiers={{'top-queries': true}}
|
51
|
+
/>
|
52
|
+
);
|
53
|
+
};
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import {useDispatch} from 'react-redux';
|
2
|
+
import {useCallback} from 'react';
|
3
|
+
|
4
|
+
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
|
5
|
+
import {
|
6
|
+
getTopNodesByMemory,
|
7
|
+
selectTopNodesByMemory,
|
8
|
+
setDataWasNotLoaded,
|
9
|
+
} from '../../../../../store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory';
|
10
|
+
import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
|
11
|
+
import {getTopNodesByMemoryColumns} from '../../../../Nodes/getNodesColumns';
|
12
|
+
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
|
13
|
+
|
14
|
+
import i18n from '../i18n';
|
15
|
+
|
16
|
+
interface TopNodesByMemoryProps {
|
17
|
+
path: string;
|
18
|
+
additionalNodesProps?: AdditionalNodesProps;
|
19
|
+
}
|
20
|
+
|
21
|
+
export function TopNodesByMemory({path, additionalNodesProps}: TopNodesByMemoryProps) {
|
22
|
+
const dispatch = useDispatch();
|
23
|
+
|
24
|
+
const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByMemory);
|
25
|
+
const {autorefresh} = useTypedSelector((state) => state.schema);
|
26
|
+
const topNodes = useTypedSelector(selectTopNodesByMemory);
|
27
|
+
const columns = getTopNodesByMemoryColumns({
|
28
|
+
getNodeRef: additionalNodesProps?.getNodeRef,
|
29
|
+
});
|
30
|
+
|
31
|
+
const fetchNodes = useCallback(
|
32
|
+
(isBackground) => {
|
33
|
+
if (!isBackground) {
|
34
|
+
dispatch(setDataWasNotLoaded());
|
35
|
+
}
|
36
|
+
|
37
|
+
dispatch(getTopNodesByMemory({tenant: path}));
|
38
|
+
},
|
39
|
+
[dispatch, path],
|
40
|
+
);
|
41
|
+
|
42
|
+
useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
|
43
|
+
|
44
|
+
return (
|
45
|
+
<TenantOverviewTableLayout
|
46
|
+
data={topNodes || []}
|
47
|
+
columns={columns}
|
48
|
+
title="Top nodes by memory"
|
49
|
+
loading={loading}
|
50
|
+
wasLoaded={wasLoaded}
|
51
|
+
error={error}
|
52
|
+
emptyDataMessage={i18n('top-nodes.empty-data')}
|
53
|
+
/>
|
54
|
+
);
|
55
|
+
}
|
@@ -1,4 +1,9 @@
|
|
1
|
+
@import '../../../../styles/mixins.scss';
|
2
|
+
|
1
3
|
.tenant-overview {
|
4
|
+
overflow: auto;
|
5
|
+
|
6
|
+
height: 100%;
|
2
7
|
padding-bottom: 20px;
|
3
8
|
|
4
9
|
&__loader {
|
@@ -78,4 +83,39 @@
|
|
78
83
|
font-weight: 600;
|
79
84
|
line-height: var(--yc-text-body-2-line-height);
|
80
85
|
}
|
86
|
+
|
87
|
+
&__info {
|
88
|
+
position: sticky;
|
89
|
+
left: 0;
|
90
|
+
|
91
|
+
width: max-content;
|
92
|
+
}
|
93
|
+
|
94
|
+
&__title {
|
95
|
+
margin-bottom: 10px;
|
96
|
+
|
97
|
+
font-size: var(--yc-text-body-2-font-size);
|
98
|
+
font-weight: 700;
|
99
|
+
line-height: var(--yc-text-body-2-line-height);
|
100
|
+
}
|
101
|
+
|
102
|
+
&__table {
|
103
|
+
width: var(--diagnostics-section-table-width);
|
104
|
+
|
105
|
+
@include table-styles();
|
106
|
+
|
107
|
+
&:not(:last-child) {
|
108
|
+
margin-bottom: var(--diagnostics-section-margin);
|
109
|
+
}
|
110
|
+
|
111
|
+
th {
|
112
|
+
height: 40px;
|
113
|
+
|
114
|
+
vertical-align: middle;
|
115
|
+
}
|
116
|
+
|
117
|
+
&_top-queries tr {
|
118
|
+
cursor: pointer;
|
119
|
+
}
|
120
|
+
}
|
81
121
|
}
|
@@ -9,15 +9,16 @@ import {TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
|
|
9
9
|
import {TENANT_METRICS_TABS_IDS} from '../../../../store/reducers/tenant/constants';
|
10
10
|
import {mapDatabaseTypeToDBName} from '../../utils/schema';
|
11
11
|
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
12
|
-
import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
|
12
|
+
import type {AdditionalNodesProps, AdditionalTenantsProps} from '../../../../types/additionalProps';
|
13
13
|
import {getTenantInfo, setDataWasNotLoaded} from '../../../../store/reducers/tenant/tenant';
|
14
14
|
import {calculateTenantMetrics} from '../../../../store/reducers/tenants/utils';
|
15
|
+
import {TenantCpu} from './TenantCpu/TenantCpu';
|
15
16
|
import {HealthcheckDetails} from './Healthcheck/HealthcheckDetails';
|
16
17
|
import {MetricsCards, type TenantMetrics} from './MetricsCards/MetricsCards';
|
17
18
|
import {TenantStorage} from './TenantStorage/TenantStorage';
|
19
|
+
import {TenantMemory} from './TenantMemory/TenantMemory';
|
18
20
|
import {useHealthcheck} from './useHealthcheck';
|
19
21
|
|
20
|
-
import i18n from './i18n';
|
21
22
|
import './TenantOverview.scss';
|
22
23
|
|
23
24
|
const b = cn('tenant-overview');
|
@@ -25,9 +26,14 @@ const b = cn('tenant-overview');
|
|
25
26
|
interface TenantOverviewProps {
|
26
27
|
tenantName: string;
|
27
28
|
additionalTenantProps?: AdditionalTenantsProps;
|
29
|
+
additionalNodesProps?: AdditionalNodesProps;
|
28
30
|
}
|
29
31
|
|
30
|
-
export function TenantOverview({
|
32
|
+
export function TenantOverview({
|
33
|
+
tenantName,
|
34
|
+
additionalTenantProps,
|
35
|
+
additionalNodesProps,
|
36
|
+
}: TenantOverviewProps) {
|
31
37
|
const dispatch = useDispatch();
|
32
38
|
|
33
39
|
const {
|
@@ -115,16 +121,23 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
|
|
115
121
|
const renderTabContent = () => {
|
116
122
|
switch (metricsTab) {
|
117
123
|
case TENANT_METRICS_TABS_IDS.cpu: {
|
118
|
-
return
|
124
|
+
return <TenantCpu path={tenantName} additionalNodesProps={additionalNodesProps} />;
|
119
125
|
}
|
120
126
|
case TENANT_METRICS_TABS_IDS.storage: {
|
121
127
|
return <TenantStorage tenantName={tenantName} metrics={storageMetrics} />;
|
122
128
|
}
|
123
129
|
case TENANT_METRICS_TABS_IDS.memory: {
|
124
|
-
return
|
130
|
+
return <TenantMemory path={tenantName} />;
|
125
131
|
}
|
126
132
|
case TENANT_METRICS_TABS_IDS.healthcheck: {
|
127
|
-
return
|
133
|
+
return (
|
134
|
+
<HealthcheckDetails
|
135
|
+
issueTrees={issueTrees}
|
136
|
+
loading={healthcheckLoading}
|
137
|
+
wasLoaded={healthCheckWasLoaded}
|
138
|
+
error={healthcheckError}
|
139
|
+
/>
|
140
|
+
);
|
128
141
|
}
|
129
142
|
default: {
|
130
143
|
return undefined;
|
@@ -132,7 +145,7 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
|
|
132
145
|
}
|
133
146
|
};
|
134
147
|
|
135
|
-
if (
|
148
|
+
if (tenantLoading && !tenantWasLoaded) {
|
136
149
|
return (
|
137
150
|
<div className={b('loader')}>
|
138
151
|
<Loader size="m" />
|
@@ -142,19 +155,22 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
|
|
142
155
|
|
143
156
|
return (
|
144
157
|
<div className={b()}>
|
145
|
-
<div className={b('
|
146
|
-
|
147
|
-
{
|
148
|
-
|
158
|
+
<div className={b('info')}>
|
159
|
+
<div className={b('top-label')}>{tenantType}</div>
|
160
|
+
<div className={b('top')}>
|
161
|
+
{renderName()}
|
162
|
+
{additionalTenantProps?.getMonitoringLink?.(Name, Type)}
|
163
|
+
</div>
|
164
|
+
<MetricsCards
|
165
|
+
metrics={calculatedMetrics}
|
166
|
+
issuesStatistics={issuesStatistics}
|
167
|
+
selfCheckResult={selfCheckResult}
|
168
|
+
fetchHealthcheck={fetchHealthcheck}
|
169
|
+
healthcheckLoading={healthcheckLoading}
|
170
|
+
healthCheckWasLoaded={healthCheckWasLoaded}
|
171
|
+
healthcheckError={healthcheckError}
|
172
|
+
/>
|
149
173
|
</div>
|
150
|
-
<MetricsCards
|
151
|
-
metrics={calculatedMetrics}
|
152
|
-
issuesStatistics={issuesStatistics}
|
153
|
-
selfCheckResult={selfCheckResult}
|
154
|
-
fetchHealthcheck={fetchHealthcheck}
|
155
|
-
healthcheckLoading={healthcheckLoading}
|
156
|
-
healthcheckError={healthcheckError}
|
157
|
-
/>
|
158
174
|
{renderTabContent()}
|
159
175
|
</div>
|
160
176
|
);
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import cn from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import DataTable from '@gravity-ui/react-data-table';
|
4
|
+
import type {DataTableProps} from '@gravity-ui/react-data-table';
|
5
|
+
|
6
|
+
import {
|
7
|
+
TENANT_OVERVIEW_TABLES_LIMIT,
|
8
|
+
TENANT_OVERVIEW_TABLES_SETTINGS,
|
9
|
+
} from '../../../../utils/constants';
|
10
|
+
import type {IResponseError} from '../../../../types/api/error';
|
11
|
+
import {TableSkeleton} from '../../../../components/TableSkeleton/TableSkeleton';
|
12
|
+
import {ResponseError} from '../../../../components/Errors/ResponseError';
|
13
|
+
|
14
|
+
const b = cn('tenant-overview');
|
15
|
+
|
16
|
+
interface TenantOverviewTableLayoutProps<T> extends Omit<DataTableProps<T>, 'theme'> {
|
17
|
+
title: string;
|
18
|
+
loading?: boolean;
|
19
|
+
wasLoaded?: boolean;
|
20
|
+
error?: IResponseError;
|
21
|
+
tableClassNameModifiers?: {
|
22
|
+
[name: string]: string | boolean | undefined;
|
23
|
+
};
|
24
|
+
}
|
25
|
+
|
26
|
+
export function TenantOverviewTableLayout<T>({
|
27
|
+
title,
|
28
|
+
error,
|
29
|
+
loading,
|
30
|
+
wasLoaded,
|
31
|
+
tableClassNameModifiers = {},
|
32
|
+
...props
|
33
|
+
}: TenantOverviewTableLayoutProps<T>) {
|
34
|
+
const renderContent = () => {
|
35
|
+
if (error) {
|
36
|
+
return <ResponseError error={error} />;
|
37
|
+
}
|
38
|
+
|
39
|
+
if (loading && !wasLoaded) {
|
40
|
+
return <TableSkeleton rows={TENANT_OVERVIEW_TABLES_LIMIT} />;
|
41
|
+
}
|
42
|
+
|
43
|
+
return (
|
44
|
+
<DataTable theme="yandex-cloud" settings={TENANT_OVERVIEW_TABLES_SETTINGS} {...props} />
|
45
|
+
);
|
46
|
+
};
|
47
|
+
return (
|
48
|
+
<>
|
49
|
+
<div className={b('title')}>{title}</div>
|
50
|
+
<div className={b('table', tableClassNameModifiers)}>{renderContent()}</div>
|
51
|
+
</>
|
52
|
+
);
|
53
|
+
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import {useDispatch} from 'react-redux';
|
2
|
+
import {useLocation} from 'react-router';
|
2
3
|
import cn from 'bem-cn-lite';
|
3
4
|
|
4
5
|
import DataTable, {Column} from '@gravity-ui/react-data-table';
|
@@ -17,6 +18,7 @@ import type {KeyValueRow} from '../../../../../types/api/query';
|
|
17
18
|
import {formatBytes, getSizeWithSignificantDigits} from '../../../../../utils/bytesParsers';
|
18
19
|
import {TableSkeleton} from '../../../../../components/TableSkeleton/TableSkeleton';
|
19
20
|
import {ResponseError} from '../../../../../components/Errors/ResponseError';
|
21
|
+
import {LinkToSchemaObject} from '../../../../../components/LinkToSchemaObject/LinkToSchemaObject';
|
20
22
|
|
21
23
|
import './TenantStorage.scss';
|
22
24
|
|
@@ -28,6 +30,7 @@ interface TopTablesProps {
|
|
28
30
|
|
29
31
|
export function TopTables({path}: TopTablesProps) {
|
30
32
|
const dispatch = useDispatch();
|
33
|
+
const location = useLocation();
|
31
34
|
|
32
35
|
const {autorefresh} = useTypedSelector((state) => state.schema);
|
33
36
|
|
@@ -67,13 +70,18 @@ export function TopTables({path}: TopTablesProps) {
|
|
67
70
|
{
|
68
71
|
name: 'Path',
|
69
72
|
sortable: false,
|
70
|
-
render: ({row}) =>
|
71
|
-
|
72
|
-
<
|
73
|
-
{
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
render: ({row}) =>
|
74
|
+
row.Path ? (
|
75
|
+
<LinkToSchemaObject
|
76
|
+
className={b('cell-with-popover-wrapper')}
|
77
|
+
path={String(row.Path)}
|
78
|
+
location={location}
|
79
|
+
>
|
80
|
+
<Popover className={b('cell-with-popover')} content={row.Path}>
|
81
|
+
{row.Path}
|
82
|
+
</Popover>
|
83
|
+
</LinkToSchemaObject>
|
84
|
+
) : null,
|
77
85
|
},
|
78
86
|
];
|
79
87
|
|
@@ -2,10 +2,10 @@
|
|
2
2
|
"no-data": "No data",
|
3
3
|
"no-pools-data": "No pools data",
|
4
4
|
|
5
|
+
"top-nodes.empty-data": "No such nodes",
|
6
|
+
|
5
7
|
"title.pools": "Pools",
|
6
8
|
"title.metrics": "Metrics",
|
7
9
|
|
8
|
-
"top-groups.empty-data": "No such groups"
|
9
|
-
|
10
|
-
"label.under-development": "This section is under development"
|
10
|
+
"top-groups.empty-data": "No such groups"
|
11
11
|
}
|
@@ -2,10 +2,10 @@
|
|
2
2
|
"no-data": "Нет данных",
|
3
3
|
"no-pools-data": "Нет данных о пулах",
|
4
4
|
|
5
|
+
"top-nodes.empty-data": "Нет узлов",
|
6
|
+
|
5
7
|
"title.pools": "Пулы",
|
6
8
|
"title.metrics": "Метрики",
|
7
9
|
|
8
|
-
"top-groups.empty-data": "Нет групп"
|
9
|
-
|
10
|
-
"label.under-development": "Этот раздел находится в разработке"
|
10
|
+
"top-groups.empty-data": "Нет групп"
|
11
11
|
}
|