ydb-embedded-ui 4.19.3 → 4.20.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/CellWithPopover/CellWithPopover.scss +13 -0
  3. package/dist/components/CellWithPopover/CellWithPopover.tsx +26 -0
  4. package/dist/components/LinkToSchemaObject/LinkToSchemaObject.tsx +20 -0
  5. package/dist/components/NodeHostWrapper/NodeHostWrapper.scss +0 -2
  6. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +28 -29
  7. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +3 -2
  8. package/dist/components/TruncatedQuery/TruncatedQuery.scss +8 -0
  9. package/dist/components/TruncatedQuery/TruncatedQuery.tsx +15 -1
  10. package/dist/components/UsageLabel/UsageLabel.scss +6 -0
  11. package/dist/components/UsageLabel/UsageLabel.tsx +22 -0
  12. package/dist/containers/AsideNavigation/AsideNavigation.tsx +13 -8
  13. package/dist/containers/AsideNavigation/i18n/en.json +13 -0
  14. package/dist/containers/AsideNavigation/i18n/index.ts +11 -0
  15. package/dist/containers/AsideNavigation/i18n/ru.json +13 -0
  16. package/dist/containers/Node/NodeStructure/Pdisk.tsx +74 -68
  17. package/dist/containers/Node/NodeStructure/Vdisk.tsx +9 -33
  18. package/dist/containers/Nodes/Nodes.tsx +10 -2
  19. package/dist/containers/Nodes/getNodesColumns.tsx +207 -123
  20. package/dist/containers/Storage/Storage.tsx +9 -2
  21. package/dist/containers/Storage/StorageGroups/StorageGroups.scss +0 -11
  22. package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx +11 -11
  23. package/dist/containers/Storage/utils/index.ts +1 -22
  24. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -3
  25. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +0 -1
  26. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +4 -2
  27. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +1 -0
  28. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +8 -1
  29. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +11 -1
  30. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/IssuesViewer/IssueTree.tsx +0 -1
  31. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +3 -0
  32. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx +21 -0
  33. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +53 -0
  34. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +53 -0
  35. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +83 -0
  36. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +53 -0
  37. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx +9 -0
  38. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +55 -0
  39. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +44 -0
  40. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +35 -19
  41. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +53 -0
  42. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx +4 -2
  43. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +9 -36
  44. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +22 -41
  45. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -3
  46. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -3
  47. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +0 -2
  48. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +19 -61
  49. package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +102 -0
  50. package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.tsx +2 -2
  51. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +18 -97
  52. package/dist/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx +138 -0
  53. package/dist/containers/Tenant/Info/ExternalTable/ExternalTable.tsx +2 -4
  54. package/dist/containers/Tenant/Query/ExecuteResult/{ExecuteResult.js → ExecuteResult.tsx} +51 -31
  55. package/dist/containers/Tenant/Query/Issues/Issues.tsx +4 -6
  56. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.tsx +1 -1
  57. package/dist/containers/Tenant/utils/paneVisibilityToggleHelpers.tsx +1 -1
  58. package/dist/routes.ts +26 -1
  59. package/dist/store/reducers/{executeTopQueries.ts → executeTopQueries/executeTopQueries.ts} +23 -75
  60. package/dist/{types/store/executeTopQueries.ts → store/reducers/executeTopQueries/types.ts} +3 -7
  61. package/dist/store/reducers/executeTopQueries/utils.ts +36 -0
  62. package/dist/store/reducers/index.ts +12 -2
  63. package/dist/store/reducers/nodes/types.ts +1 -0
  64. package/dist/store/reducers/nodes/utils.ts +16 -6
  65. package/dist/store/reducers/{shardsWorkload.ts → shardsWorkload/shardsWorkload.ts} +5 -11
  66. package/dist/{types/store/shardsWorkload.ts → store/reducers/shardsWorkload/types.ts} +3 -7
  67. package/dist/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts +87 -0
  68. package/dist/store/reducers/tenantOverview/topNodesByCpu/types.ts +29 -0
  69. package/dist/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts +87 -0
  70. package/dist/store/reducers/tenantOverview/topNodesByLoad/types.ts +29 -0
  71. package/dist/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts +87 -0
  72. package/dist/store/reducers/tenantOverview/topNodesByMemory/types.ts +29 -0
  73. package/dist/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts +93 -0
  74. package/dist/store/reducers/tenantOverview/topQueries/types.ts +14 -0
  75. package/dist/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts +103 -0
  76. package/dist/store/reducers/tenantOverview/topShards/types.ts +14 -0
  77. package/dist/store/reducers/tenantOverview/topShards/utils.ts +3 -0
  78. package/dist/styles/mixins.scss +4 -0
  79. package/dist/types/additionalProps.ts +3 -1
  80. package/dist/types/api/compute.ts +1 -1
  81. package/dist/types/react-json-inspector.d.ts +21 -0
  82. package/dist/utils/diagnostics.ts +23 -0
  83. package/dist/utils/generateEvaluator.ts +21 -0
  84. package/dist/utils/generateHash.ts +11 -0
  85. package/package.json +3 -2
  86. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.scss +0 -41
