ydb-embedded-ui 4.16.2 → 4.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/components/CircularProgressBar/CircularProgressBar.scss +42 -0
  3. package/dist/components/CircularProgressBar/CircularProgressBar.tsx +59 -0
  4. package/dist/components/DiagnosticCard/DiagnosticCard.scss +20 -3
  5. package/dist/components/DiagnosticCard/DiagnosticCard.tsx +5 -6
  6. package/dist/components/FullNodeViewer/FullNodeViewer.tsx +2 -2
  7. package/dist/components/InfoViewer/formatters/common.ts +1 -1
  8. package/dist/components/InfoViewer/formatters/pqGroup.ts +1 -1
  9. package/dist/components/InfoViewer/formatters/table.ts +6 -1
  10. package/dist/components/ProgressViewer/ProgressViewer.tsx +99 -0
  11. package/dist/components/TooltipsContent/TabletTooltipContent/TabletTooltipContent.tsx +1 -1
  12. package/dist/containers/AsideNavigation/AsideNavigation.tsx +3 -1
  13. package/dist/containers/Authentication/Authentication.tsx +14 -4
  14. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +2 -2
  15. package/dist/containers/Heatmap/Heatmap.tsx +1 -1
  16. package/dist/containers/Heatmap/Histogram/Histogram.js +1 -1
  17. package/dist/containers/Node/NodeStructure/Pdisk.tsx +2 -2
  18. package/dist/containers/Node/NodeStructure/Vdisk.tsx +5 -2
  19. package/dist/containers/Nodes/getNodesColumns.tsx +2 -2
  20. package/dist/containers/Storage/PDisk/PDisk.tsx +1 -1
  21. package/dist/containers/Storage/PDiskPopup/PDiskPopup.tsx +1 -1
  22. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +1 -1
  23. package/dist/containers/Storage/VDisk/VDisk.tsx +1 -1
  24. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +1 -1
  25. package/dist/containers/Tablet/TabletInfo/TabletInfo.tsx +1 -1
  26. package/dist/containers/Tablet/TabletTable/TabletTable.tsx +1 -1
  27. package/dist/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.tsx +1 -1
  28. package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +1 -1
  29. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +1 -5
  30. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +40 -17
  31. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/Details.tsx +3 -3
  32. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.scss +27 -14
  33. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.tsx +6 -6
  34. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/Preview.tsx +15 -16
  35. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +1 -1
  36. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +1 -1
  37. package/dist/containers/Tenant/Diagnostics/Partitions/columns/columns.tsx +1 -1
  38. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/Healthcheck.scss +108 -0
  39. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +45 -0
  40. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +83 -0
  41. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.scss +1 -3
  42. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.tsx +1 -1
  43. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +1 -1
  44. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/en.json +2 -1
  45. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/index.ts +1 -1
  46. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/ru.json +2 -1
  47. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.scss +52 -0
  48. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.tsx +48 -0
  49. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.scss +12 -0
  50. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +134 -0
  51. package/dist/containers/Tenant/Diagnostics/TenantOverview/OldTenantOverview.tsx +155 -0
  52. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +3 -5
  53. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +76 -86
  54. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -1
  55. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -1
  56. package/dist/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts +53 -0
  57. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +1 -1
  58. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +1 -1
  59. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +1 -1
  60. package/dist/containers/Tenant/TenantPages.tsx +1 -0
  61. package/dist/containers/Tenants/Tenants.tsx +5 -1
  62. package/dist/containers/UserSettings/i18n/en.json +4 -1
  63. package/dist/containers/UserSettings/i18n/ru.json +4 -1
  64. package/dist/containers/UserSettings/settings.ts +7 -0
  65. package/dist/containers/Versions/NodesTable/NodesTable.tsx +2 -2
  66. package/dist/services/api.ts +6 -4
  67. package/dist/store/reducers/clusterNodes/clusterNodes.tsx +1 -1
  68. package/dist/store/reducers/healthcheckInfo.ts +20 -12
  69. package/dist/store/reducers/node/selectors.ts +1 -1
  70. package/dist/store/reducers/nodes/selectors.ts +1 -1
  71. package/dist/store/reducers/nodes/types.ts +1 -1
  72. package/dist/store/reducers/nodes/utils.ts +1 -1
  73. package/dist/store/reducers/settings/settings.ts +6 -1
  74. package/dist/store/reducers/storage/types.ts +1 -1
  75. package/dist/store/reducers/storage/utils.ts +1 -1
  76. package/dist/store/reducers/tenant/constants.ts +7 -0
  77. package/dist/store/reducers/tenant/tenant.ts +15 -0
  78. package/dist/store/reducers/tenant/types.ts +5 -0
  79. package/dist/store/reducers/tenants/contants.ts +6 -0
  80. package/dist/store/reducers/tenants/types.ts +4 -0
  81. package/dist/store/reducers/tenants/utils.ts +114 -7
  82. package/dist/store/state-url-mapping.js +3 -0
  83. package/dist/styles/constants.scss +2 -0
  84. package/dist/types/api/tenant.ts +3 -0
  85. package/dist/types/api/vdisk.ts +1 -1
  86. package/dist/utils/bytesParsers/formatBytes.ts +1 -1
  87. package/dist/utils/constants.ts +2 -0
  88. package/dist/utils/dataFormatters/dataFormatters.ts +128 -0
  89. package/dist/utils/dataFormatters/i18n/en.json +3 -0
  90. package/dist/utils/dataFormatters/i18n/index.ts +11 -0
  91. package/dist/utils/dataFormatters/i18n/ru.json +3 -0
  92. package/dist/utils/index.js +0 -102
  93. package/package.json +1 -1
  94. package/dist/components/ProgressViewer/ProgressViewer.js +0 -92
  95. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/index.ts +0 -0
  96. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/index.ts +0 -0
  97. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/index.ts +0 -0
  98. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +0 -0
  99. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/index.ts +0 -0
