ydb-embedded-ui 4.16.2 → 4.17.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +15 -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/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +1 -5
  7. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +40 -17
  8. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/Details.tsx +3 -3
  9. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.scss +27 -14
  10. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.tsx +6 -6
  11. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/Preview.tsx +15 -16
  12. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/Healthcheck.scss +108 -0
  13. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +45 -0
  14. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +83 -0
  15. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.scss +1 -3
  16. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.tsx +1 -1
  17. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +1 -1
  18. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/en.json +2 -1
  19. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/index.ts +1 -1
  20. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/ru.json +2 -1
  21. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.scss +52 -0
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.tsx +48 -0
  23. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.scss +12 -0
  24. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +134 -0
  25. package/dist/containers/Tenant/Diagnostics/TenantOverview/OldTenantOverview.tsx +155 -0
  26. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +3 -5
  27. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +76 -86
  28. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -1
  29. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -1
  30. package/dist/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts +53 -0
  31. package/dist/containers/Tenant/TenantPages.tsx +1 -0
  32. package/dist/containers/UserSettings/i18n/en.json +4 -1
  33. package/dist/containers/UserSettings/i18n/ru.json +4 -1
  34. package/dist/containers/UserSettings/settings.ts +7 -0
  35. package/dist/services/api.ts +6 -4
  36. package/dist/store/reducers/healthcheckInfo.ts +20 -12
  37. package/dist/store/reducers/settings/settings.ts +5 -0
  38. package/dist/store/reducers/tenant/constants.ts +7 -0
  39. package/dist/store/reducers/tenant/tenant.ts +15 -0
  40. package/dist/store/reducers/tenant/types.ts +5 -0
  41. package/dist/store/reducers/tenants/contants.ts +6 -0
  42. package/dist/store/reducers/tenants/types.ts +4 -0
  43. package/dist/store/reducers/tenants/utils.ts +114 -7
  44. package/dist/store/state-url-mapping.js +3 -0
  45. package/dist/styles/constants.scss +2 -0
  46. package/dist/types/api/tenant.ts +3 -0
  47. package/dist/utils/constants.ts +1 -0
  48. package/dist/utils/formatCPU/formatCPU.ts +20 -0
  49. package/dist/utils/formatCPU/i18n/en.json +3 -0
  50. package/dist/utils/formatCPU/i18n/index.ts +11 -0
  51. package/dist/utils/formatCPU/i18n/ru.json +3 -0
  52. package/package.json +1 -1
  53. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/index.ts +0 -0
  54. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/index.ts +0 -0
  55. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/index.ts +0 -0
  56. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +0 -0
  57. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/index.ts +0 -0