@@ -0,0 +1,21 @@
1
+ import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
2
+ import {TopNodesByLoad} from './TopNodesByLoad';
3
+ import {TopNodesByCpu} from './TopNodesByCpu';
4
+ import {TopShards} from './TopShards';
5
+ import {TopQueries} from './TopQueries';
6
+
7
+ interface TenantCpuProps {
8
+ path: string;
9
+ additionalNodesProps?: AdditionalNodesProps;
10
+ }
11
+
12
+ export function TenantCpu({path, additionalNodesProps}: TenantCpuProps) {
13
+ return (
14
+ <>
15
+ <TopNodesByLoad path={path} additionalNodesProps={additionalNodesProps} />
16
+ <TopNodesByCpu path={path} additionalNodesProps={additionalNodesProps} />
17
+ <TopShards path={path} />
18
+ <TopQueries path={path} />
19
+ </>
20
+ );
21
+ }
@@ -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
+ getTopNodesByCpu,
7
+ selectTopNodesByCpu,
8
+ setDataWasNotLoaded,
9
+ } from '../../../../../store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu';
10
+ import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
11
+ import {getTopNodesByCpuColumns} from '../../../../Nodes/getNodesColumns';
12
+ import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
13
+
14
+ import i18n from '../i18n';
15
+
16
+ interface TopNodesByCpuProps {
17
+ path: string;
18
+ additionalNodesProps?: AdditionalNodesProps;
19
+ }
20
+
21
+ export function TopNodesByCpu({path, additionalNodesProps}: TopNodesByCpuProps) {
22
+ const dispatch = useDispatch();
23
+
24
+ const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByCpu);
25
+ const {autorefresh} = useTypedSelector((state) => state.schema);
26
+ const topNodes = useTypedSelector(selectTopNodesByCpu);
27
+ const columns = getTopNodesByCpuColumns(additionalNodesProps?.getNodeRef);
28
+
29
+ const fetchNodes = useCallback(
30
+ (isBackground) => {
31
+ if (!isBackground) {
32
+ dispatch(setDataWasNotLoaded());
33
+ }
34
+
35
+ dispatch(getTopNodesByCpu({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 pools usage"
47
+ loading={loading}
48
+ wasLoaded={wasLoaded}
49
+ error={error}
50
+ emptyDataMessage={i18n('top-nodes.empty-data')}
51
+ />
52
+ );
53
+ }
@@ -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,83 @@
1
+ import {useDispatch} from 'react-redux';
2
+ import {useHistory, useLocation} from 'react-router';
3
+ import {useCallback} from 'react';
4
+
5
+ import {
6
+ TENANT_PAGE,
7
+ TENANT_PAGES_IDS,
8
+ TENANT_QUERY_TABS_ID,
9
+ } from '../../../../../store/reducers/tenant/constants';
10
+ import {
11
+ fetchTenantOverviewTopQueries,
12
+ setDataWasNotLoaded,
13
+ } from '../../../../../store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries';
14
+ import {changeUserInput} from '../../../../../store/reducers/executeQuery';
15
+ import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
16
+ import {parseQuery} from '../../../../../routes';
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 = parseQuery(location);
59
+
60
+ const queryPath = getTenantPath({
61
+ ...queryParams,
62
+ [TENANT_PAGE]: TENANT_PAGES_IDS.query,
63
+ [TenantTabsGroups.queryTab]: TENANT_QUERY_TABS_ID.newQuery,
64
+ });
65
+
66
+ history.push(queryPath);
67
+ },
68
+ [dispatch, history, location],
69
+ );
70
+
71
+ return (
72
+ <TenantOverviewTableLayout
73
+ data={data || []}
74
+ columns={columns}
75
+ onRowClick={handleRowClick}
76
+ title="Top queries by cpu time"
77
+ loading={loading}
78
+ wasLoaded={wasLoaded}
79
+ error={error}
80
+ tableClassNameModifiers={{'top-queries': true}}
81
+ />
82
+ );
83
+ }
@@ -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,9 @@
1
+ import {TopNodesByMemory} from './TopNodesByMemory';
2
+
3
+ interface TenantMemoryProps {
4
+ path: string;
5
+ }
6
+
7
+ export function TenantMemory({path}: TenantMemoryProps) {
8
+ return <TopNodesByMemory path={path} />;
9
+ }
@@ -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,43 @@
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
+ }
121
+
122
+ &__info {
123
+ margin-bottom: 36px;
124
+ }
81
125
  }