@@ -0,0 +1,52 @@
1
+ @import '../../../../../../styles/mixins.scss';
2
+
3
+ .ydb-metrics-card {
4
+ $b: &;
5
+ &__header {
6
+ display: flex;
7
+ justify-content: space-between;
8
+ align-items: center;
9
+
10
+ margin-bottom: 10px;
11
+ }
12
+
13
+ &__label {
14
+ font-weight: 600;
15
+ @include lead-typography();
16
+ }
17
+
18
+ &__content {
19
+ display: flex;
20
+ flex-direction: column;
21
+ align-items: center;
22
+
23
+ font-size: var(--yc-text-header-1-font-size);
24
+ line-height: var(--yc-text-header-1-line-height);
25
+ text-align: center;
26
+
27
+ color: var(--yc-color-text-secondary);
28
+ }
29
+
30
+ &__progress {
31
+ font-size: 36px;
32
+ font-weight: 500;
33
+ line-height: 40px;
34
+ text-align: center;
35
+ }
36
+
37
+ &__resources {
38
+ font-size: var(--yc-text-body-1-font-size);
39
+
40
+ color: var(--yc-color-text-secondary);
41
+ }
42
+
43
+ &_active {
44
+ #{$b}__content {
45
+ color: var(--yc-color-text-complementary);
46
+ }
47
+
48
+ #{$b}__progress-bar-circle-bg {
49
+ stroke: var(--yc-color-base-float);
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,48 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import {CircularProgressBar} from '../../../../../../components/CircularProgressBar/CircularProgressBar';
4
+ import {DiagnosticCard} from '../../../../../../components/DiagnosticCard/DiagnosticCard';
5
+ import {formatUsage} from '../../../../../../store/reducers/tenants/utils';
6
+ import type {MetricStatus} from '../../../../../../store/reducers/tenants/types';
7
+
8
+ import i18n from '../../i18n';
9
+
10
+ import './MetricCard.scss';
11
+
12
+ const b = cn('ydb-metrics-card');
13
+
14
+ interface MetricCardProps {
15
+ active?: boolean;
16
+ progress?: number;
17
+ label?: string;
18
+ status?: MetricStatus;
19
+ resourcesUsed?: string;
20
+ }
21
+
22
+ export function MetricCard({active, progress, label, status, resourcesUsed}: MetricCardProps) {
23
+ const renderContent = () => {
24
+ return (
25
+ <div className={b('content')}>
26
+ {progress && <div className={b('progress')}>{formatUsage(progress)}</div>}
27
+ {resourcesUsed ? (
28
+ <div className={b('resources')}>{resourcesUsed}</div>
29
+ ) : (
30
+ i18n('no-data')
31
+ )}
32
+ </div>
33
+ );
34
+ };
35
+ return (
36
+ <DiagnosticCard className={b({active})} active={active}>
37
+ <div className={b('header')}>{label && <div className={b('label')}>{label}</div>}</div>
38
+ <CircularProgressBar
39
+ size={172}
40
+ strokeWidth={11}
41
+ progress={progress || 0}
42
+ content={renderContent()}
43
+ status={status}
44
+ circleBgClassName={b('progress-bar-circle-bg')}
45
+ />
46
+ </DiagnosticCard>
47
+ );
48
+ }
@@ -0,0 +1,12 @@
1
+ .metrics-cards {
2
+ display: flex;
3
+ gap: 16px;
4
+
5
+ margin-bottom: 32px;
6
+
7
+ &__tab {
8
+ text-decoration: none;
9
+
10
+ color: inherit;
11
+ }
12
+ }
@@ -0,0 +1,134 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import {Link, useLocation} from 'react-router-dom';
4
+
5
+ import type {TenantMetricsTab} from '../../../../../store/reducers/tenant/types';
6
+ import {TENANT_METRICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
7
+ import {useTypedSelector} from '../../../../../utils/hooks';
8
+ import {parseQuery} from '../../../../../routes';
9
+ import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
10
+ import {
11
+ calculateUsage,
12
+ cpuUsageToStatus,
13
+ storageUsageToStatus,
14
+ memoryUsageToStatus,
15
+ formatTenantMetrics,
16
+ } from '../../../../../store/reducers/tenants/utils';
17
+ import type {SelfCheckResult, StatusFlag} from '../../../../../types/api/healthcheck';
18
+ import type {IResponseError} from '../../../../../types/api/error';
19
+ import {HealthcheckPreview} from '../Healthcheck/HealthcheckPreview';
20
+ import {MetricCard} from './MetricCard/MetricCard';
21
+
22
+ import './MetricsCards.scss';
23
+
24
+ const b = cn('metrics-cards');
25
+
26
+ export interface TenantMetrics {
27
+ memoryUsed?: number;
28
+ memoryLimit?: number;
29
+ cpuUsed?: number;
30
+ cpuLimit?: number;
31
+ storageUsed?: number;
32
+ storageLimit?: number;
33
+ }
34
+
35
+ interface MetricsCardsProps {
36
+ metrics?: TenantMetrics;
37
+ issuesStatistics?: [StatusFlag, number][];
38
+ selfCheckResult: SelfCheckResult;
39
+ fetchHealthcheck: VoidFunction;
40
+ healthcheckLoading?: boolean;
41
+ healthcheckError?: IResponseError;
42
+ }
43
+
44
+ export function MetricsCards({
45
+ metrics,
46
+ issuesStatistics,
47
+ selfCheckResult,
48
+ fetchHealthcheck,
49
+ healthcheckLoading,
50
+ healthcheckError,
51
+ }: MetricsCardsProps) {
52
+ const location = useLocation();
53
+
54
+ const {memoryUsed, memoryLimit, cpuUsed, cpuLimit, storageUsed, storageLimit} = metrics || {};
55
+
56
+ const {metricsTab} = useTypedSelector((state) => state.tenant);
57
+
58
+ const cpuUsage = calculateUsage(cpuUsed, cpuLimit);
59
+ const storageUsage = calculateUsage(storageUsed, storageLimit);
60
+ const memoryUsage = calculateUsage(memoryUsed, memoryLimit);
61
+
62
+ const cpuStatus = cpuUsageToStatus(cpuUsage);
63
+ const storageStatus = storageUsageToStatus(storageUsage);
64
+ const memoryStatus = memoryUsageToStatus(memoryUsage);
65
+
66
+ const {cpu, storage, memory} = formatTenantMetrics({
67
+ cpu: cpuUsed,
68
+ storage: storageUsed,
69
+ memory: memoryUsed,
70
+ });
71
+
72
+ const queryParams = parseQuery(location);
73
+
74
+ const tabLinks: Record<TenantMetricsTab, string> = {
75
+ [TENANT_METRICS_TABS_IDS.cpu]: getTenantPath({
76
+ ...queryParams,
77
+ [TenantTabsGroups.metricsTab]: TENANT_METRICS_TABS_IDS.cpu,
78
+ }),
79
+ [TENANT_METRICS_TABS_IDS.storage]: getTenantPath({
80
+ ...queryParams,
81
+ [TenantTabsGroups.metricsTab]: TENANT_METRICS_TABS_IDS.storage,
82
+ }),
83
+ [TENANT_METRICS_TABS_IDS.memory]: getTenantPath({
84
+ ...queryParams,
85
+ [TenantTabsGroups.metricsTab]: TENANT_METRICS_TABS_IDS.memory,
86
+ }),
87
+ [TENANT_METRICS_TABS_IDS.healthcheck]: getTenantPath({
88
+ ...queryParams,
89
+ [TenantTabsGroups.metricsTab]: TENANT_METRICS_TABS_IDS.healthcheck,
90
+ }),
91
+ };
92
+
93
+ return (
94
+ <div className={b()}>
95
+ <Link to={tabLinks.cpu} className={b('tab')}>
96
+ <MetricCard
97
+ label="CPU"
98
+ progress={cpuUsage}
99
+ status={cpuStatus}
100
+ resourcesUsed={cpu}
101
+ active={metricsTab === TENANT_METRICS_TABS_IDS.cpu}
102
+ />
103
+ </Link>
104
+ <Link to={tabLinks.storage} className={b('tab')}>
105
+ <MetricCard
106
+ label="Storage"
107
+ progress={storageUsage}
108
+ status={storageStatus}
109
+ resourcesUsed={storage}
110
+ active={metricsTab === TENANT_METRICS_TABS_IDS.storage}
111
+ />
112
+ </Link>
113
+ <Link to={tabLinks.memory} className={b('tab')}>
114
+ <MetricCard
115
+ label="Memory"
116
+ progress={memoryUsage}
117
+ status={memoryStatus}
118
+ resourcesUsed={memory}
119
+ active={metricsTab === TENANT_METRICS_TABS_IDS.memory}
120
+ />
121
+ </Link>
122
+ <Link to={tabLinks.healthcheck} className={b('tab')}>
123
+ <HealthcheckPreview
124
+ selfCheckResult={selfCheckResult}
125
+ issuesStatistics={issuesStatistics}
126
+ onUpdate={fetchHealthcheck}
127
+ loading={healthcheckLoading}
128
+ error={healthcheckError}
129
+ active={metricsTab === TENANT_METRICS_TABS_IDS.healthcheck}
130
+ />
131
+ </Link>
132
+ </div>
133
+ );
134
+ }
@@ -0,0 +1,155 @@
1
+ import cn from 'bem-cn-lite';
2
+ import {useCallback} from 'react';
3
+ import {useDispatch} from 'react-redux';
4
+
5
+ import {Loader} from '@gravity-ui/uikit';
6
+
7
+ import {InfoViewer} from '../../../../components/InfoViewer';
8
+ import {PoolUsage} from '../../../../components/PoolUsage/PoolUsage';
9
+ import {Tablet} from '../../../../components/Tablet';
10
+ import EntityStatus from '../../../../components/EntityStatus/EntityStatus';
11
+ import {formatCPU} from '../../../../utils/dataFormatters/dataFormatters';
12
+ import {TABLET_STATES, TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
13
+ import {bytesToGB} from '../../../../utils/utils';
14
+ import {mapDatabaseTypeToDBName} from '../../utils/schema';
15
+ import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
16
+ import type {ETabletVolatileState} from '../../../../types/api/tenant';
17
+ import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
18
+ import {getTenantInfo, setDataWasNotLoaded} from '../../../../store/reducers/tenant/tenant';
19
+
20
+ import i18n from './i18n';
21
+ import './TenantOverview.scss';
22
+
23
+ const b = cn('tenant-overview');
24
+
25
+ interface OldTenantOverviewProps {
26
+ tenantName: string;
27
+ additionalTenantProps?: AdditionalTenantsProps;
28
+ }
29
+
30
+ export function OldTenantOverview({tenantName, additionalTenantProps}: OldTenantOverviewProps) {
31
+ const {tenant, loading, wasLoaded} = useTypedSelector((state) => state.tenant);
32
+ const {autorefresh} = useTypedSelector((state) => state.schema);
33
+ const dispatch = useDispatch();
34
+ const fetchTenant = useCallback(
35
+ (isBackground = true) => {
36
+ if (!isBackground) {
37
+ dispatch(setDataWasNotLoaded());
38
+ }
39
+ dispatch(getTenantInfo({path: tenantName}));
40
+ },
41
+ [dispatch, tenantName],
42
+ );
43
+
44
+ useAutofetcher(fetchTenant, [fetchTenant], autorefresh);
45
+
46
+ const {
47
+ Metrics = {},
48
+ PoolStats,
49
+ StateStats = [],
50
+ MemoryUsed,
51
+ Name,
52
+ State,
53
+ CoresUsed,
54
+ StorageGroups,
55
+ StorageAllocatedSize,
56
+ Type,
57
+ SystemTablets,
58
+ } = tenant || {};
59
+
60
+ const tenantType = mapDatabaseTypeToDBName(Type);
61
+ const memoryRaw = MemoryUsed ?? Metrics.Memory;
62
+
63
+ const memory = (memoryRaw && bytesToGB(memoryRaw)) || i18n('no-data');
64
+ const storage = (Metrics.Storage && bytesToGB(Metrics.Storage)) || i18n('no-data');
65
+ const storageGroups = StorageGroups ?? i18n('no-data');
66
+ const blobStorage =
67
+ (StorageAllocatedSize && bytesToGB(StorageAllocatedSize)) || i18n('no-data');
68
+ const storageEfficiency =
69
+ Metrics.Storage && StorageAllocatedSize
70
+ ? `${((parseInt(Metrics.Storage) * 100) / parseInt(StorageAllocatedSize)).toFixed(2)}%`
71
+ : i18n('no-data');
72
+
73
+ const cpuRaw = CoresUsed !== undefined ? Number(CoresUsed) * 1_000_000 : Metrics.CPU;
74
+
75
+ const cpu = formatCPU(cpuRaw);
76
+
77
+ const metricsInfo = [
78
+ {label: 'Type', value: Type},
79
+ {label: 'Memory', value: memory},
80
+ {label: 'CPU', value: cpu},
81
+ {label: 'Tablet storage', value: storage},
82
+ {label: 'Storage groups', value: storageGroups},
83
+ {label: 'Blob storage', value: blobStorage},
84
+ {label: 'Storage efficiency', value: storageEfficiency},
85
+ ];
86
+
87
+ const tabletsInfo = StateStats.filter(
88
+ (item): item is {VolatileState: ETabletVolatileState; Count: number} => {
89
+ return item.VolatileState !== undefined && item.Count !== undefined;
90
+ },
91
+ ).map((info) => {
92
+ return {label: TABLET_STATES[info.VolatileState], value: info.Count};
93
+ });
94
+
95
+ const renderName = () => {
96
+ return (
97
+ <div className={b('tenant-name-wrapper')}>
98
+ <EntityStatus
99
+ status={State}
100
+ name={Name || TENANT_DEFAULT_TITLE}
101
+ withLeftTrim
102
+ hasClipboardButton={Boolean(tenant)}
103
+ clipboardButtonAlwaysVisible
104
+ />
105
+ </div>
106
+ );
107
+ };
108
+
109
+ if (loading && !wasLoaded) {
110
+ return (
111
+ <div className={b('loader')}>
112
+ <Loader size="m" />
113
+ </div>
114
+ );
115
+ }
116
+
117
+ return (
118
+ <div className={b()}>
119
+ <div className={b('top-label')}>{tenantType}</div>
120
+ <div className={b('top')}>
121
+ {renderName()}
122
+ {additionalTenantProps?.getMonitoringLink?.(Name, Type)}
123
+ </div>
124
+ <div className={b('system-tablets')}>
125
+ {SystemTablets &&
126
+ SystemTablets.map((tablet, tabletIndex) => (
127
+ <Tablet key={tabletIndex} tablet={tablet} tenantName={Name} />
128
+ ))}
129
+ </div>
130
+ <div className={b('common-info')}>
131
+ <div>
132
+ <div className={b('section-title')}>{i18n('title.pools')}</div>
133
+ {PoolStats ? (
134
+ <div className={b('section', {pools: true})}>
135
+ {PoolStats.map((pool, poolIndex) => (
136
+ <PoolUsage key={poolIndex} data={pool} />
137
+ ))}
138
+ </div>
139
+ ) : (
140
+ <div className="error">{i18n('no-pools-data')}</div>
141
+ )}
142
+ </div>
143
+ <InfoViewer
144
+ title={i18n('title.metrics')}
145
+ className={b('section', {metrics: true})}
146
+ info={metricsInfo}
147
+ />
148
+
149
+ <div className={b('section')}>
150
+ <InfoViewer info={tabletsInfo} title="Tablets" />
151
+ </div>
152
+ </div>
153
+ </div>
154
+ );
155
+ }
@@ -1,7 +1,6 @@
1
- @use '../DetailedOverview/DetailedOverview.scss' as detailedOverview;
2
-
3
1
  .tenant-overview {
4
2
  padding-bottom: 20px;
3
+
5
4
  &__loader {
6
5
  display: flex;
7
6
  justify-content: center;
@@ -22,10 +21,10 @@
22
21
  }
23
22
 
24
23
  &__top-label {
25
- margin-bottom: detailedOverview.$section-title-margin;
24
+ margin-bottom: var(--diagnostics-section-title-margin);
26
25
 
27
26
  font-weight: 600;
28
- line-height: detailedOverview.$section-title-line-height;
27
+ line-height: 24px;
29
28
  gap: 10px;
30
29
  }
31
30
 
@@ -50,7 +49,6 @@
50
49
  font-size: var(--yc-text-body-2-font-size);
51
50
  font-weight: 500;
52
51
  line-height: var(--yc-text-body-2-line-height);
53
- //text-transform: uppercase;
54
52
  }
55
53
 
56
54
  &__section {
@@ -4,18 +4,17 @@ import {useDispatch} from 'react-redux';
4
4
 
5
5
  import {Loader} from '@gravity-ui/uikit';
6
6
 
7
- import {InfoViewer} from '../../../../components/InfoViewer';
8
- import {PoolUsage} from '../../../../components/PoolUsage/PoolUsage';
9
- import {Tablet} from '../../../../components/Tablet';
10
7
  import EntityStatus from '../../../../components/EntityStatus/EntityStatus';
11
- import {formatCPU} from '../../../../utils';
12
- import {TABLET_STATES, TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
13
- import {bytesToGB} from '../../../../utils/utils';
8
+ import {TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
9
+ import {TENANT_METRICS_TABS_IDS} from '../../../../store/reducers/tenant/constants';
14
10
  import {mapDatabaseTypeToDBName} from '../../utils/schema';
15
11
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
16
- import type {ETabletVolatileState} from '../../../../types/api/tenant';
17
12
  import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
18
13
  import {getTenantInfo, setDataWasNotLoaded} from '../../../../store/reducers/tenant/tenant';
14
+ import {calculateTenantMetrics} from '../../../../store/reducers/tenants/utils';
15
+ import {HealthcheckDetails} from './Healthcheck/HealthcheckDetails';
16
+ import {MetricsCards, type TenantMetrics} from './MetricsCards/MetricsCards';
17
+ import {useHealthcheck} from './useHealthcheck';
19
18
 
20
19
  import i18n from './i18n';
21
20
  import './TenantOverview.scss';
@@ -28,9 +27,26 @@ interface TenantOverviewProps {
28
27
  }
29
28
 
30
29
  export function TenantOverview({tenantName, additionalTenantProps}: TenantOverviewProps) {
31
- const {tenant, loading, wasLoaded} = useTypedSelector((state) => state.tenant);
32
- const {autorefresh} = useTypedSelector((state) => state.schema);
33
30
  const dispatch = useDispatch();
31
+
32
+ const {
33
+ tenant,
34
+ loading: tenantLoading,
35
+ wasLoaded: tenantWasLoaded,
36
+ metricsTab,
37
+ } = useTypedSelector((state) => state.tenant);
38
+ const {autorefresh} = useTypedSelector((state) => state.schema);
39
+
40
+ const {
41
+ issueTrees,
42
+ issuesStatistics,
43
+ selfCheckResult,
44
+ fetchHealthcheck,
45
+ loading: healthcheckLoading,
46
+ wasLoaded: healthCheckWasLoaded,
47
+ error: healthcheckError,
48
+ } = useHealthcheck(tenantName);
49
+
34
50
  const fetchTenant = useCallback(
35
51
  (isBackground = true) => {
36
52
  if (!isBackground) {
@@ -41,56 +57,30 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
41
57
  [dispatch, tenantName],
42
58
  );
43
59
 
44
- useAutofetcher(fetchTenant, [fetchTenant], autorefresh);
60
+ useAutofetcher(
61
+ (isBackground) => {
62
+ fetchTenant(isBackground);
63
+ fetchHealthcheck(isBackground);
64
+ },
65
+ [fetchTenant, fetchHealthcheck],
66
+ autorefresh,
67
+ );
45
68
 
46
- const {
47
- Metrics = {},
48
- PoolStats,
49
- StateStats = [],
50
- MemoryUsed,
51
- Name,
52
- State,
53
- CoresUsed,
54
- StorageGroups,
55
- StorageAllocatedSize,
56
- Type,
57
- SystemTablets,
58
- } = tenant || {};
69
+ const {Name, State, Type} = tenant || {};
59
70
 
60
71
  const tenantType = mapDatabaseTypeToDBName(Type);
61
- const memoryRaw = MemoryUsed ?? Metrics.Memory;
62
-
63
- const memory = (memoryRaw && bytesToGB(memoryRaw)) || i18n('no-data');
64
- const storage = (Metrics.Storage && bytesToGB(Metrics.Storage)) || i18n('no-data');
65
- const storageGroups = StorageGroups ?? i18n('no-data');
66
- const blobStorage =
67
- (StorageAllocatedSize && bytesToGB(StorageAllocatedSize)) || i18n('no-data');
68
- const storageEfficiency =
69
- Metrics.Storage && StorageAllocatedSize
70
- ? `${((parseInt(Metrics.Storage) * 100) / parseInt(StorageAllocatedSize)).toFixed(2)}%`
71
- : i18n('no-data');
72
-
73
- const cpuRaw = CoresUsed !== undefined ? Number(CoresUsed) * 1_000_000 : Metrics.CPU;
74
-
75
- const cpu = formatCPU(cpuRaw);
76
-
77
- const metricsInfo = [
78
- {label: 'Type', value: Type},
79
- {label: 'Memory', value: memory},
80
- {label: 'CPU', value: cpu},
81
- {label: 'Tablet storage', value: storage},
82
- {label: 'Storage groups', value: storageGroups},
83
- {label: 'Blob storage', value: blobStorage},
84
- {label: 'Storage efficiency', value: storageEfficiency},
85
- ];
86
-
87
- const tabletsInfo = StateStats.filter(
88
- (item): item is {VolatileState: ETabletVolatileState; Count: number} => {
89
- return item.VolatileState !== undefined && item.Count !== undefined;
90
- },
91
- ).map((info) => {
92
- return {label: TABLET_STATES[info.VolatileState], value: info.Count};
93
- });
72
+
73
+ const {cpu, storage, memory, cpuLimit, storageLimit, memoryLimit} =
74
+ calculateTenantMetrics(tenant);
75
+
76
+ const calculatedMetrics: TenantMetrics = {
77
+ memoryUsed: memory,
78
+ memoryLimit,
79
+ cpuUsed: cpu,
80
+ cpuLimit,
81
+ storageUsed: storage,
82
+ storageLimit,
83
+ };
94
84
 
95
85
  const renderName = () => {
96
86
  return (
@@ -106,7 +96,27 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
106
96
  );
107
97
  };
108
98
 
109
- if (loading && !wasLoaded) {
99
+ const renderTabContent = () => {
100
+ switch (metricsTab) {
101
+ case TENANT_METRICS_TABS_IDS.cpu: {
102
+ return i18n('label.under-development');
103
+ }
104
+ case TENANT_METRICS_TABS_IDS.storage: {
105
+ return i18n('label.under-development');
106
+ }
107
+ case TENANT_METRICS_TABS_IDS.memory: {
108
+ return i18n('label.under-development');
109
+ }
110
+ case TENANT_METRICS_TABS_IDS.healthcheck: {
111
+ return <HealthcheckDetails issueTrees={issueTrees} error={healthcheckError} />;
112
+ }
113
+ default: {
114
+ return undefined;
115
+ }
116
+ }
117
+ };
118
+
119
+ if ((tenantLoading && !tenantWasLoaded) || (healthcheckLoading && !healthCheckWasLoaded)) {
110
120
  return (
111
121
  <div className={b('loader')}>
112
122
  <Loader size="m" />
@@ -121,35 +131,15 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
121
131
  {renderName()}
122
132
  {additionalTenantProps?.getMonitoringLink?.(Name, Type)}
123
133
  </div>
124
- <div className={b('system-tablets')}>
125
- {SystemTablets &&
126
- SystemTablets.map((tablet, tabletIndex) => (
127
- <Tablet key={tabletIndex} tablet={tablet} tenantName={Name} />
128
- ))}
129
- </div>
130
- <div className={b('common-info')}>
131
- <div>
132
- <div className={b('section-title')}>{i18n('title.pools')}</div>
133
- {PoolStats ? (
134
- <div className={b('section', {pools: true})}>
135
- {PoolStats.map((pool, poolIndex) => (
136
- <PoolUsage key={poolIndex} data={pool} />
137
- ))}
138
- </div>
139
- ) : (
140
- <div className="error">{i18n('no-pools-data')}</div>
141
- )}
142
- </div>
143
- <InfoViewer
144
- title={i18n('title.metrics')}
145
- className={b('section', {metrics: true})}
146
- info={metricsInfo}
147
- />
148
-
149
- <div className={b('section')}>
150
- <InfoViewer info={tabletsInfo} title="Tablets" />
151
- </div>
152
- </div>
134
+ <MetricsCards
135
+ metrics={calculatedMetrics}
136
+ issuesStatistics={issuesStatistics}
137
+ selfCheckResult={selfCheckResult}
138
+ fetchHealthcheck={fetchHealthcheck}
139
+ healthcheckLoading={healthcheckLoading}
140
+ healthcheckError={healthcheckError}
141
+ />
142
+ {renderTabContent()}
153
143
  </div>
154
144
  );
155
145
  }
@@ -3,5 +3,7 @@
3
3
  "no-pools-data": "No pools data",
4
4
 
5
5
  "title.pools": "Pools",
6
- "title.metrics": "Metrics"
6
+ "title.metrics": "Metrics",
7
+
8
+ "label.under-development": "This section is under development"
7
9
  }
@@ -3,5 +3,7 @@
3
3
  "no-pools-data": "Нет данных о пулах",
4
4
 
5
5
  "title.pools": "Пулы",
6
- "title.metrics": "Метрики"
6
+ "title.metrics": "Метрики",
7
+
8
+ "label.under-development": "Этот раздел находится в разработке"
7
9
  }