@@ -0,0 +1,83 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import {Button, Icon} from '@gravity-ui/uikit';
4
+
5
+ import updateArrow from '../../../../../assets/icons/update-arrow.svg';
6
+
7
+ import {SelfCheckResult, type StatusFlag} from '../../../../../types/api/healthcheck';
8
+ import type {IResponseError} from '../../../../../types/api/error';
9
+ import {DiagnosticCard} from '../../../../../components/DiagnosticCard/DiagnosticCard';
10
+ import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
11
+ import {ResponseError} from '../../../../../components/Errors/ResponseError';
12
+
13
+ import i18n from './i18n';
14
+ import './Healthcheck.scss';
15
+
16
+ const b = cn('healthcheck');
17
+
18
+ interface HealthcheckPreviewProps {
19
+ selfCheckResult: SelfCheckResult;
20
+ issuesStatistics?: [StatusFlag, number][];
21
+ loading?: boolean;
22
+ onUpdate: VoidFunction;
23
+ error?: IResponseError;
24
+ active?: boolean;
25
+ }
26
+
27
+ export function HealthcheckPreview(props: HealthcheckPreviewProps) {
28
+ const {selfCheckResult, issuesStatistics, loading, onUpdate, error, active} = props;
29
+
30
+ const renderHeader = () => {
31
+ const modifier = selfCheckResult.toLowerCase();
32
+
33
+ return (
34
+ <div className={b('preview-header')}>
35
+ <div className={b('preview-title-wrapper')}>
36
+ <div className={b('preview-title')}>{i18n('title.healthcheck')}</div>
37
+ <Button size="s" onClick={onUpdate} loading={loading} view="flat-secondary">
38
+ <Icon data={updateArrow} width={20} height={20} />
39
+ </Button>
40
+ </div>
41
+ <div className={b('self-check-status-indicator', {[modifier]: true})}>
42
+ {selfCheckResult}
43
+ </div>
44
+ </div>
45
+ );
46
+ };
47
+
48
+ const renderContent = () => {
49
+ if (error) {
50
+ return <ResponseError error={error} defaultMessage={i18n('no-data')} />;
51
+ }
52
+
53
+ return (
54
+ <div className={b('preview-content')}>
55
+ {!issuesStatistics || !issuesStatistics.length ? (
56
+ i18n('status_message.ok')
57
+ ) : (
58
+ <>
59
+ <div>{i18n('label.issues')}</div>
60
+ <div className={b('issues-statistics')}>
61
+ {issuesStatistics.map(([status, count]) => (
62
+ <EntityStatus
63
+ key={status}
64
+ mode="icons"
65
+ status={status}
66
+ label={count.toString()}
67
+ size="l"
68
+ />
69
+ ))}
70
+ </div>
71
+ </>
72
+ )}
73
+ </div>
74
+ );
75
+ };
76
+
77
+ return (
78
+ <DiagnosticCard className={b('preview')} active={active}>
79
+ {renderHeader()}
80
+ {renderContent()}
81
+ </DiagnosticCard>
82
+ );
83
+ }
@@ -1,4 +1,4 @@
1
- @import '../../../../../styles/mixins.scss';
1
+ @import '../../../../../../styles/mixins.scss';
2
2
 
3
3
  .indicator {
4
4
  width: 12px;
@@ -38,8 +38,6 @@
38
38
  .issue-tree {
39
39
  display: flex;
40
40
 
41
- width: 820px;
42
-
43
41
  &__block {
44
42
  width: 100%;
45
43
  }
@@ -7,7 +7,7 @@ import JSONTree from 'react-json-inspector';
7
7
 
8
8
  import {TreeView} from 'ydb-ui-components';
9
9
 
10
- import {IIssuesTree} from '../../../../../types/store/healthcheck';
10
+ import {IIssuesTree} from '../../../../../../types/store/healthcheck';
11
11
 
12
12
  import {IssueTreeItem} from './IssueTreeItem';
13
13
 
@@ -1,6 +1,6 @@
1
1
  import cn from 'bem-cn-lite';
2
2
 
3
- import EntityStatus from '../../../../../../components/EntityStatus/EntityStatus';
3
+ import EntityStatus from '../../../../../../../components/EntityStatus/EntityStatus';
4
4
 
5
5
  import './IssueTreeItem.scss';
6
6
 
@@ -2,6 +2,7 @@
2
2
  "title.healthcheck": "Healthcheck",
3
3
  "label.update": "Update",
4
4
  "label.show-details": "Show details",
5
- "status_message.ok": "No issues have been found on this database",
5
+ "label.issues": "Issues:",
6
+ "status_message.ok": "No issues",
6
7
  "no-data": "no healthcheck data"
7
8
  }
@@ -1,4 +1,4 @@
1
- import {i18n, Lang} from '../../../../../utils/i18n';
1
+ import {i18n, Lang} from '../../../../../../utils/i18n';
2
2
 
3
3
  import en from './en.json';
4
4
  import ru from './ru.json';
@@ -2,6 +2,7 @@
2
2
  "title.healthcheck": "Healthcheck",
3
3
  "label.update": "Обновить",
4
4
  "label.show-details": "Посмотреть подробности",
5
- "status_message.ok": "В базе данных нет проблем",
5
+ "label.issues": "Проблемы:",
6
+ "status_message.ok": "Нет проблем",
6
7
  "no-data": "нет данных healthcheck"
7
8
  }
@@ -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';
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 {