diff --git a/src/components/UsageLabel/UsageLabel.scss b/src/components/UsageLabel/UsageLabel.scss
new file mode 100644
index 000000000..e93b0d435
--- /dev/null
+++ b/src/components/UsageLabel/UsageLabel.scss
@@ -0,0 +1,6 @@
+.ydb-usage-label {
+ &_overload {
+ color: var(--yc-color-text-light-primary);
+ background-color: var(--yc-color-base-danger-heavy);
+ }
+}
diff --git a/src/components/UsageLabel/UsageLabel.tsx b/src/components/UsageLabel/UsageLabel.tsx
new file mode 100644
index 000000000..3a20e2df6
--- /dev/null
+++ b/src/components/UsageLabel/UsageLabel.tsx
@@ -0,0 +1,18 @@
+import cn from 'bem-cn-lite';
+
+import {Label, type LabelProps} from '@gravity-ui/uikit';
+
+const b = cn('ydb-usage-label');
+
+interface UsageLabelProps extends LabelProps {
+ value: number | string;
+ overloadThreshold?: number;
+}
+
+export function UsageLabel({value, overloadThreshold = 90, theme}: UsageLabelProps) {
+ return (
+
+ );
+}
diff --git a/src/containers/Nodes/Nodes.scss b/src/containers/Nodes/Nodes.scss
index 466375efa..74aacb99f 100644
--- a/src/containers/Nodes/Nodes.scss
+++ b/src/containers/Nodes/Nodes.scss
@@ -20,11 +20,4 @@
&__node_unavailable {
opacity: 0.6;
}
-
- &__usage-label {
- &_overload {
- color: var(--yc-color-text-light-primary);
- background-color: var(--yc-color-base-danger-heavy);
- }
- }
}
diff --git a/src/containers/Nodes/getNodesColumns.tsx b/src/containers/Nodes/getNodesColumns.tsx
index a3ce434ec..df8583057 100644
--- a/src/containers/Nodes/getNodesColumns.tsx
+++ b/src/containers/Nodes/getNodesColumns.tsx
@@ -1,7 +1,5 @@
-import cn from 'bem-cn-lite';
-
import DataTable, {type Column} from '@gravity-ui/react-data-table';
-import {Label, Popover} from '@gravity-ui/uikit';
+import {Popover} from '@gravity-ui/uikit';
import {PoolsGraph} from '../../components/PoolsGraph/PoolsGraph';
import {ProgressViewer} from '../../components/ProgressViewer/ProgressViewer';
@@ -9,10 +7,9 @@ import {TabletsStatistic} from '../../components/TabletsStatistic';
import {NodeHostWrapper} from '../../components/NodeHostWrapper/NodeHostWrapper';
import {formatBytesToGigabyte} from '../../utils/dataFormatters/dataFormatters';
import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
-import type {NodeAddress} from '../../types/additionalProps';
+import type {GetNodeRefFunc} from '../../types/additionalProps';
import {getLoadSeverityForNode} from '../../store/reducers/tenantOverview/topNodesByLoad/utils';
-
-const b = cn('node');
+import {UsageLabel} from '../../components/UsageLabel/UsageLabel';
const NODES_COLUMNS_IDS = {
NodeId: 'NodeId',
@@ -25,11 +22,12 @@ const NODES_COLUMNS_IDS = {
CPU: 'CPU',
LoadAverage: 'LoadAverage',
Tablets: 'Tablets',
+ TopNodesLoadAverage: 'TopNodesLoadAverage',
};
interface GetNodesColumnsProps {
tabletsPath?: string;
- getNodeRef?: (node?: NodeAddress) => string | null;
+ getNodeRef?: GetNodeRefFunc;
}
const nodeIdColumn: Column = {
@@ -41,7 +39,7 @@ const nodeIdColumn: Column = {
};
const getHostColumn = (
- getNodeRef?: (node?: NodeAddress) => string | null,
+ getNodeRef?: GetNodeRefFunc,
fixedWidth = false,
): Column => ({
name: NODES_COLUMNS_IDS.Host,
@@ -154,21 +152,14 @@ const getTabletsColumn = (tabletsPath?: string): Column =>
});
const topNodesLoadAverageColumn: Column = {
- name: NODES_COLUMNS_IDS.LoadAverage,
+ name: NODES_COLUMNS_IDS.TopNodesLoadAverage,
header: 'Load',
- sortAccessor: ({LoadAverage = []}) =>
- LoadAverage.slice(0, 1).reduce((acc, item) => acc + item, 0),
- defaultOrder: DataTable.DESCENDING,
render: ({row}) =>
row.LoadAverage && row.LoadAverage.length > 0 ? (
- <>
-
- >
+
) : (
'—'
),
@@ -195,14 +186,14 @@ export function getNodesColumns({
];
}
-export function getTopNodesColumns(
- getNodeRef?: (node?: NodeAddress) => string | null,
+export function getTopNodesByLoadColumns(
+ getNodeRef?: GetNodeRefFunc,
): Column[] {
return [topNodesLoadAverageColumn, nodeIdColumn, getHostColumn(getNodeRef), versionColumn];
}
-export function getTopPoolsColumns(
- getNodeRef?: (node?: NodeAddress) => string | null,
+export function getTopNodesByCpuColumns(
+ getNodeRef?: GetNodeRefFunc,
): Column[] {
return [cpuColumn, nodeIdColumn, getHostColumn(getNodeRef)];
}
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.scss b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.scss
deleted file mode 100644
index 66903d7ce..000000000
--- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.scss
+++ /dev/null
@@ -1,31 +0,0 @@
-@import '../../../../../styles/mixins.scss';
-
-.tenant-overview-cpu {
- &__title {
- margin-bottom: 10px;
-
- font-size: var(--yc-text-body-2-font-size);
- font-weight: 700;
- line-height: var(--yc-text-body-2-line-height);
- }
-
- &__table {
- width: var(--diagnostics-section-table-width);
-
- @include table-styles();
-
- &:not(:last-child) {
- margin-bottom: var(--diagnostics-section-margin);
- }
-
- th {
- height: 40px;
-
- vertical-align: middle;
- }
-
- &_top-queries tr {
- cursor: pointer;
- }
- }
-}
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx
index ff91aeb8d..bf4df1d27 100644
--- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx
+++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx
@@ -1,7 +1,4 @@
-import {useSelector} from 'react-redux';
-
import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
-import type {EPathType, TEvDescribeSchemeResult} from '../../../../../types/api/schema';
import {TopNodesByLoad} from './TopNodesByLoad';
import {TopNodesByCpu} from './TopNodesByCpu';
import {TopShards} from './TopShards';
@@ -13,21 +10,10 @@ interface TenantCpuProps {
}
export function TenantCpu({path, additionalNodesProps}: TenantCpuProps) {
- const {currentSchemaPath, currentSchema: currentItem = {}} = useSelector(
- (state: any) => state.schema,
- );
- const {PathType: preloadedPathType} = useSelector(
- (state: any) => state.schema.data[currentSchemaPath]?.PathDescription?.Self || {},
- );
- const {PathType: currentPathType} =
- (currentItem as TEvDescribeSchemeResult).PathDescription?.Self || {};
-
- const type: EPathType | undefined = preloadedPathType || currentPathType;
-
return (
<>
-
-
+
+
>
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx
index 90c90f26b..c91ce7503 100644
--- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx
+++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx
@@ -1,45 +1,30 @@
-import cn from 'bem-cn-lite';
import {useDispatch} from 'react-redux';
import {useCallback} from 'react';
-import DataTable from '@gravity-ui/react-data-table';
-
-import {
- TENANT_OVERVIEW_TABLES_LIMIT,
- TENANT_OVERVIEW_TABLES_SETTINGS,
-} from '../../../../../utils/constants';
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
import {
- getTopComputeNodesByCpu,
getTopNodesByCpu,
selectTopNodesByCpu,
setDataWasNotLoaded,
} from '../../../../../store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu';
-import type {EPathType} from '../../../../../types/api/schema';
import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
-import {TableSkeleton} from '../../../../../components/TableSkeleton/TableSkeleton';
-import {ResponseError} from '../../../../../components/Errors/ResponseError';
-import {getTopPoolsColumns} from '../../../../Nodes/getNodesColumns';
-import {isDatabaseEntityType} from '../../../utils/schema';
+import {getTopNodesByCpuColumns} from '../../../../Nodes/getNodesColumns';
+import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
import i18n from '../i18n';
-import './TenantCpu.scss';
-
-const b = cn('tenant-overview-cpu');
interface TopNodesByCpuProps {
- path?: string;
- type?: EPathType;
+ path: string;
additionalNodesProps?: AdditionalNodesProps;
}
-export function TopNodesByCpu({path, type, additionalNodesProps}: TopNodesByCpuProps) {
+export function TopNodesByCpu({path, additionalNodesProps}: TopNodesByCpuProps) {
const dispatch = useDispatch();
const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByCpu);
const {autorefresh} = useTypedSelector((state) => state.schema);
const topNodes = useTypedSelector(selectTopNodesByCpu);
- const columns = getTopPoolsColumns(additionalNodesProps?.getNodeRef);
+ const columns = getTopNodesByCpuColumns(additionalNodesProps?.getNodeRef);
const fetchNodes = useCallback(
(isBackground) => {
@@ -47,43 +32,22 @@ export function TopNodesByCpu({path, type, additionalNodesProps}: TopNodesByCpuP
dispatch(setDataWasNotLoaded());
}
- // For not DB entities we always use /compute endpoint instead of /nodes
- // since /nodes can return data only for tenants
- if (path && !isDatabaseEntityType(type)) {
- dispatch(getTopComputeNodesByCpu({path}));
- } else {
- dispatch(getTopNodesByCpu({tenant: path}));
- }
+ dispatch(getTopNodesByCpu({tenant: path}));
},
- [dispatch, path, type],
+ [dispatch, path],
);
useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
- const renderContent = () => {
- if (error) {
- return ;
- }
-
- if (loading && !wasLoaded) {
- return ;
- }
-
- return (
-
- );
- };
-
return (
- <>
- Top nodes by pools usage
- {renderContent()}
- >
+
);
}
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx
index 257e756fd..2870f4bb2 100644
--- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx
+++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx
@@ -1,45 +1,30 @@
-import cn from 'bem-cn-lite';
import {useDispatch} from 'react-redux';
import {useCallback} from 'react';
-import DataTable from '@gravity-ui/react-data-table';
-
-import {
- TENANT_OVERVIEW_TABLES_LIMIT,
- TENANT_OVERVIEW_TABLES_SETTINGS,
-} from '../../../../../utils/constants';
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
import {
- getTopComputeNodesByLoad,
getTopNodesByLoad,
selectTopNodesByLoad,
setDataWasNotLoaded,
} from '../../../../../store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad';
-import type {EPathType} from '../../../../../types/api/schema';
import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
-import {TableSkeleton} from '../../../../../components/TableSkeleton/TableSkeleton';
-import {ResponseError} from '../../../../../components/Errors/ResponseError';
-import {getTopNodesColumns} from '../../../../Nodes/getNodesColumns';
-import {isDatabaseEntityType} from '../../../utils/schema';
+import {getTopNodesByLoadColumns} from '../../../../Nodes/getNodesColumns';
+import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
import i18n from '../i18n';
-import './TenantCpu.scss';
-
-const b = cn('tenant-overview-cpu');
interface TopNodesByLoadProps {
- path?: string;
- type?: EPathType;
+ path: string;
additionalNodesProps?: AdditionalNodesProps;
}
-export function TopNodesByLoad({path, type, additionalNodesProps}: TopNodesByLoadProps) {
+export function TopNodesByLoad({path, additionalNodesProps}: TopNodesByLoadProps) {
const dispatch = useDispatch();
const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByLoad);
const {autorefresh} = useTypedSelector((state) => state.schema);
const topNodes = useTypedSelector(selectTopNodesByLoad);
- const columns = getTopNodesColumns(additionalNodesProps?.getNodeRef);
+ const columns = getTopNodesByLoadColumns(additionalNodesProps?.getNodeRef);
const fetchNodes = useCallback(
(isBackground) => {
@@ -47,43 +32,22 @@ export function TopNodesByLoad({path, type, additionalNodesProps}: TopNodesByLoa
dispatch(setDataWasNotLoaded());
}
- // For not DB entities we always use /compute endpoint instead of /nodes
- // since /nodes can return data only for tenants
- if (path && !isDatabaseEntityType(type)) {
- dispatch(getTopComputeNodesByLoad({path}));
- } else {
- dispatch(getTopNodesByLoad({tenant: path}));
- }
+ dispatch(getTopNodesByLoad({tenant: path}));
},
- [dispatch, path, type],
+ [dispatch, path],
);
useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
- const renderContent = () => {
- if (error) {
- return ;
- }
-
- if (loading && !wasLoaded) {
- return ;
- }
-
- return (
-
- );
- };
-
return (
- <>
- Top nodes by load
- {renderContent()}
- >
+
);
}
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx
index b16e42be9..254bc697c 100644
--- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx
+++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx
@@ -1,37 +1,25 @@
-import cn from 'bem-cn-lite';
import qs from 'qs';
import {useDispatch} from 'react-redux';
import {useHistory, useLocation} from 'react-router';
import {useCallback} from 'react';
-import DataTable from '@gravity-ui/react-data-table';
-
-import {
- TENANT_OVERVIEW_TABLES_LIMIT,
- TENANT_OVERVIEW_TABLES_SETTINGS,
-} from '../../../../../utils/constants';
import {
TENANT_PAGE,
TENANT_PAGES_IDS,
TENANT_QUERY_TABS_ID,
} from '../../../../../store/reducers/tenant/constants';
import {
- fetchTopQueries,
+ fetchTenantOverviewTopQueries,
setDataWasNotLoaded,
-} from '../../../../../store/reducers/tenantOverview/executeTopQueries/executeTopQueries';
+} from '../../../../../store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries';
import {changeUserInput} from '../../../../../store/reducers/executeQuery';
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
-import {ResponseError} from '../../../../../components/Errors/ResponseError';
-import {TableSkeleton} from '../../../../../components/TableSkeleton/TableSkeleton';
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
import {getTenantOverviewTopQueriesColumns} from '../../TopQueries/getTopQueriesColumns';
-
-import './TenantCpu.scss';
-
-const b = cn('tenant-overview-cpu');
+import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
interface TopQueriesProps {
- path?: string;
+ path: string;
}
export function TopQueries({path}: TopQueriesProps) {
@@ -46,7 +34,7 @@ export function TopQueries({path}: TopQueriesProps) {
wasLoaded,
error,
data: {result: data = undefined} = {},
- } = useTypedSelector((state) => state.tenantOverviewExecuteTopQueries);
+ } = useTypedSelector((state) => state.tenantOverviewTopQueries);
const columns = getTenantOverviewTopQueriesColumns();
useAutofetcher(
@@ -55,9 +43,7 @@ export function TopQueries({path}: TopQueriesProps) {
dispatch(setDataWasNotLoaded());
}
- // @ts-expect-error
- // typed dispatch required, remove error expectation after adding it
- dispatch(fetchTopQueries(path));
+ dispatch(fetchTenantOverviewTopQueries(path));
},
[dispatch, path],
autorefresh,
@@ -84,30 +70,16 @@ export function TopQueries({path}: TopQueriesProps) {
[dispatch, history, location],
);
- const renderContent = () => {
- if (error) {
- return ;
- }
-
- if (loading && !wasLoaded) {
- return ;
- }
-
- return (
-
- );
- };
-
return (
- <>
- Top queries by cpu time
- {renderContent()}
- >
+
);
}
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx
index b5d1bb61c..bf01c4bdf 100644
--- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx
+++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx
@@ -1,25 +1,16 @@
-import {useMemo} from 'react';
import {useDispatch} from 'react-redux';
-import cn from 'bem-cn-lite';
-import DataTable, {type Column} from '@gravity-ui/react-data-table';
+import {type Column} from '@gravity-ui/react-data-table';
-import {
- TENANT_OVERVIEW_TABLES_LIMIT,
- TENANT_OVERVIEW_TABLES_SETTINGS,
-} from '../../../../../utils/constants';
import {getSchema, setCurrentSchemaPath} from '../../../../../store/reducers/schema/schema';
import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
import type {KeyValueRow} from '../../../../../types/api/query';
import {
- sendTopShardsQuery,
+ sendTenantOverviewTopShardsQuery,
setDataWasNotLoaded,
-} from '../../../../../store/reducers/tenantOverview/executeTopShards/executeTopShards';
-import {ResponseError} from '../../../../../components/Errors/ResponseError';
-import {TableSkeleton} from '../../../../../components/TableSkeleton/TableSkeleton';
+} from '../../../../../store/reducers/tenantOverview/topShards/tenantOverviewTopShards';
import {getTopShardsColumns} from '../../TopShards/getTopShardsColumns';
-
-const b = cn('tenant-overview-cpu');
+import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
interface TopShardsProps {
path: string;
@@ -35,56 +26,38 @@ export const TopShards = ({path}: TopShardsProps) => {
data: {result: data = undefined} = {},
error,
wasLoaded,
- } = useTypedSelector((state) => state.executeTopShards);
+ } = useTypedSelector((state) => state.tenantOverviewTopShards);
useAutofetcher(
(isBackground) => {
if (!isBackground) {
dispatch(setDataWasNotLoaded());
}
- dispatch(sendTopShardsQuery(path, currentSchemaPath));
+ dispatch(sendTenantOverviewTopShardsQuery(path, currentSchemaPath));
},
[dispatch, path, currentSchemaPath],
autorefresh,
);
- const columns = useMemo(() => {
- const onSchemaClick = (schemaPath: string) => {
- return () => {
- dispatch(setCurrentSchemaPath(schemaPath));
- dispatch(getSchema({path: schemaPath}));
- history.go(0);
- };
+ const onSchemaClick = (schemaPath: string) => {
+ return () => {
+ dispatch(setCurrentSchemaPath(schemaPath));
+ dispatch(getSchema({path: schemaPath}));
+ history.go(0);
};
-
- const tableColumns: Column[] = getTopShardsColumns(onSchemaClick, path);
-
- return tableColumns;
- }, [dispatch, path]);
-
- const renderContent = () => {
- if (error) {
- return ;
- }
-
- if (loading && !wasLoaded) {
- return ;
- }
-
- return (
-
- );
};
+ const columns: Column[] = getTopShardsColumns(onSchemaClick, path);
+
return (
- <>
- Top shards by cpu usage
- {renderContent()}
- >
+
);
};
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss
index 1290d7ee7..9f1b8f1fb 100644
--- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss
+++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss
@@ -1,3 +1,5 @@
+@import '../../../../styles/mixins.scss';
+
.tenant-overview {
padding-bottom: 20px;
@@ -78,4 +80,32 @@
font-weight: 600;
line-height: var(--yc-text-body-2-line-height);
}
+
+ &__title {
+ margin-bottom: 10px;
+
+ font-size: var(--yc-text-body-2-font-size);
+ font-weight: 700;
+ line-height: var(--yc-text-body-2-line-height);
+ }
+
+ &__table {
+ width: var(--diagnostics-section-table-width);
+
+ @include table-styles();
+
+ &:not(:last-child) {
+ margin-bottom: var(--diagnostics-section-margin);
+ }
+
+ th {
+ height: 40px;
+
+ vertical-align: middle;
+ }
+
+ &_top-queries tr {
+ cursor: pointer;
+ }
+ }
}
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx
new file mode 100644
index 000000000..3c03f0a80
--- /dev/null
+++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx
@@ -0,0 +1,62 @@
+import cn from 'bem-cn-lite';
+
+import DataTable from '@gravity-ui/react-data-table';
+import type {DataTableProps, THEMES} from '@gravity-ui/react-data-table';
+
+import {
+ TENANT_OVERVIEW_TABLES_LIMIT,
+ TENANT_OVERVIEW_TABLES_SETTINGS,
+} from '../../../../utils/constants';
+import type {IResponseError} from '../../../../types/api/error';
+import {TableSkeleton} from '../../../../components/TableSkeleton/TableSkeleton';
+import {ResponseError} from '../../../../components/Errors/ResponseError';
+
+const b = cn('tenant-overview');
+
+interface TenantOverviewTableLayoutProps extends Omit, 'theme'> {
+ theme?: THEMES | string;
+ title: string;
+ loading?: boolean;
+ wasLoaded?: boolean;
+ error?: IResponseError;
+ tableClassNameModifiers?: {
+ [name: string]: string | boolean | undefined;
+ };
+}
+
+export function TenantOverviewTableLayout({
+ title,
+ data,
+ columns,
+ error,
+ loading,
+ wasLoaded,
+ emptyDataMessage,
+ tableClassNameModifiers = {},
+}: TenantOverviewTableLayoutProps) {
+ const renderContent = () => {
+ if (error) {
+ return ;
+ }
+
+ if (loading && !wasLoaded) {
+ return ;
+ }
+
+ return (
+
+ );
+ };
+ return (
+ <>
+ {title}
+ {renderContent()}
+ >
+ );
+}
diff --git a/src/containers/Tenant/Diagnostics/TopShards/TopShards.scss b/src/containers/Tenant/Diagnostics/TopShards/TopShards.scss
index 4f794d380..c4b433620 100644
--- a/src/containers/Tenant/Diagnostics/TopShards/TopShards.scss
+++ b/src/containers/Tenant/Diagnostics/TopShards/TopShards.scss
@@ -16,11 +16,4 @@
overflow: auto;
flex-grow: 1;
}
-
- &__usage-label {
- &_overload {
- color: var(--yc-color-text-light-primary);
- background-color: var(--yc-color-base-danger-heavy);
- }
- }
}
diff --git a/src/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx b/src/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx
index d9d54c287..c1e5cc80f 100644
--- a/src/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx
+++ b/src/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx
@@ -1,20 +1,19 @@
import cn from 'bem-cn-lite';
import DataTable, {type Column} from '@gravity-ui/react-data-table';
-import {Label} from '@gravity-ui/uikit';
import type {KeyValueRow} from '../../../../types/api/query';
import type {ValueOf} from '../../../../types/common';
import {formatNumber, roundToPrecision} from '../../../../utils/dataFormatters/dataFormatters';
-import {getLoadSeverityForShard} from '../../../../store/reducers/tenantOverview/executeTopShards/utils';
+import {getLoadSeverityForShard} from '../../../../store/reducers/tenantOverview/topShards/utils';
import {InternalLink} from '../../../../components/InternalLink';
import routes, {createHref} from '../../../../routes';
import {getDefaultNodePath} from '../../../Node/NodePages';
+import {UsageLabel} from '../../../../components/UsageLabel/UsageLabel';
import './TopShards.scss';
-const b = cn('top-shards');
-const bLink = cn('yc-link');
+const b = cn('yc-link');
const TOP_SHARDS_COLUMNS_IDS = {
TabletId: 'TabletId',
@@ -53,10 +52,7 @@ const getPathColumn = (
render: ({row}) => {
// row.Path - relative schema path
return (
-
+
{row.Path}
);
@@ -115,14 +111,10 @@ const topShardsCpuCoresColumn: Column = {
header: tableColumnsNames[TOP_SHARDS_COLUMNS_IDS.CPUCores],
render: ({row}) => {
return (
- <>
-
- >
+
);
},
align: DataTable.RIGHT,
diff --git a/src/store/reducers/index.ts b/src/store/reducers/index.ts
index 41bb568a6..131135630 100644
--- a/src/store/reducers/index.ts
+++ b/src/store/reducers/index.ts
@@ -1,8 +1,8 @@
import {combineReducers} from 'redux';
import nodes from './nodes/nodes';
-import topNodesByLoad from './tenantOverview/topNodesByLoad/topNodesByLoad';
-import topNodesByCpu from './tenantOverview/topNodesByCpu/topNodesByCpu';
+import {topNodesByLoad} from './tenantOverview/topNodesByLoad/topNodesByLoad';
+import {topNodesByCpu} from './tenantOverview/topNodesByCpu/topNodesByCpu';
import cluster from './cluster/cluster';
import clusterNodes from './clusterNodes/clusterNodes';
import tenant from './tenant/tenant';
@@ -29,11 +29,11 @@ import nodesList from './nodesList';
import describe from './describe';
import schemaAcl from './schemaAcl/schemaAcl';
import executeTopQueries from './executeTopQueries/executeTopQueries';
-import tenantOverviewExecuteTopQueries from './tenantOverview/executeTopQueries/executeTopQueries';
+import {tenantOverviewTopQueries} from './tenantOverview/topQueries/tenantOverviewTopQueries';
import executeTopTables from './tenantOverview/executeTopTables/executeTopTables';
import healthcheckInfo from './healthcheckInfo';
import shardsWorkload from './shardsWorkload/shardsWorkload';
-import executeTopShards from './tenantOverview/executeTopShards/executeTopShards';
+import {tenantOverviewTopShards} from './tenantOverview/topShards/tenantOverviewTopShards';
import hotKeys from './hotKeys';
import olapStats from './olapStats';
import authentication from './authentication/authentication';
@@ -75,10 +75,10 @@ export const rootReducer = {
schemaAcl,
executeTopQueries,
executeTopTables,
- tenantOverviewExecuteTopQueries,
+ tenantOverviewTopQueries,
healthcheckInfo,
shardsWorkload,
- executeTopShards,
+ tenantOverviewTopShards,
hotKeys,
authentication,
header,
diff --git a/src/store/reducers/tenantOverview/executeTopQueries/types.ts b/src/store/reducers/tenantOverview/executeTopQueries/types.ts
deleted file mode 100644
index 00adfba5e..000000000
--- a/src/store/reducers/tenantOverview/executeTopQueries/types.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import type {IQueryResult, QueryErrorResponse} from '../../../../types/store/query';
-import type {ApiRequestAction} from '../../../utils';
-import {FETCH_TOP_QUERIES, setDataWasNotLoaded} from './executeTopQueries';
-
-export interface TopQueriesState {
- loading: boolean;
- wasLoaded: boolean;
- data?: IQueryResult;
- error?: QueryErrorResponse;
-}
-
-export type TopQueriesAction =
- | ApiRequestAction
- | ReturnType;
-
-export interface TopQueriesSlice {
- executeTopQueries: TopQueriesState;
-}
diff --git a/src/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts b/src/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts
index c56cfe224..e7dcbb802 100644
--- a/src/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts
+++ b/src/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts
@@ -1,12 +1,10 @@
import type {Reducer} from 'redux';
import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants';
-import {EVersion} from '../../../../types/api/compute';
import {createApiRequest, createRequestActionTypes} from '../../../utils';
import {prepareNodesData} from '../../nodes/utils';
-import type {ComputeApiRequestParams, NodesApiRequestParams} from '../../nodes/types';
+import type {NodesApiRequestParams} from '../../nodes/types';
import type {TopNodesByCpuAction, TopNodesByCpuState, TopPoolsStateSlice} from './types';
-import {prepareTopComputeNodesData} from './utils';
export const FETCH_TOP_NODES_BY_CPU = createRequestActionTypes(
'topNodesByCpu',
@@ -19,7 +17,7 @@ const initialState = {
wasLoaded: false,
};
-const topNodesByCpu: Reducer = (
+export const topNodesByCpu: Reducer = (
state = initialState,
action,
) => {
@@ -80,23 +78,6 @@ export function getTopNodesByCpu({
});
}
-export function getTopComputeNodesByCpu({
- sortOrder = -1,
- sortValue = 'CPU',
- limit = TENANT_OVERVIEW_TABLES_LIMIT,
- version = EVersion.v2,
- ...params
-}: ComputeApiRequestParams) {
- return createApiRequest({
- request: window.api.getCompute(
- {sortOrder, sortValue, limit, version, ...params},
- {concurrentId},
- ),
- actions: FETCH_TOP_NODES_BY_CPU,
- dataHandler: prepareTopComputeNodesData,
- });
-}
-
export const selectTopNodesByCpu = (state: TopPoolsStateSlice) => state.topNodesByCpu.data;
export const setDataWasNotLoaded = () => {
@@ -104,5 +85,3 @@ export const setDataWasNotLoaded = () => {
type: SET_DATA_WAS_NOT_LOADED,
} as const;
};
-
-export default topNodesByCpu;
diff --git a/src/store/reducers/tenantOverview/topNodesByCpu/utils.ts b/src/store/reducers/tenantOverview/topNodesByCpu/utils.ts
deleted file mode 100644
index 249601d94..000000000
--- a/src/store/reducers/tenantOverview/topNodesByCpu/utils.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import type {TComputeInfo} from '../../../../types/api/compute';
-import {prepareComputeNodes} from '../../nodes/utils';
-import type {TopNodesByCpuHandledResponse} from './types';
-
-export const prepareTopComputeNodesData = (data: TComputeInfo): TopNodesByCpuHandledResponse => {
- const preparedNodes = prepareComputeNodes(data.Nodes, data.Tenants);
-
- if (!data.Nodes) {
- preparedNodes.sort((a, b) => {
- let aMaxPoolUsage = 0;
- let bMaxPoolUsage = 0;
- if (a.PoolStats) {
- aMaxPoolUsage = Math.max(...a.PoolStats.map(({Usage}) => Number(Usage)));
- }
- if (b.PoolStats) {
- bMaxPoolUsage = Math.max(...b.PoolStats.map(({Usage}) => Number(Usage)));
- }
- return bMaxPoolUsage - aMaxPoolUsage;
- });
- }
-
- return {
- Nodes: preparedNodes,
- };
-};
diff --git a/src/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts b/src/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts
index 27591ebf8..16ed110e6 100644
--- a/src/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts
+++ b/src/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts
@@ -1,12 +1,10 @@
import type {Reducer} from 'redux';
import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants';
-import {EVersion} from '../../../../types/api/compute';
import {createApiRequest, createRequestActionTypes} from '../../../utils';
import {prepareNodesData} from '../../nodes/utils';
-import type {ComputeApiRequestParams, NodesApiRequestParams} from '../../nodes/types';
+import type {NodesApiRequestParams} from '../../nodes/types';
import type {TopNodesByLoadAction, TopNodesByLoadState, TopNodesByLoadStateSlice} from './types';
-import {prepareTopComputeNodesData} from './utils';
export const FETCH_TOP_NODES_BY_LOAD = createRequestActionTypes(
'topNodesByLoad',
@@ -19,7 +17,7 @@ const initialState = {
wasLoaded: false,
};
-const topNodesByLoad: Reducer = (
+export const topNodesByLoad: Reducer = (
state = initialState,
action,
) => {
@@ -80,23 +78,6 @@ export function getTopNodesByLoad({
});
}
-export function getTopComputeNodesByLoad({
- sortOrder = -1,
- sortValue = 'LoadAverage',
- limit = TENANT_OVERVIEW_TABLES_LIMIT,
- version = EVersion.v2,
- ...params
-}: ComputeApiRequestParams) {
- return createApiRequest({
- request: window.api.getCompute(
- {sortOrder, sortValue, limit, version, ...params},
- {concurrentId},
- ),
- actions: FETCH_TOP_NODES_BY_LOAD,
- dataHandler: prepareTopComputeNodesData,
- });
-}
-
export const selectTopNodesByLoad = (state: TopNodesByLoadStateSlice) => state.topNodesByLoad.data;
export const setDataWasNotLoaded = () => {
@@ -104,5 +85,3 @@ export const setDataWasNotLoaded = () => {
type: SET_DATA_WAS_NOT_LOADED,
} as const;
};
-
-export default topNodesByLoad;
diff --git a/src/store/reducers/tenantOverview/topNodesByLoad/utils.ts b/src/store/reducers/tenantOverview/topNodesByLoad/utils.ts
index 0a59ea5ea..95dfdca4b 100644
--- a/src/store/reducers/tenantOverview/topNodesByLoad/utils.ts
+++ b/src/store/reducers/tenantOverview/topNodesByLoad/utils.ts
@@ -1,20 +1,3 @@
-import type {TComputeInfo} from '../../../../types/api/compute';
import {generateEvaluator} from '../../../../utils/generateEvaluator';
-import {prepareComputeNodes} from '../../nodes/utils';
-import type {TopNodesByLoadHandledResponse} from './types';
-
-export const prepareTopComputeNodesData = (data: TComputeInfo): TopNodesByLoadHandledResponse => {
- const preparedNodes = prepareComputeNodes(data.Nodes, data.Tenants);
-
- let sortedNodes = preparedNodes;
-
- if (!data.Nodes) {
- sortedNodes = preparedNodes.sort((a, b) => Number(b.LoadAverage) - Number(a.LoadAverage));
- }
-
- return {
- Nodes: sortedNodes,
- };
-};
export const getLoadSeverityForNode = generateEvaluator(60, 80, ['success', 'warning', 'danger']);
diff --git a/src/store/reducers/tenantOverview/executeTopQueries/executeTopQueries.ts b/src/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts
similarity index 71%
rename from src/store/reducers/tenantOverview/executeTopQueries/executeTopQueries.ts
rename to src/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts
index 0f14793a2..280b84db3 100644
--- a/src/store/reducers/tenantOverview/executeTopQueries/executeTopQueries.ts
+++ b/src/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts
@@ -5,10 +5,13 @@ import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants';
import {parseQueryAPIExecuteResponse} from '../../../../utils/query';
import {createRequestActionTypes, createApiRequest} from '../../../utils';
-import type {TopQueriesAction, TopQueriesState} from './types';
+import type {TenantOverviewTopQueriesAction, TenantOverviewTopQueriesState} from './types';
-export const FETCH_TOP_QUERIES = createRequestActionTypes('topQueries', 'FETCH_TOP_QUERIES');
-const SET_DATA_WAS_NOT_LOADED = 'topQueries/SET_DATA_WAS_NOT_LOADED';
+export const FETCH_TENANT_OVERVIEW_TOP_QUERIES = createRequestActionTypes(
+ 'tenantOverviewTopQueries',
+ 'FETCH_TOP_QUERIES',
+);
+const SET_DATA_WAS_NOT_LOADED = 'tenantOverviewTopQueries/SET_DATA_WAS_NOT_LOADED';
const initialState = {
loading: false,
@@ -27,19 +30,19 @@ LIMIT ${TENANT_OVERVIEW_TABLES_LIMIT}
`;
};
-const executeTopQueries: Reducer = (
- state = initialState,
- action,
-) => {
+export const tenantOverviewTopQueries: Reducer<
+ TenantOverviewTopQueriesState,
+ TenantOverviewTopQueriesAction
+> = (state = initialState, action) => {
switch (action.type) {
- case FETCH_TOP_QUERIES.REQUEST: {
+ case FETCH_TENANT_OVERVIEW_TOP_QUERIES.REQUEST: {
return {
...state,
loading: true,
error: undefined,
};
}
- case FETCH_TOP_QUERIES.SUCCESS: {
+ case FETCH_TENANT_OVERVIEW_TOP_QUERIES.SUCCESS: {
return {
...state,
data: action.data,
@@ -49,7 +52,7 @@ const executeTopQueries: Reducer = (
};
}
// 401 Unauthorized error is handled by GenericAPI
- case FETCH_TOP_QUERIES.FAILURE: {
+ case FETCH_TENANT_OVERVIEW_TOP_QUERIES.FAILURE: {
return {
...state,
error: action.error || 'Unauthorized',
@@ -66,7 +69,7 @@ const executeTopQueries: Reducer = (
}
};
-export const fetchTopQueries = (database: string) =>
+export const fetchTenantOverviewTopQueries = (database: string) =>
createApiRequest({
request: window.api.sendQuery(
{
@@ -79,7 +82,7 @@ export const fetchTopQueries = (database: string) =>
concurrentId: 'executeTopQueries',
},
),
- actions: FETCH_TOP_QUERIES,
+ actions: FETCH_TENANT_OVERVIEW_TOP_QUERIES,
dataHandler: parseQueryAPIExecuteResponse,
});
@@ -88,5 +91,3 @@ export function setDataWasNotLoaded() {
type: SET_DATA_WAS_NOT_LOADED,
} as const;
}
-
-export default executeTopQueries;
diff --git a/src/store/reducers/tenantOverview/topQueries/types.ts b/src/store/reducers/tenantOverview/topQueries/types.ts
new file mode 100644
index 000000000..31764dc42
--- /dev/null
+++ b/src/store/reducers/tenantOverview/topQueries/types.ts
@@ -0,0 +1,14 @@
+import type {IQueryResult, QueryErrorResponse} from '../../../../types/store/query';
+import type {ApiRequestAction} from '../../../utils';
+import {FETCH_TENANT_OVERVIEW_TOP_QUERIES, setDataWasNotLoaded} from './tenantOverviewTopQueries';
+
+export interface TenantOverviewTopQueriesState {
+ loading: boolean;
+ wasLoaded: boolean;
+ data?: IQueryResult;
+ error?: QueryErrorResponse;
+}
+
+export type TenantOverviewTopQueriesAction =
+ | ApiRequestAction
+ | ReturnType;
diff --git a/src/store/reducers/tenantOverview/executeTopShards/executeTopShards.ts b/src/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts
similarity index 73%
rename from src/store/reducers/tenantOverview/executeTopShards/executeTopShards.ts
rename to src/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts
index d946b533f..f8ba12c53 100644
--- a/src/store/reducers/tenantOverview/executeTopShards/executeTopShards.ts
+++ b/src/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts
@@ -4,10 +4,13 @@ import '../../../../services/api';
import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants';
import {parseQueryAPIExecuteResponse} from '../../../../utils/query';
import {createRequestActionTypes, createApiRequest} from '../../../utils';
-import {TopShardsAction, TopShardsState} from './types';
+import {TenantOverviewTopShardsAction, TenantOverviewTopShardsState} from './types';
-export const FETCH_TOP_SHARDS = createRequestActionTypes('topShards', 'FETCH_TOP_SHARDS');
-const SET_DATA_WAS_NOT_LOADED = 'topShards/SET_DATA_WAS_NOT_LOADED';
+export const FETCH_TENANT_OVERVIEW_TOP_SHARDS = createRequestActionTypes(
+ 'tenantOverviewTopShards',
+ 'FETCH_TENANT_OVERVIEW_TOP_SHARDS',
+);
+const SET_DATA_WAS_NOT_LOADED = 'tenantOverviewTopShards/SET_DATA_WAS_NOT_LOADED';
const initialState = {
loading: false,
@@ -33,19 +36,19 @@ LIMIT ${TENANT_OVERVIEW_TABLES_LIMIT}`;
const queryAction = 'execute-scan';
-const executeTopShards: Reducer = (
- state = initialState,
- action,
-) => {
+export const tenantOverviewTopShards: Reducer<
+ TenantOverviewTopShardsState,
+ TenantOverviewTopShardsAction
+> = (state = initialState, action) => {
switch (action.type) {
- case FETCH_TOP_SHARDS.REQUEST: {
+ case FETCH_TENANT_OVERVIEW_TOP_SHARDS.REQUEST: {
return {
...state,
loading: true,
error: undefined,
};
}
- case FETCH_TOP_SHARDS.SUCCESS: {
+ case FETCH_TENANT_OVERVIEW_TOP_SHARDS.SUCCESS: {
return {
...state,
data: action.data,
@@ -55,7 +58,7 @@ const executeTopShards: Reducer = (
};
}
// 401 Unauthorized error is handled by GenericAPI
- case FETCH_TOP_SHARDS.FAILURE: {
+ case FETCH_TENANT_OVERVIEW_TOP_SHARDS.FAILURE: {
if (action.error?.isCancelled) {
return state;
}
@@ -76,7 +79,7 @@ const executeTopShards: Reducer = (
}
};
-export const sendTopShardsQuery = (database: string, path = '') =>
+export const sendTenantOverviewTopShardsQuery = (database: string, path = '') =>
createApiRequest({
request: window.api.sendQuery(
{
@@ -89,7 +92,7 @@ export const sendTopShardsQuery = (database: string, path = '') =>
concurrentId: 'executeTopShards',
},
),
- actions: FETCH_TOP_SHARDS,
+ actions: FETCH_TENANT_OVERVIEW_TOP_SHARDS,
dataHandler: parseQueryAPIExecuteResponse,
});
@@ -98,5 +101,3 @@ export function setDataWasNotLoaded() {
type: SET_DATA_WAS_NOT_LOADED,
} as const;
}
-
-export default executeTopShards;
diff --git a/src/store/reducers/tenantOverview/executeTopShards/types.ts b/src/store/reducers/tenantOverview/topShards/types.ts
similarity index 50%
rename from src/store/reducers/tenantOverview/executeTopShards/types.ts
rename to src/store/reducers/tenantOverview/topShards/types.ts
index 55bf935f2..d679e3109 100644
--- a/src/store/reducers/tenantOverview/executeTopShards/types.ts
+++ b/src/store/reducers/tenantOverview/topShards/types.ts
@@ -1,18 +1,14 @@
import type {IQueryResult, QueryErrorResponse} from '../../../../types/store/query';
import type {ApiRequestAction} from '../../../utils';
-import {FETCH_TOP_SHARDS, setDataWasNotLoaded} from './executeTopShards';
+import {FETCH_TENANT_OVERVIEW_TOP_SHARDS, setDataWasNotLoaded} from './tenantOverviewTopShards';
-export interface TopShardsState {
+export interface TenantOverviewTopShardsState {
loading: boolean;
wasLoaded: boolean;
data?: IQueryResult;
error?: QueryErrorResponse;
}
-export type TopShardsAction =
- | ApiRequestAction
+export type TenantOverviewTopShardsAction =
+ | ApiRequestAction
| ReturnType;
-
-export interface TopShardsSlice {
- topShards: TopShardsState;
-}
diff --git a/src/store/reducers/tenantOverview/executeTopShards/utils.ts b/src/store/reducers/tenantOverview/topShards/utils.ts
similarity index 100%
rename from src/store/reducers/tenantOverview/executeTopShards/utils.ts
rename to src/store/reducers/tenantOverview/topShards/utils.ts
diff --git a/src/types/additionalProps.ts b/src/types/additionalProps.ts
index 59d03477e..724b28f76 100644
--- a/src/types/additionalProps.ts
+++ b/src/types/additionalProps.ts
@@ -26,6 +26,8 @@ export interface AdditionalTenantsProps {
export type NodeAddress = Pick;
+export type GetNodeRefFunc = (node?: NodeAddress) => string | null;
+
export interface AdditionalNodesProps extends Record {
- getNodeRef?: (node?: NodeAddress) => string | null;
+ getNodeRef?: GetNodeRefFunc;
}