({
diff --git a/src/containers/AsideNavigation/AsideNavigation.tsx b/src/containers/AsideNavigation/AsideNavigation.tsx
index 2061d4250..c14e90a0d 100644
--- a/src/containers/AsideNavigation/AsideNavigation.tsx
+++ b/src/containers/AsideNavigation/AsideNavigation.tsx
@@ -50,7 +50,9 @@ function YbdInternalUser({ydbUser, logout}: YbdInternalUserProps) {
const history = useHistory();
const handleLoginClick = () => {
- history.push(createHref(routes.auth, undefined, {returnUrl: encodeURI(location.href)}));
+ history.push(
+ createHref(routes.auth, undefined, {returnUrl: encodeURIComponent(location.href)}),
+ );
};
return (
diff --git a/src/containers/Authentication/Authentication.tsx b/src/containers/Authentication/Authentication.tsx
index f70a4cea8..8ddd18d1a 100644
--- a/src/containers/Authentication/Authentication.tsx
+++ b/src/containers/Authentication/Authentication.tsx
@@ -1,12 +1,13 @@
import {KeyboardEvent, useEffect, useState} from 'react';
import {useDispatch} from 'react-redux';
-import {useHistory} from 'react-router';
+import {useHistory, useLocation} from 'react-router';
import cn from 'bem-cn-lite';
import {Button, TextInput, Icon, Link as ExternalLink} from '@gravity-ui/uikit';
import {authenticate} from '../../store/reducers/authentication/authentication';
import {useTypedSelector} from '../../utils/hooks';
+import {parseQuery} from '../../routes';
import ydbLogoIcon from '../../assets/icons/ydb.svg';
import showIcon from '../../assets/icons/show.svg';
@@ -18,13 +19,15 @@ import './Authentication.scss';
const b = cn('authentication');
interface AuthenticationProps {
- returnUrl?: string;
closable?: boolean;
}
-function Authentication({returnUrl, closable = false}: AuthenticationProps) {
+function Authentication({closable = false}: AuthenticationProps) {
const dispatch = useDispatch();
const history = useHistory();
+ const location = useLocation();
+
+ const {returnUrl} = parseQuery(location);
const {error} = useTypedSelector((state) => state.authentication);
@@ -58,7 +61,14 @@ function Authentication({returnUrl, closable = false}: AuthenticationProps) {
// typed dispatch required, remove error expectation after adding it
dispatch(authenticate(login, pass)).then(() => {
if (returnUrl) {
- history.replace(decodeURI(returnUrl));
+ const decodedUrl = decodeURIComponent(returnUrl.toString());
+
+ // to prevent page reload we use router history
+ // history navigates relative to origin
+ // so we remove origin to make it work properly
+ const url = new URL(decodedUrl);
+ const path = url.pathname + url.search;
+ history.replace(path);
}
});
};
diff --git a/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx b/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx
index 252e33b6e..5624d023e 100644
--- a/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx
+++ b/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx
@@ -3,7 +3,7 @@ import block from 'bem-cn-lite';
import {Skeleton} from '@gravity-ui/uikit';
import EntityStatus from '../../../components/EntityStatus/EntityStatus';
-import ProgressViewer from '../../../components/ProgressViewer/ProgressViewer';
+import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
import InfoViewer, {InfoViewerItem} from '../../../components/InfoViewer/InfoViewer';
import {Tags} from '../../../components/Tags';
import {Tablet} from '../../../components/Tablet';
@@ -16,7 +16,7 @@ import type {AdditionalClusterProps, ClusterLink} from '../../../types/additiona
import type {VersionValue} from '../../../types/versions';
import type {TClusterInfo} from '../../../types/api/cluster';
import {backend, customBackend} from '../../../store';
-import {formatStorageValues} from '../../../utils';
+import {formatStorageValues} from '../../../utils/dataFormatters/dataFormatters';
import {useSetting, useTypedSelector} from '../../../utils/hooks';
import {
CLUSTER_DEFAULT_TITLE,
diff --git a/src/containers/Heatmap/Heatmap.tsx b/src/containers/Heatmap/Heatmap.tsx
index 71ec1f96a..c75a41f93 100644
--- a/src/containers/Heatmap/Heatmap.tsx
+++ b/src/containers/Heatmap/Heatmap.tsx
@@ -7,7 +7,7 @@ import {Checkbox, Select} from '@gravity-ui/uikit';
import type {IHeatmapMetricValue} from '../../types/store/heatmap';
import {getTabletsInfo, setHeatmapOptions} from '../../store/reducers/heatmap';
import {showTooltip, hideTooltip} from '../../store/reducers/tooltip';
-import {formatNumber} from '../../utils';
+import {formatNumber} from '../../utils/dataFormatters/dataFormatters';
import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
import {Loader} from '../../components/Loader';
diff --git a/src/containers/Heatmap/Histogram/Histogram.js b/src/containers/Heatmap/Histogram/Histogram.js
index 843179bb1..54b2ec440 100644
--- a/src/containers/Heatmap/Histogram/Histogram.js
+++ b/src/containers/Heatmap/Histogram/Histogram.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import cn from 'bem-cn-lite';
import {getColorRange, getCurrentMetricLimits} from '../util';
-import {formatNumber} from '../../../utils';
+import {formatNumber} from '../../../utils/dataFormatters/dataFormatters';
import './Histogram.scss';
diff --git a/src/containers/Node/NodeStructure/Pdisk.tsx b/src/containers/Node/NodeStructure/Pdisk.tsx
index 1b86cc789..73cc33091 100644
--- a/src/containers/Node/NodeStructure/Pdisk.tsx
+++ b/src/containers/Node/NodeStructure/Pdisk.tsx
@@ -8,12 +8,12 @@ import DataTable, {Column, Settings} from '@gravity-ui/react-data-table';
import EntityStatus from '../../../components/EntityStatus/EntityStatus';
import InfoViewer from '../../../components/InfoViewer/InfoViewer';
-import ProgressViewer from '../../../components/ProgressViewer/ProgressViewer';
+import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
import {Icon} from '../../../components/Icon';
import {Vdisk} from './Vdisk';
import {bytesToGB, pad9} from '../../../utils/utils';
-import {formatStorageValuesToGb} from '../../../utils';
+import {formatStorageValuesToGb} from '../../../utils/dataFormatters/dataFormatters';
import {getPDiskType} from '../../../utils/pdisk';
import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
diff --git a/src/containers/Node/NodeStructure/Vdisk.tsx b/src/containers/Node/NodeStructure/Vdisk.tsx
index 54f2b4818..30b733da5 100644
--- a/src/containers/Node/NodeStructure/Vdisk.tsx
+++ b/src/containers/Node/NodeStructure/Vdisk.tsx
@@ -1,8 +1,11 @@
import React from 'react';
import cn from 'bem-cn-lite';
-import ProgressViewer from '../../../components/ProgressViewer/ProgressViewer';
-import {formatStorageValuesToGb, stringifyVdiskId} from '../../../utils';
+import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
+import {
+ formatStorageValuesToGb,
+ stringifyVdiskId,
+} from '../../../utils/dataFormatters/dataFormatters';
import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
import EntityStatus from '../../../components/EntityStatus/EntityStatus';
import {valueIsDefined} from './NodeStructure';
diff --git a/src/containers/Nodes/getNodesColumns.tsx b/src/containers/Nodes/getNodesColumns.tsx
index 5ac4ee696..023dc7ca0 100644
--- a/src/containers/Nodes/getNodesColumns.tsx
+++ b/src/containers/Nodes/getNodesColumns.tsx
@@ -2,12 +2,12 @@ import DataTable, {Column} from '@gravity-ui/react-data-table';
import {Popover} from '@gravity-ui/uikit';
import {PoolsGraph} from '../../components/PoolsGraph/PoolsGraph';
-import ProgressViewer from '../../components/ProgressViewer/ProgressViewer';
+import {ProgressViewer} from '../../components/ProgressViewer/ProgressViewer';
import {TabletsStatistic} from '../../components/TabletsStatistic';
import {NodeHostWrapper} from '../../components/NodeHostWrapper/NodeHostWrapper';
import {isSortableNodesProperty} from '../../utils/nodes';
-import {formatBytesToGigabyte} from '../../utils/index';
+import {formatBytesToGigabyte} from '../../utils/dataFormatters/dataFormatters';
import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
diff --git a/src/containers/Storage/PDisk/PDisk.tsx b/src/containers/Storage/PDisk/PDisk.tsx
index 3df8ec675..fe022de1f 100644
--- a/src/containers/Storage/PDisk/PDisk.tsx
+++ b/src/containers/Storage/PDisk/PDisk.tsx
@@ -7,7 +7,7 @@ import {Stack} from '../../../components/Stack/Stack';
import routes, {createHref} from '../../../routes';
import {selectVDisksForPDisk} from '../../../store/reducers/storage/selectors';
import {TPDiskStateInfo, TPDiskState} from '../../../types/api/pdisk';
-import {stringifyVdiskId} from '../../../utils';
+import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
import {useTypedSelector} from '../../../utils/hooks';
import {getPDiskType} from '../../../utils/pdisk';
import {isFullVDiskData} from '../../../utils/storage';
diff --git a/src/containers/Storage/PDiskPopup/PDiskPopup.tsx b/src/containers/Storage/PDiskPopup/PDiskPopup.tsx
index 5ed6323c9..bfe2d8e6e 100644
--- a/src/containers/Storage/PDiskPopup/PDiskPopup.tsx
+++ b/src/containers/Storage/PDiskPopup/PDiskPopup.tsx
@@ -9,7 +9,7 @@ import {InfoViewer, InfoViewerItem} from '../../../components/InfoViewer';
import {EFlag} from '../../../types/api/enums';
import {TPDiskStateInfo} from '../../../types/api/pdisk';
-import {getPDiskId} from '../../../utils';
+import {getPDiskId} from '../../../utils/dataFormatters/dataFormatters';
import {getPDiskType} from '../../../utils/pdisk';
import {bytesToGB} from '../../../utils/utils';
diff --git a/src/containers/Storage/StorageGroups/StorageGroups.tsx b/src/containers/Storage/StorageGroups/StorageGroups.tsx
index 909d33cd2..bb308fcb7 100644
--- a/src/containers/Storage/StorageGroups/StorageGroups.tsx
+++ b/src/containers/Storage/StorageGroups/StorageGroups.tsx
@@ -10,7 +10,7 @@ import type {HandleSort} from '../../../utils/hooks/useTableSort';
import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
-import {stringifyVdiskId} from '../../../utils';
+import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
import {getUsage, isFullVDiskData, isSortableStorageProperty} from '../../../utils/storage';
import shieldIcon from '../../../assets/icons/shield.svg';
diff --git a/src/containers/Storage/VDisk/VDisk.tsx b/src/containers/Storage/VDisk/VDisk.tsx
index 5bf6fb4c4..270762382 100644
--- a/src/containers/Storage/VDisk/VDisk.tsx
+++ b/src/containers/Storage/VDisk/VDisk.tsx
@@ -8,7 +8,7 @@ import {InternalLink} from '../../../components/InternalLink';
import routes, {createHref} from '../../../routes';
import {EFlag} from '../../../types/api/enums';
import {EVDiskState, TVDiskStateInfo} from '../../../types/api/vdisk';
-import {stringifyVdiskId} from '../../../utils';
+import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
import {isFullVDiskData} from '../../../utils/storage';
import {STRUCTURE} from '../../Node/NodePages';
diff --git a/src/containers/Storage/VDiskPopup/VDiskPopup.tsx b/src/containers/Storage/VDiskPopup/VDiskPopup.tsx
index 2e0f62384..2802a1272 100644
--- a/src/containers/Storage/VDiskPopup/VDiskPopup.tsx
+++ b/src/containers/Storage/VDiskPopup/VDiskPopup.tsx
@@ -9,7 +9,7 @@ import {InfoViewer, InfoViewerItem} from '../../../components/InfoViewer';
import {EFlag} from '../../../types/api/enums';
import type {TVDiskStateInfo} from '../../../types/api/vdisk';
-import {stringifyVdiskId} from '../../../utils';
+import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
import {isFullVDiskData} from '../../../utils/storage';
diff --git a/src/containers/Tablet/TabletInfo/TabletInfo.tsx b/src/containers/Tablet/TabletInfo/TabletInfo.tsx
index ad581677d..8fd2f264e 100644
--- a/src/containers/Tablet/TabletInfo/TabletInfo.tsx
+++ b/src/containers/Tablet/TabletInfo/TabletInfo.tsx
@@ -5,7 +5,7 @@ import {Link as UIKitLink} from '@gravity-ui/uikit';
import {ETabletState, TTabletStateInfo} from '../../../types/api/tablet';
import {InfoViewer, InfoViewerItem} from '../../../components/InfoViewer';
import routes, {createHref} from '../../../routes';
-import {calcUptime} from '../../../utils';
+import {calcUptime} from '../../../utils/dataFormatters/dataFormatters';
import {getDefaultNodePath} from '../../Node/NodePages';
import {b} from '../Tablet';
diff --git a/src/containers/Tablet/TabletTable/TabletTable.tsx b/src/containers/Tablet/TabletTable/TabletTable.tsx
index 678b96c2b..fc027b967 100644
--- a/src/containers/Tablet/TabletTable/TabletTable.tsx
+++ b/src/containers/Tablet/TabletTable/TabletTable.tsx
@@ -4,7 +4,7 @@ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
import {InternalLink} from '../../../components/InternalLink/InternalLink';
import type {ITabletPreparedHistoryItem} from '../../../types/store/tablet';
-import {calcUptime} from '../../../utils';
+import {calcUptime} from '../../../utils/dataFormatters/dataFormatters';
import {getDefaultNodePath} from '../../Node/NodePages';
import {b} from '../Tablet';
diff --git a/src/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.tsx b/src/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.tsx
index 0d3ab4923..d7a755a48 100644
--- a/src/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.tsx
+++ b/src/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.tsx
@@ -1,7 +1,7 @@
import block from 'bem-cn-lite';
import type {IPreparedTopicStats} from '../../../../../types/store/topic';
-import {formatMsToUptime} from '../../../../../utils';
+import {formatMsToUptime} from '../../../../../utils/dataFormatters/dataFormatters';
import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
import './ConsumersTopicStats.scss';
diff --git a/src/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx b/src/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx
index 03f33fe44..4ee394454 100644
--- a/src/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx
+++ b/src/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx
@@ -6,7 +6,7 @@ import type {IPreparedConsumerData} from '../../../../../types/store/topic';
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
import {InternalLink} from '../../../../../components/InternalLink';
-import {formatMsToUptime} from '../../../../../utils';
+import {formatMsToUptime} from '../../../../../utils/dataFormatters/dataFormatters';
import routes, {createHref} from '../../../../../routes';
import {TenantTabsGroups} from '../../../TenantPages';
diff --git a/src/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx b/src/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx
index 1c0305860..588ccd504 100644
--- a/src/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx
+++ b/src/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx
@@ -8,7 +8,7 @@ import type {EPathType} from '../../../../types/api/schema';
import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
import {Icon} from '../../../../components/Icon';
import {useSetting} from '../../../../utils/hooks';
-import {ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN} from '../../../../utils/constants';
+import {DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS} from '../../../../utils/constants';
import Overview from '../Overview/Overview';
import {Healthcheck} from '../OldHealthcheck';
import {TenantOverview} from '../TenantOverview/TenantOverview';
@@ -32,7 +32,7 @@ function DetailedOverview(props: DetailedOverviewProps) {
const {currentSchemaPath} = useSelector((state: any) => state.schema);
- const [newTenantDiagnostics] = useSetting(ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN);
+ const [displayMetricsCards] = useSetting(DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS);
const openModalHandler = () => {
setIsModalVisible(true);
@@ -59,7 +59,7 @@ function DetailedOverview(props: DetailedOverviewProps) {
};
const renderTenantOverview = () => {
- if (newTenantDiagnostics) {
+ if (displayMetricsCards) {
return (
(
- this.getPath('/viewer/json/healthcheck'),
+ this.getPath('/viewer/json/healthcheck?merge_records=true'),
{tenant: database},
{concurrentId},
);
diff --git a/src/store/reducers/clusterNodes/clusterNodes.tsx b/src/store/reducers/clusterNodes/clusterNodes.tsx
index 15eed0cce..5b81afb08 100644
--- a/src/store/reducers/clusterNodes/clusterNodes.tsx
+++ b/src/store/reducers/clusterNodes/clusterNodes.tsx
@@ -5,7 +5,7 @@ import {createRequestActionTypes, createApiRequest} from '../../utils';
import type {ClusterNodesAction, ClusterNodesState, PreparedClusterNode} from './types';
import '../../../services/api';
-import {calcUptime} from '../../../utils';
+import {calcUptime} from '../../../utils/dataFormatters/dataFormatters';
export const FETCH_CLUSTER_NODES = createRequestActionTypes('cluster', 'FETCH_CLUSTER_NODES');
diff --git a/src/store/reducers/node/selectors.ts b/src/store/reducers/node/selectors.ts
index efc4e486d..3b9b4a61c 100644
--- a/src/store/reducers/node/selectors.ts
+++ b/src/store/reducers/node/selectors.ts
@@ -1,7 +1,7 @@
import type {Selector} from 'reselect';
import {createSelector} from 'reselect';
-import {stringifyVdiskId} from '../../../utils';
+import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
import type {
NodeStateSlice,
diff --git a/src/store/reducers/nodes/selectors.ts b/src/store/reducers/nodes/selectors.ts
index ea9ef03ac..b2f79e56f 100644
--- a/src/store/reducers/nodes/selectors.ts
+++ b/src/store/reducers/nodes/selectors.ts
@@ -1,7 +1,7 @@
import {Selector, createSelector} from 'reselect';
import {EFlag} from '../../../types/api/enums';
-import {calcUptimeInSeconds} from '../../../utils';
+import {calcUptimeInSeconds} from '../../../utils/dataFormatters/dataFormatters';
import {HOUR_IN_SECONDS} from '../../../utils/constants';
import {NodesUptimeFilterValues} from '../../../utils/nodes';
import {prepareSearchValue} from '../../../utils/filters';
diff --git a/src/store/reducers/nodes/types.ts b/src/store/reducers/nodes/types.ts
index a90282243..13e16ee29 100644
--- a/src/store/reducers/nodes/types.ts
+++ b/src/store/reducers/nodes/types.ts
@@ -64,7 +64,7 @@ export interface NodesGeneralRequestParams extends NodesSortParams {
uptime?: number; // return nodes with less uptime in seconds
problems_only?: boolean; // return nodes with SystemState !== EFlag.Green
- offser?: number;
+ offset?: number;
limit?: number;
}
diff --git a/src/store/reducers/nodes/utils.ts b/src/store/reducers/nodes/utils.ts
index 40c89229e..9838fe6a6 100644
--- a/src/store/reducers/nodes/utils.ts
+++ b/src/store/reducers/nodes/utils.ts
@@ -1,6 +1,6 @@
import type {TComputeInfo, TComputeNodeInfo} from '../../../types/api/compute';
import type {TNodesInfo} from '../../../types/api/nodes';
-import {calcUptime} from '../../../utils';
+import {calcUptime} from '../../../utils/dataFormatters/dataFormatters';
import type {NodesHandledResponse, NodesPreparedEntity} from './types';
diff --git a/src/store/reducers/settings/settings.ts b/src/store/reducers/settings/settings.ts
index cb76eb049..56f587263 100644
--- a/src/store/reducers/settings/settings.ts
+++ b/src/store/reducers/settings/settings.ts
@@ -15,7 +15,7 @@ import {
LAST_USED_QUERY_ACTION_KEY,
USE_BACKEND_PARAMS_FOR_TABLES_KEY,
LANGUAGE_KEY,
- ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN,
+ DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS,
} from '../../../utils/constants';
import '../../../services/api';
import {parseJson} from '../../../utils/utils';
@@ -50,14 +50,14 @@ export const initialState = {
[INVERTED_DISKS_KEY]: readSavedSettingsValue(INVERTED_DISKS_KEY, 'false'),
[USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY]: readSavedSettingsValue(
USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
- 'false',
+ 'true',
),
[ENABLE_ADDITIONAL_QUERY_MODES]: readSavedSettingsValue(
ENABLE_ADDITIONAL_QUERY_MODES,
'false',
),
- [ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN]: readSavedSettingsValue(
- ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN,
+ [DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS]: readSavedSettingsValue(
+ DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS,
'false',
),
[SAVED_QUERIES_KEY]: readSavedSettingsValue(SAVED_QUERIES_KEY, '[]'),
diff --git a/src/store/reducers/storage/types.ts b/src/store/reducers/storage/types.ts
index 7693b6432..fbf3f3f9f 100644
--- a/src/store/reducers/storage/types.ts
+++ b/src/store/reducers/storage/types.ts
@@ -63,7 +63,7 @@ export interface StorageSortParams {
export interface StorageSortAndFilterParams extends StorageSortParams {
filter?: string; // PoolName or GroupId
- offser?: number;
+ offset?: number;
limit?: number;
}
diff --git a/src/store/reducers/storage/utils.ts b/src/store/reducers/storage/utils.ts
index 4dce0b429..620c752fc 100644
--- a/src/store/reducers/storage/utils.ts
+++ b/src/store/reducers/storage/utils.ts
@@ -9,7 +9,7 @@ import {TPDiskState} from '../../../types/api/pdisk';
import {EFlag} from '../../../types/api/enums';
import {getPDiskType} from '../../../utils/pdisk';
import {getUsage} from '../../../utils/storage';
-import {calcUptime} from '../../../utils';
+import {calcUptime} from '../../../utils/dataFormatters/dataFormatters';
import type {PreparedStorageGroup, PreparedStorageNode, PreparedStorageResponse} from './types';
diff --git a/src/store/reducers/tenants/utils.ts b/src/store/reducers/tenants/utils.ts
index 9d6fc9930..68532fe08 100644
--- a/src/store/reducers/tenants/utils.ts
+++ b/src/store/reducers/tenants/utils.ts
@@ -1,6 +1,6 @@
import type {TTenant} from '../../../types/api/tenant';
import {formatBytes} from '../../../utils/bytesParsers';
-import {formatCPU} from '../../../utils/formatCPU/formatCPU';
+import {formatCPUWithLabel} from '../../../utils/dataFormatters/dataFormatters';
import {isNumeric} from '../../../utils/utils';
import {METRIC_STATUS} from './contants';
@@ -158,7 +158,7 @@ export const formatTenantMetrics = ({
storage?: number;
memory?: number;
}) => ({
- cpu: formatCPU(cpu),
+ cpu: formatCPUWithLabel(cpu),
storage: formatBytes({value: storage, significantDigits: 2}) || undefined,
memory: formatBytes({value: memory, significantDigits: 2}) || undefined,
});
diff --git a/src/types/api/vdisk.ts b/src/types/api/vdisk.ts
index 5344f6be3..516ea2280 100644
--- a/src/types/api/vdisk.ts
+++ b/src/types/api/vdisk.ts
@@ -99,7 +99,7 @@ interface TVDiskSatisfactionRank {
LevelRank?: TRank;
}
-interface TVDiskID {
+export interface TVDiskID {
GroupID?: number;
GroupGeneration?: number;
Ring?: number;
diff --git a/src/utils/bytesParsers/formatBytes.ts b/src/utils/bytesParsers/formatBytes.ts
index 92f3f22e3..c3d74eceb 100644
--- a/src/utils/bytesParsers/formatBytes.ts
+++ b/src/utils/bytesParsers/formatBytes.ts
@@ -1,4 +1,4 @@
-import {formatNumber} from '..';
+import {formatNumber} from '../dataFormatters/dataFormatters';
import {GIGABYTE, KILOBYTE, MEGABYTE, TERABYTE} from '../constants';
import {isNumeric} from '../utils';
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index f5d4a6043..58686bd81 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -88,7 +88,8 @@ export const LANGUAGE_KEY = 'language';
export const INVERTED_DISKS_KEY = 'invertedDisks';
export const USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY = 'useNodesEndpointInDiagnostics';
export const ENABLE_ADDITIONAL_QUERY_MODES = 'enableAdditionalQueryModes';
-export const ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN = 'enableNewTenantDiagnosticsDesign';
+// Remain key name "enableNewTenantDiagnosticsDesign" for backward compatibility
+export const DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS = 'enableNewTenantDiagnosticsDesign';
export const SAVED_QUERIES_KEY = 'saved_queries';
export const ASIDE_HEADER_COMPACT_KEY = 'asideHeaderCompact';
export const QUERIES_HISTORY_KEY = 'queries_history';
diff --git a/src/utils/dataFormatters/dataFormatters.ts b/src/utils/dataFormatters/dataFormatters.ts
new file mode 100644
index 000000000..b51f797b7
--- /dev/null
+++ b/src/utils/dataFormatters/dataFormatters.ts
@@ -0,0 +1,128 @@
+import {dateTimeParse} from '@gravity-ui/date-utils';
+
+import type {TVDiskID, TVSlotId} from '../../types/api/vdisk';
+import {DAY_IN_SECONDS, GIGABYTE, TERABYTE} from '../constants';
+import {configuredNumeral} from '../numeral';
+import {isNumeric} from '../utils';
+
+import i18n from './i18n';
+
+// Here you can't control displayed size and precision
+// If you need more custom format, use formatBytesCustom instead
+export const formatBytes = (bytes?: string | number) => {
+ if (!isNumeric(bytes)) {
+ return '';
+ }
+
+ // by agreement, display byte values in decimal scale
+ return configuredNumeral(bytes).format('0 b');
+};
+
+export const formatBps = (bytes?: string | number) => {
+ const formattedBytes = formatBytes(bytes);
+
+ if (!formattedBytes) {
+ return '';
+ }
+
+ return formattedBytes + '/s';
+};
+
+export const formatBytesToGigabyte = (bytes: number | string) => {
+ return `${Math.floor(Number(bytes) / GIGABYTE)} GB`;
+};
+
+export const stringifyVdiskId = (id?: TVDiskID | TVSlotId) => {
+ return id ? Object.values(id).join('-') : '';
+};
+
+export const getPDiskId = (info: {NodeId?: number; PDiskId?: number}) => {
+ return info.NodeId && info.PDiskId ? `${info.NodeId}-${info.PDiskId}` : undefined;
+};
+
+export const formatUptime = (seconds: number) => {
+ const days = Math.floor(seconds / DAY_IN_SECONDS);
+ const remain = seconds % DAY_IN_SECONDS;
+
+ const uptime = [days && `${days}d`, configuredNumeral(remain).format('00:00:00')]
+ .filter(Boolean)
+ .join(' ');
+
+ return uptime;
+};
+
+export const formatMsToUptime = (ms?: number) => {
+ return ms && formatUptime(ms / 1000);
+};
+
+export const formatStorageValues = (value?: number, total?: number) => {
+ return [
+ value ? String(Math.floor(value / TERABYTE)) : undefined,
+ total ? `${Math.floor(total / TERABYTE)} TB` : undefined,
+ ];
+};
+export const formatStorageValuesToGb = (value?: number, total?: number): (string | undefined)[] => {
+ return [
+ value ? String(Math.floor(value / 1000000000)) : undefined,
+ total ? `${Math.floor(total / 1000000000)} GB` : undefined,
+ ];
+};
+
+export const formatNumber = (number?: unknown) => {
+ if (!isNumeric(number)) {
+ return '';
+ }
+
+ return configuredNumeral(number).format();
+};
+
+const normalizeCPU = (value: number | string) => {
+ const rawCores = Number(value) / 1000000;
+ let cores = rawCores.toPrecision(3);
+ if (rawCores >= 1000) {
+ cores = rawCores.toFixed();
+ }
+ if (rawCores < 0.001) {
+ cores = '0';
+ }
+
+ return Number(cores);
+};
+
+export const formatCPU = (value?: number | string) => {
+ if (value === undefined) {
+ return undefined;
+ }
+
+ return configuredNumeral(normalizeCPU(value)).format('0.[000]');
+};
+
+export const formatCPUWithLabel = (value?: number) => {
+ if (value === undefined) {
+ return undefined;
+ }
+ const cores = normalizeCPU(value);
+ const localizedCores = configuredNumeral(cores).format('0.[000]');
+
+ return `${localizedCores} ${i18n('format-cpu.cores', {count: cores})}`;
+};
+
+export const formatDateTime = (value?: number | string) => {
+ if (!isNumeric(value)) {
+ return '';
+ }
+
+ const formattedData = dateTimeParse(Number(value))?.format('YYYY-MM-DD HH:mm');
+
+ return Number(value) > 0 && formattedData ? formattedData : 'N/A';
+};
+
+export const calcUptimeInSeconds = (milliseconds: number | string) => {
+ const currentDate = new Date();
+ const diff = currentDate.getTime() - Number(milliseconds);
+ return diff <= 0 ? 0 : diff / 1000;
+};
+
+export const calcUptime = (milliseconds?: number | string) => {
+ return formatUptime(calcUptimeInSeconds(Number(milliseconds)));
+};
diff --git a/src/utils/dataFormatters/i18n/en.json b/src/utils/dataFormatters/i18n/en.json
new file mode 100644
index 000000000..fffa73d78
--- /dev/null
+++ b/src/utils/dataFormatters/i18n/en.json
@@ -0,0 +1,3 @@
+{
+ "format-cpu.cores": ["core", "cores", "cores", "cores"]
+}
diff --git a/src/utils/formatCPU/i18n/index.ts b/src/utils/dataFormatters/i18n/index.ts
similarity index 100%
rename from src/utils/formatCPU/i18n/index.ts
rename to src/utils/dataFormatters/i18n/index.ts
diff --git a/src/utils/dataFormatters/i18n/ru.json b/src/utils/dataFormatters/i18n/ru.json
new file mode 100644
index 000000000..d0e8aa33a
--- /dev/null
+++ b/src/utils/dataFormatters/i18n/ru.json
@@ -0,0 +1,3 @@
+{
+ "format-cpu.cores": ["ядро", "ядра", "ядер", "ядер"]
+}
diff --git a/src/utils/formatCPU/formatCPU.ts b/src/utils/formatCPU/formatCPU.ts
deleted file mode 100644
index da6250066..000000000
--- a/src/utils/formatCPU/formatCPU.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import {configuredNumeral} from '../numeral';
-import i18n from './i18n';
-
-export const formatCPU = (value?: number) => {
- if (value === undefined) {
- return undefined;
- }
-
- const rawCores = value / 1000000;
- let cores = rawCores.toPrecision(3);
- if (rawCores >= 1000) {
- cores = rawCores.toFixed();
- }
- if (rawCores < 0.001) {
- cores = '0';
- }
- const localizedCores = configuredNumeral(Number(cores)).format('0.[000]');
-
- return `${localizedCores} ${i18n('cores', {count: cores})}`;
-};
diff --git a/src/utils/formatCPU/i18n/en.json b/src/utils/formatCPU/i18n/en.json
deleted file mode 100644
index c6e60e464..000000000
--- a/src/utils/formatCPU/i18n/en.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "cores": ["core", "cores", "cores", "cores"]
-}
diff --git a/src/utils/formatCPU/i18n/ru.json b/src/utils/formatCPU/i18n/ru.json
deleted file mode 100644
index 7f5cb0d75..000000000
--- a/src/utils/formatCPU/i18n/ru.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "cores": ["ядро", "ядра", "ядер", "ядер"]
-}
diff --git a/src/utils/index.js b/src/utils/index.js
index 6bde6c2de..2ec28dc49 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -1,105 +1,3 @@
-import {dateTimeParse} from '@gravity-ui/date-utils';
-
-import {MEGABYTE, TERABYTE, GIGABYTE, DAY_IN_SECONDS} from './constants';
-import {isNumeric} from './utils';
-import {configuredNumeral} from './numeral';
-
-// Here you can't control displayed size and precision
-// If you need more custom format, use formatBytesCustom instead
-export const formatBytes = (bytes) => {
- if (!isNumeric(bytes)) {
- return '';
- }
-
- // by agreement, display byte values in decimal scale
- return configuredNumeral(bytes).format('0 b');
-};
-
-export const formatBps = (bytes) => {
- const formattedBytes = formatBytes(bytes);
-
- if (!formattedBytes) {
- return '';
- }
-
- return formattedBytes + '/s';
-};
-
-export const formatBytesToGigabyte = (bytes) => {
- return `${Math.floor(bytes / GIGABYTE)} GB`;
-};
-
-export const stringifyVdiskId = (id) => {
- return Object.values(id).join('-');
-};
-export const getPDiskId = (info) => {
- return `${info.NodeId}-${info.PDiskId}`;
-};
-
-export const formatUptime = (seconds) => {
- const days = Math.floor(seconds / DAY_IN_SECONDS);
- const remain = seconds % DAY_IN_SECONDS;
-
- const uptime = [days && `${days}d`, configuredNumeral(remain).format('00:00:00')]
- .filter(Boolean)
- .join(' ');
-
- return uptime;
-};
-
-export const formatMsToUptime = (ms) => {
- return formatUptime(ms / 1000);
-};
-
-export const formatIOPS = (value, capacity) => {
- return [Math.floor(value), Math.floor(capacity) + ' IOPS'];
-};
-
-export const formatStorageValues = (value, total) => {
- return [Math.floor(value / TERABYTE), `${Math.floor(total / TERABYTE)} TB`];
-};
-export const formatStorageValuesToGb = (value, total) => {
- return [Math.floor(value / 1000000000), `${Math.floor(total / 1000000000)} GB`];
-};
-
-export const formatThroughput = (value, total) => {
- return [(value / MEGABYTE).toFixed(2), (total / MEGABYTE).toFixed(1) + ' MB/s'];
-};
-
-export const formatNumber = (number) => {
- if (!isNumeric(number)) {
- return '';
- }
-
- return configuredNumeral(number).format();
-};
-
-export const formatCPU = (value) => {
- if (!isNumeric(value)) {
- return '';
- }
-
- return configuredNumeral(value / 1000000).format('0.00');
-};
-
-export const formatDateTime = (value) => {
- if (!isNumeric(value)) {
- return '';
- }
-
- return value > 0 ? dateTimeParse(Number(value)).format('YYYY-MM-DD HH:mm') : 'N/A';
-};
-
-export const calcUptimeInSeconds = (milliseconds) => {
- const currentDate = new Date();
- const diff = currentDate - Number(milliseconds);
- return diff <= 0 ? 0 : diff / 1000;
-};
-
-export const calcUptime = (milliseconds) => {
- return formatUptime(calcUptimeInSeconds(milliseconds));
-};
-
// determine how many nodes have status Connected "true"
export const getConnectedNodesCount = (nodeStateInfo) => {
return nodeStateInfo?.reduce((acc, item) => (item.Connected ? acc + 1 : acc), 0);