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.
- package/CHANGELOG.md +15 -0
- package/dist/components/CircularProgressBar/CircularProgressBar.scss +42 -0
- package/dist/components/CircularProgressBar/CircularProgressBar.tsx +59 -0
- package/dist/components/DiagnosticCard/DiagnosticCard.scss +20 -3
- package/dist/components/DiagnosticCard/DiagnosticCard.tsx +5 -6
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +1 -5
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +40 -17
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/Details.tsx +3 -3
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.scss +27 -14
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.tsx +6 -6
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/Preview.tsx +15 -16
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/Healthcheck.scss +108 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +45 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +83 -0
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.scss +1 -3
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/en.json +2 -1
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/index.ts +1 -1
- package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/ru.json +2 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.scss +52 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.tsx +48 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.scss +12 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +134 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/OldTenantOverview.tsx +155 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +3 -5
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +76 -86
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts +53 -0
- package/dist/containers/Tenant/TenantPages.tsx +1 -0
- package/dist/containers/UserSettings/i18n/en.json +4 -1
- package/dist/containers/UserSettings/i18n/ru.json +4 -1
- package/dist/containers/UserSettings/settings.ts +7 -0
- package/dist/services/api.ts +6 -4
- package/dist/store/reducers/healthcheckInfo.ts +20 -12
- package/dist/store/reducers/settings/settings.ts +5 -0
- package/dist/store/reducers/tenant/constants.ts +7 -0
- package/dist/store/reducers/tenant/tenant.ts +15 -0
- package/dist/store/reducers/tenant/types.ts +5 -0
- package/dist/store/reducers/tenants/contants.ts +6 -0
- package/dist/store/reducers/tenants/types.ts +4 -0
- package/dist/store/reducers/tenants/utils.ts +114 -7
- package/dist/store/state-url-mapping.js +3 -0
- package/dist/styles/constants.scss +2 -0
- package/dist/types/api/tenant.ts +3 -0
- package/dist/utils/constants.ts +1 -0
- package/dist/utils/formatCPU/formatCPU.ts +20 -0
- package/dist/utils/formatCPU/i18n/en.json +3 -0
- package/dist/utils/formatCPU/i18n/index.ts +11 -0
- package/dist/utils/formatCPU/i18n/ru.json +3 -0
- package/package.json +1 -1
- /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/index.ts +0 -0
- /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/index.ts +0 -0
- /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/index.ts +0 -0
- /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +0 -0
- /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 | 
            +
            }
         | 
| @@ -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 ' | 
| 10 | 
            +
            import {IIssuesTree} from '../../../../../../types/store/healthcheck';
         | 
| 11 11 |  | 
| 12 12 | 
             
            import {IssueTreeItem} from './IssueTreeItem';
         | 
| 13 13 |  | 
    
        package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/en.json
    RENAMED
    
    | @@ -2,6 +2,7 @@ | |
| 2 2 | 
             
              "title.healthcheck": "Healthcheck",
         | 
| 3 3 | 
             
              "label.update": "Update",
         | 
| 4 4 | 
             
              "label.show-details": "Show details",
         | 
| 5 | 
            -
              " | 
| 5 | 
            +
              "label.issues": "Issues:",
         | 
| 6 | 
            +
              "status_message.ok": "No issues",
         | 
| 6 7 | 
             
              "no-data": "no healthcheck data"
         | 
| 7 8 | 
             
            }
         | 
    
        package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/ru.json
    RENAMED
    
    | @@ -2,6 +2,7 @@ | |
| 2 2 | 
             
              "title.healthcheck": "Healthcheck",
         | 
| 3 3 | 
             
              "label.update": "Обновить",
         | 
| 4 4 | 
             
              "label.show-details": "Посмотреть подробности",
         | 
| 5 | 
            -
              " | 
| 5 | 
            +
              "label.issues": "Проблемы:",
         | 
| 6 | 
            +
              "status_message.ok": "Нет проблем",
         | 
| 6 7 | 
             
              "no-data": "нет данных healthcheck"
         | 
| 7 8 | 
             
            }
         | 
    
        package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.scss
    ADDED
    
    | @@ -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 | 
            +
            }
         | 
    
        package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.tsx
    ADDED
    
    | @@ -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,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:  | 
| 24 | 
            +
                    margin-bottom: var(--diagnostics-section-title-margin);
         | 
| 26 25 |  | 
| 27 26 | 
             
                    font-weight: 600;
         | 
| 28 | 
            -
                    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 {
         |