@@ -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({tenantName, additionalTenantProps}: TenantOverviewProps) {
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 i18n('label.under-development');
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 i18n('label.under-development');
130
+ return <TenantMemory path={tenantName} />;
125
131
  }
126
132
  case TENANT_METRICS_TABS_IDS.healthcheck: {
127
- return <HealthcheckDetails issueTrees={issueTrees} error={healthcheckError} />;
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 ((tenantLoading && !tenantWasLoaded) || (healthcheckLoading && !healthCheckWasLoaded)) {
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('top-label')}>{tenantType}</div>
146
- <div className={b('top')}>
147
- {renderName()}
148
- {additionalTenantProps?.getMonitoringLink?.(Name, Type)}
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
+ }
@@ -4,11 +4,13 @@ import InfoViewer from '../../../../../components/InfoViewer/InfoViewer';
4
4
  import {ProgressViewer} from '../../../../../components/ProgressViewer/ProgressViewer';
5
5
  import {formatStorageValues} from '../../../../../utils/dataFormatters/dataFormatters';
6
6
  import {getSizeWithSignificantDigits} from '../../../../../utils/bytesParsers';
7
+
8
+ import '../TenantOverview.scss';
9
+
7
10
  import {TopTables} from './TopTables';
8
11
  import {TopGroups} from './TopGroups';
9
- import './TenantStorage.scss';
10
12
 
11
- const b = cn('tenant-overview-storage');
13
+ const b = cn('tenant-overview');
12
14
 
13
15
  export interface TenantStorageMetrics {
14
16
  blobStorageUsed?: number;
@@ -1,25 +1,14 @@
1
- import cn from 'bem-cn-lite';
2
1
  import {useCallback} from 'react';
3
2
  import {useDispatch} from 'react-redux';
4
3
 
5
- import DataTable from '@gravity-ui/react-data-table';
6
-
7
4
  import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
8
- import {
9
- TENANT_OVERVIEW_TABLES_LIMIT,
10
- TENANT_OVERVIEW_TABLES_SETTINGS,
11
- } from '../../../../../utils/constants';
12
5
  import {
13
6
  setDataWasNotLoaded,
14
7
  getTopStorageGroups,
15
8
  selectTopStorageGroups,
16
9
  } from '../../../../../store/reducers/tenantOverview/topStorageGroups/topStorageGroups';
17
- import {ResponseError} from '../../../../../components/Errors/ResponseError';
18
- import {TableSkeleton} from '../../../../../components/TableSkeleton/TableSkeleton';
19
10
  import {getStorageTopGroupsColumns} from '../../../../Storage/StorageGroups/getStorageGroupsColumns';
20
- import i18n from '../i18n';
21
-
22
- const b = cn('tenant-overview-storage');
11
+ import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
23
12
 
24
13
  interface TopGroupsProps {
25
14
  tenant?: string;
@@ -47,30 +36,14 @@ export function TopGroups({tenant}: TopGroupsProps) {
47
36
 
48
37
  useAutofetcher(fetchData, [fetchData], autorefresh);
49
38
 
50
- const renderContent = () => {
51
- if (error) {
52
- return <ResponseError error={error} />;
53
- }
54
-
55
- if (loading && !wasLoaded) {
56
- return <TableSkeleton rows={TENANT_OVERVIEW_TABLES_LIMIT} />;
57
- }
58
-
59
- return (
60
- <DataTable
61
- theme="yandex-cloud"
62
- data={topGroups || []}
63
- columns={columns}
64
- settings={TENANT_OVERVIEW_TABLES_SETTINGS}
65
- emptyDataMessage={i18n('top-groups.empty-data')}
66
- />
67
- );
68
- };
69
-
70
39
  return (
71
- <>
72
- <div className={b('title')}>Top groups by usage</div>
73
- <div className={b('table')}>{renderContent()}</div>
74
- </>
40
+ <TenantOverviewTableLayout
41
+ data={topGroups || []}
42
+ columns={columns}
43
+ title="Top groups by usage"
44
+ loading={loading}
45
+ wasLoaded={wasLoaded}
46
+ error={error}
47
+ />
75
48
  );
76
49
  }