diff --git a/src/components/NetworkTable/NetworkTable.tsx b/src/components/NetworkTable/NetworkTable.tsx
new file mode 100644
index 0000000000..57d6d963cc
--- /dev/null
+++ b/src/components/NetworkTable/NetworkTable.tsx
@@ -0,0 +1,40 @@
+import {Nodes} from '../../containers/Nodes/Nodes';
+import type {NodesProps} from '../../containers/Nodes/Nodes';
+
+import {getNetworkTableNodesColumns} from './columns';
+import {
+ NETWORK_DEFAULT_NODES_COLUMNS,
+ NETWORK_NODES_GROUP_BY_PARAMS,
+ NETWORK_NODES_TABLE_SELECTED_COLUMNS_KEY,
+ NETWORK_REQUIRED_NODES_COLUMNS,
+} from './constants';
+
+type NetworkWrapperProps = Pick<
+ NodesProps,
+ 'path' | 'scrollContainerRef' | 'additionalNodesProps' | 'database'
+>;
+
+export function NetworkTable({
+ database,
+ path,
+ scrollContainerRef,
+ additionalNodesProps,
+}: NetworkWrapperProps) {
+ return (
+
+ );
+}
diff --git a/src/components/NetworkTable/columns.tsx b/src/components/NetworkTable/columns.tsx
new file mode 100644
index 0000000000..6afb89fd83
--- /dev/null
+++ b/src/components/NetworkTable/columns.tsx
@@ -0,0 +1,41 @@
+import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
+import type {Column} from '../../utils/tableUtils/types';
+import {
+ getClockSkewColumn,
+ getConnectionsColumn,
+ getCpuColumn,
+ getDataCenterColumn,
+ getHostColumn,
+ getNetworkUtilizationColumn,
+ getNodeIdColumn,
+ getPingTimeColumn,
+ getPoolsColumn,
+ getRackColumn,
+ getReceiveThroughputColumn,
+ getSendThroughputColumn,
+ getUptimeColumn,
+} from '../nodesColumns/columns';
+import {isSortableNodesColumn} from '../nodesColumns/constants';
+import type {GetNodesColumnsParams} from '../nodesColumns/types';
+
+export function getNetworkTableNodesColumns(params: GetNodesColumnsParams) {
+ const columns: Column[] = [
+ getNodeIdColumn(),
+ getHostColumn(params, {statusForIcon: 'ConnectStatus'}),
+ getDataCenterColumn(),
+ getRackColumn(),
+ getUptimeColumn(),
+ getCpuColumn(),
+ getPoolsColumn(),
+ getConnectionsColumn(),
+ getNetworkUtilizationColumn(),
+ getSendThroughputColumn(),
+ getReceiveThroughputColumn(),
+ getPingTimeColumn(),
+ getClockSkewColumn(),
+ ];
+
+ return columns.map((column) => {
+ return {...column, sortable: isSortableNodesColumn(column.name)};
+ });
+}
diff --git a/src/containers/Tenant/Diagnostics/Network/NetworkTable/constants.ts b/src/components/NetworkTable/constants.ts
similarity index 79%
rename from src/containers/Tenant/Diagnostics/Network/NetworkTable/constants.ts
rename to src/components/NetworkTable/constants.ts
index e6854dcb7a..a493899109 100644
--- a/src/containers/Tenant/Diagnostics/Network/NetworkTable/constants.ts
+++ b/src/components/NetworkTable/constants.ts
@@ -1,5 +1,5 @@
-import type {NodesColumnId} from '../../../../../components/nodesColumns/constants';
-import type {NodesGroupByField} from '../../../../../types/api/nodes';
+import type {NodesGroupByField} from '../../types/api/nodes';
+import type {NodesColumnId} from '../nodesColumns/constants';
export const NETWORK_NODES_TABLE_SELECTED_COLUMNS_KEY = 'networkNodesTableSelectedColumns';
diff --git a/src/components/NetworkTable/hooks.ts b/src/components/NetworkTable/hooks.ts
new file mode 100644
index 0000000000..d961de340c
--- /dev/null
+++ b/src/components/NetworkTable/hooks.ts
@@ -0,0 +1,20 @@
+import {
+ useNodesHandlerHasWorkingClusterNetworkStats,
+ useViewerNodesHandlerHasNetworkStats,
+} from '../../store/reducers/capabilities/hooks';
+import {ENABLE_NETWORK_TABLE_KEY} from '../../utils/constants';
+import {useSetting} from '../../utils/hooks';
+
+export function useShouldShowDatabaseNetworkTable() {
+ const viewerNodesHasNetworkStats = useViewerNodesHandlerHasNetworkStats();
+ const [networkTableEnabled] = useSetting(ENABLE_NETWORK_TABLE_KEY);
+
+ return Boolean(viewerNodesHasNetworkStats && networkTableEnabled);
+}
+
+export function useShouldShowClusterNetworkTable() {
+ const nodesHasWorkingClusterNetworkStats = useNodesHandlerHasWorkingClusterNetworkStats();
+ const [networkTableEnabled] = useSetting(ENABLE_NETWORK_TABLE_KEY);
+
+ return Boolean(nodesHasWorkingClusterNetworkStats && networkTableEnabled);
+}
diff --git a/src/containers/Cluster/Cluster.tsx b/src/containers/Cluster/Cluster.tsx
index 6d85f748ae..896df61267 100644
--- a/src/containers/Cluster/Cluster.tsx
+++ b/src/containers/Cluster/Cluster.tsx
@@ -9,9 +9,12 @@ import {AutoRefreshControl} from '../../components/AutoRefreshControl/AutoRefres
import {EntityStatus} from '../../components/EntityStatusNew/EntityStatus';
import {EFlagToDescription} from '../../components/EntityStatusNew/utils';
import {InternalLink} from '../../components/InternalLink';
+import {NetworkTable} from '../../components/NetworkTable/NetworkTable';
+import {useShouldShowClusterNetworkTable} from '../../components/NetworkTable/hooks';
import routes, {getLocationObjectFromHref} from '../../routes';
import {useClusterDashboardAvailable} from '../../store/reducers/capabilities/hooks';
import {
+ INITIAL_DEFAULT_CLUSTER_TAB,
clusterApi,
selectClusterTabletsWithFqdn,
selectClusterTitle,
@@ -55,6 +58,8 @@ export function Cluster({
const container = React.useRef(null);
const isClusterDashboardAvailable = useClusterDashboardAvailable();
+ const shouldShowNetworkTable = useShouldShowClusterNetworkTable();
+
const [autoRefreshInterval] = useAutoRefreshInterval();
const dispatch = useTypedDispatch();
@@ -92,6 +97,14 @@ export function Cluster({
dispatch(setHeaderBreadcrumbs('cluster', {}));
}, [dispatch]);
+ const actualClusterTabs = React.useMemo(() => {
+ if (shouldShowNetworkTable) {
+ return clusterTabs;
+ } else {
+ return clusterTabs.filter((tab) => tab.id !== clusterTabsIds.network);
+ }
+ }, [shouldShowNetworkTable]);
+
const getClusterTitle = () => {
if (infoLoading) {
return ;
@@ -110,8 +123,8 @@ export function Cluster({
};
const activeTab = React.useMemo(
- () => clusterTabs.find(({id}) => id === activeTabId),
- [activeTabId],
+ () => actualClusterTabs.find(({id}) => id === activeTabId),
+ [activeTabId, actualClusterTabs],
);
return (
@@ -142,7 +155,7 @@ export function Cluster({
size="l"
allowNotSelected={true}
activeTab={activeTabId}
- items={clusterTabs}
+ items={actualClusterTabs}
wrapTo={({id}, node) => {
const path = getClusterPath(id as ClusterTab, {clusterName, backend});
return (
@@ -202,6 +215,19 @@ export function Cluster({
>
+ {shouldShowNetworkTable && (
+
+
+
+ )}
state.cluster.defaultClusterTab);
+ const shouldShowNetworkTable = useShouldShowClusterNetworkTable();
+
const match = useRouteMatch<{activeTab: string}>(routes.cluster);
const {activeTab: activeTabFromParams} = match?.params || {};
let activeTab: ClusterTab;
- if (isClusterTab(activeTabFromParams)) {
+
+ if (!shouldShowNetworkTable && activeTabFromParams === clusterTabsIds.network) {
+ activeTab = INITIAL_DEFAULT_CLUSTER_TAB;
+ } else if (isClusterTab(activeTabFromParams)) {
activeTab = activeTabFromParams;
} else {
activeTab = defaultTab;
diff --git a/src/containers/Cluster/utils.tsx b/src/containers/Cluster/utils.tsx
index 785ebfda94..47c8fa77d9 100644
--- a/src/containers/Cluster/utils.tsx
+++ b/src/containers/Cluster/utils.tsx
@@ -7,6 +7,7 @@ export const clusterTabsIds = {
tenants: 'tenants',
nodes: 'nodes',
storage: 'storage',
+ network: 'network',
versions: 'versions',
tablets: 'tablets',
} as const;
@@ -25,6 +26,10 @@ const storage = {
id: clusterTabsIds.storage,
title: 'Storage',
};
+const network = {
+ id: clusterTabsIds.network,
+ title: 'Network',
+};
const versions = {
id: clusterTabsIds.versions,
title: 'Versions',
@@ -34,7 +39,7 @@ const tablets = {
title: 'Tablets',
};
-export const clusterTabs = [tenants, nodes, storage, tablets, versions];
+export const clusterTabs = [tenants, nodes, storage, network, tablets, versions];
export function isClusterTab(tab: any): tab is ClusterTab {
return Object.values(clusterTabsIds).includes(tab);
diff --git a/src/containers/Tenant/Diagnostics/Network/NetworkTable/columns.tsx b/src/containers/Tenant/Diagnostics/Network/NetworkTable/columns.tsx
deleted file mode 100644
index f98714a93f..0000000000
--- a/src/containers/Tenant/Diagnostics/Network/NetworkTable/columns.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import {
- getClockSkewColumn,
- getConnectionsColumn,
- getCpuColumn,
- getDataCenterColumn,
- getHostColumn,
- getNetworkUtilizationColumn,
- getNodeIdColumn,
- getPingTimeColumn,
- getPoolsColumn,
- getRackColumn,
- getReceiveThroughputColumn,
- getSendThroughputColumn,
- getUptimeColumn,
-} from '../../../../../components/nodesColumns/columns';
-import {isSortableNodesColumn} from '../../../../../components/nodesColumns/constants';
-import type {GetNodesColumnsParams} from '../../../../../components/nodesColumns/types';
-import type {NodesPreparedEntity} from '../../../../../store/reducers/nodes/types';
-import type {Column} from '../../../../../utils/tableUtils/types';
-
-export function getNetworkTableNodesColumns(
- params: GetNodesColumnsParams,
-): Column[] {
- const columns = [
- getNodeIdColumn(),
- getHostColumn(params, {statusForIcon: 'ConnectStatus'}),
- getDataCenterColumn(),
- getRackColumn(),
- getUptimeColumn(),
- getCpuColumn(),
- getPoolsColumn(),
- getConnectionsColumn(),
- getNetworkUtilizationColumn(),
- getSendThroughputColumn(),
- getReceiveThroughputColumn(),
- getPingTimeColumn(),
- getClockSkewColumn(),
- ];
-
- return columns.map((column) => {
- return {...column, sortable: isSortableNodesColumn(column.name)};
- });
-}
diff --git a/src/containers/Tenant/Diagnostics/Network/NetworkWrapper.tsx b/src/containers/Tenant/Diagnostics/Network/NetworkWrapper.tsx
index 4f3adae4e5..061329e49e 100644
--- a/src/containers/Tenant/Diagnostics/Network/NetworkWrapper.tsx
+++ b/src/containers/Tenant/Diagnostics/Network/NetworkWrapper.tsx
@@ -1,21 +1,10 @@
import {LoaderWrapper} from '../../../../components/LoaderWrapper/LoaderWrapper';
-import {
- useCapabilitiesLoaded,
- useViewerNodesHandlerHasNetworkStats,
-} from '../../../../store/reducers/capabilities/hooks';
-import {ENABLE_NETWORK_TABLE_KEY} from '../../../../utils/constants';
-import {useSetting} from '../../../../utils/hooks';
+import {NetworkTable} from '../../../../components/NetworkTable/NetworkTable';
+import {useShouldShowDatabaseNetworkTable} from '../../../../components/NetworkTable/hooks';
+import {useCapabilitiesLoaded} from '../../../../store/reducers/capabilities/hooks';
import type {NodesProps} from '../../../Nodes/Nodes';
-import {Nodes} from '../../../Nodes/Nodes';
import {Network} from './Network';
-import {getNetworkTableNodesColumns} from './NetworkTable/columns';
-import {
- NETWORK_DEFAULT_NODES_COLUMNS,
- NETWORK_NODES_GROUP_BY_PARAMS,
- NETWORK_NODES_TABLE_SELECTED_COLUMNS_KEY,
- NETWORK_REQUIRED_NODES_COLUMNS,
-} from './NetworkTable/constants';
interface NetworkWrapperProps
extends Pick {
@@ -29,28 +18,16 @@ export function NetworkWrapper({
additionalNodesProps,
}: NetworkWrapperProps) {
const capabilitiesLoaded = useCapabilitiesLoaded();
- const viewerNodesHasNetworkStats = useViewerNodesHandlerHasNetworkStats();
- const [networkTableEnabled] = useSetting(ENABLE_NETWORK_TABLE_KEY);
-
- const shouldUseNetworkNodesTable = viewerNodesHasNetworkStats && networkTableEnabled;
+ const shouldUseNetworkNodesTable = useShouldShowDatabaseNetworkTable();
const renderContent = () => {
if (shouldUseNetworkNodesTable) {
return (
-
);
}
diff --git a/src/store/reducers/capabilities/hooks.ts b/src/store/reducers/capabilities/hooks.ts
index eb6fc9d455..ca6ae32fba 100644
--- a/src/store/reducers/capabilities/hooks.ts
+++ b/src/store/reducers/capabilities/hooks.ts
@@ -67,6 +67,13 @@ export const useViewerNodesHandlerHasNetworkStats = () => {
return useGetFeatureVersion('/viewer/nodes') > 13;
};
+// Before this version handler has very big response size if nodes quantity is more than 100
+// Response size could be up to 20-30MB, it loads very long and freezes UI
+// It is not very common for databases, but an often case for clusters
+export const useNodesHandlerHasWorkingClusterNetworkStats = () => {
+ return useGetFeatureVersion('/viewer/nodes') >= 16;
+};
+
export const useFeatureFlagsAvailable = () => {
return useGetFeatureVersion('/viewer/feature_flags') > 1;
};
diff --git a/src/store/reducers/cluster/cluster.ts b/src/store/reducers/cluster/cluster.ts
index 1fa396b9c8..403e883cbb 100644
--- a/src/store/reducers/cluster/cluster.ts
+++ b/src/store/reducers/cluster/cluster.ts
@@ -23,13 +23,15 @@ import {
parseGroupsStatsQueryResponse,
} from './utils';
+export const INITIAL_DEFAULT_CLUSTER_TAB = clusterTabsIds.tenants;
+
const defaultClusterTabLS = localStorage.getItem(DEFAULT_CLUSTER_TAB_KEY);
let defaultClusterTab: ClusterTab;
if (isClusterTab(defaultClusterTabLS)) {
defaultClusterTab = defaultClusterTabLS;
} else {
- defaultClusterTab = clusterTabsIds.tenants;
+ defaultClusterTab = INITIAL_DEFAULT_CLUSTER_TAB;
}
const initialState: ClusterState = {