diff --git a/src/containers/Cluster/Cluster.tsx b/src/containers/Cluster/Cluster.tsx index 5f85018d36..b77a5cb500 100644 --- a/src/containers/Cluster/Cluster.tsx +++ b/src/containers/Cluster/Cluster.tsx @@ -9,7 +9,11 @@ import {AutoRefreshControl} from '../../components/AutoRefreshControl/AutoRefres import {EntityStatus} from '../../components/EntityStatus/EntityStatus'; import {InternalLink} from '../../components/InternalLink'; import routes, {getLocationObjectFromHref} from '../../routes'; -import {clusterApi, updateDefaultClusterTab} from '../../store/reducers/cluster/cluster'; +import { + clusterApi, + selectClusterTitle, + updateDefaultClusterTab, +} from '../../store/reducers/cluster/cluster'; import {setHeaderBreadcrumbs} from '../../store/reducers/header/header'; import type { AdditionalClusterProps, @@ -18,7 +22,6 @@ import type { AdditionalVersionsProps, } from '../../types/additionalProps'; import {cn} from '../../utils/cn'; -import {CLUSTER_DEFAULT_TITLE} from '../../utils/constants'; import {useTypedDispatch, useTypedSelector} from '../../utils/hooks'; import {parseVersionsToVersionToColorMap} from '../../utils/versions'; import {NodesWrapper} from '../Nodes/NodesWrapper'; @@ -58,6 +61,10 @@ export function Cluster({ backend: StringParam, }); + const clusterTitle = useTypedSelector((state) => + selectClusterTitle(state, clusterName ?? undefined), + ); + const { data: {clusterData: cluster = {}, groupsStats} = {}, isLoading: infoLoading, @@ -66,11 +73,9 @@ export function Cluster({ const clusterError = error && typeof error === 'object' ? error : undefined; - const {Name} = cluster; - React.useEffect(() => { dispatch(setHeaderBreadcrumbs('cluster', {})); - }, [dispatch, Name]); + }, [dispatch]); const versionToColor = React.useMemo(() => { if (additionalVersionsProps?.getVersionToColorMap) { @@ -88,13 +93,12 @@ export function Cluster({ ); }; - const clusterTitle = cluster?.Name ?? clusterName ?? CLUSTER_DEFAULT_TITLE; const activeTab = React.useMemo( () => clusterTabs.find(({id}) => id === activeTabId), [activeTabId], diff --git a/src/services/api.ts b/src/services/api.ts index f7e26863ed..372ff94d48 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -14,12 +14,7 @@ import type {DescribeConsumerResult} from '../types/api/consumer'; import type {FeatureFlagConfigs} from '../types/api/featureFlags'; import type {HealthCheckAPIResponse} from '../types/api/healthcheck'; import type {JsonHotKeysResponse} from '../types/api/hotkeys'; -import type { - MetaCluster, - MetaClusters, - MetaGeneralClusterInfo, - MetaTenants, -} from '../types/api/meta'; +import type {MetaBaseClusterInfo, MetaCluster, MetaClusters, MetaTenants} from '../types/api/meta'; import type {ModifyDiskResponse} from '../types/api/modifyDisk'; import type {TNetInfo} from '../types/api/netInfo'; import type {TNodesInfo} from '../types/api/nodes'; @@ -826,7 +821,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper { getClusterBaseInfo( _clusterName: string, _opts: AxiosOptions = {}, - ): Promise { + ): Promise { throw new Error('Method is not implemented.'); } } @@ -861,8 +856,8 @@ export class YdbWebVersionAPI extends YdbEmbeddedAPI { getClusterBaseInfo( clusterName: string, {concurrentId, signal}: AxiosOptions = {}, - ): Promise { - return this.get( + ): Promise { + return this.get( `${META_BACKEND || ''}/meta/db_clusters`, { name: clusterName, diff --git a/src/store/reducers/cluster/cluster.ts b/src/store/reducers/cluster/cluster.ts index b5aa65b1ae..c10f5b07a8 100644 --- a/src/store/reducers/cluster/cluster.ts +++ b/src/store/reducers/cluster/cluster.ts @@ -1,4 +1,4 @@ -import {createSlice} from '@reduxjs/toolkit'; +import {createSelector, createSlice} from '@reduxjs/toolkit'; import type {Dispatch, PayloadAction} from '@reduxjs/toolkit'; import {skipToken} from '@reduxjs/toolkit/query'; import {StringParam, useQueryParam} from 'use-query-params'; @@ -7,12 +7,17 @@ import type {ClusterTab} from '../../../containers/Cluster/utils'; import {clusterTabsIds, isClusterTab} from '../../../containers/Cluster/utils'; import {parseTraceFields} from '../../../services/parsers/parseMetaCluster'; import type {TClusterInfo} from '../../../types/api/cluster'; -import {DEFAULT_CLUSTER_TAB_KEY} from '../../../utils/constants'; +import {CLUSTER_DEFAULT_TITLE, DEFAULT_CLUSTER_TAB_KEY} from '../../../utils/constants'; import {isQueryErrorResponse} from '../../../utils/query'; +import type {RootState} from '../../defaultStore'; import {api} from '../api'; import type {ClusterGroupsStats, ClusterState} from './types'; -import {createSelectClusterGroupsQuery, parseGroupsStatsQueryResponse} from './utils'; +import { + createSelectClusterGroupsQuery, + normalizeDomain, + parseGroupsStatsQueryResponse, +} from './utils'; const defaultClusterTabLS = localStorage.getItem(DEFAULT_CLUSTER_TAB_KEY); @@ -61,7 +66,6 @@ export const clusterApi = api.injectEndpoints({ const clusterData = await window.api.getClusterInfo(clusterName, {signal}); const clusterRoot = clusterData.Domain; - // Without domain we cannot get stats from system tables if (!clusterRoot) { return {data: {clusterData}}; @@ -134,3 +138,24 @@ export function useClusterBaseInfo() { monitoring, }; } + +const createClusterInfoSelector = createSelector( + (clusterName?: string) => clusterName, + (clusterName) => clusterApi.endpoints.getClusterInfo.select(clusterName), +); + +export const selectClusterInfo = createSelector( + (state: RootState) => state, + (_state: RootState, clusterName?: string) => createClusterInfoSelector(clusterName), + (state, selectGetClusterInfo) => selectGetClusterInfo(state).data, +); + +export const selectClusterTitle = createSelector( + (_state: RootState, clusterName?: string) => clusterName, + (state: RootState, clusterName?: string) => selectClusterInfo(state, clusterName), + (clusterName, clusterInfo) => { + const {Name, Domain} = clusterInfo?.clusterData || {}; + + return Name || clusterName || normalizeDomain(Domain) || CLUSTER_DEFAULT_TITLE; + }, +); diff --git a/src/store/reducers/cluster/utils.ts b/src/store/reducers/cluster/utils.ts index 16c3f7d3fa..2dc9c9d767 100644 --- a/src/store/reducers/cluster/utils.ts +++ b/src/store/reducers/cluster/utils.ts @@ -86,3 +86,11 @@ export const parseGroupsStatsQueryResponse = ( return result; }; + +export function normalizeDomain(domain?: string) { + if (!domain) { + return undefined; + } + const normalizedDomain = domain.startsWith('/') ? domain.slice(1) : domain; + return normalizedDomain.toUpperCase(); +} diff --git a/src/types/api/meta.ts b/src/types/api/meta.ts index 8142b78194..bf213bf6fe 100644 --- a/src/types/api/meta.ts +++ b/src/types/api/meta.ts @@ -22,7 +22,7 @@ export interface MetaExtendedClusterInfo extends MetaGeneralClusterInfo { versions?: MetaClusterVersion[]; } -export interface MetaGeneralClusterInfo { +export interface MetaBaseClusterInfo { owner?: string; location?: string; image?: string; @@ -38,11 +38,14 @@ export interface MetaGeneralClusterInfo { description?: string; balancer?: string; service?: string; - cluster?: MetaViewerClusterInfo; trace_view?: string; trace_check?: string; } +export interface MetaGeneralClusterInfo extends MetaBaseClusterInfo { + cluster?: MetaViewerClusterInfo; +} + // In case of error in viewer /cluster request mvp return error field instead of cluster data export interface MetaViewerClusterInfo extends TClusterInfo { error?: string;