import React from 'react'; import {Helmet} from 'react-helmet-async'; import {PageError} from '../../components/Errors/PageError/PageError'; import {LoaderWrapper} from '../../components/LoaderWrapper/LoaderWrapper'; import SplitPane from '../../components/SplitPane'; import {useClusterWithProxy} from '../../store/reducers/cluster/cluster'; import {setHeaderBreadcrumbs} from '../../store/reducers/header/header'; import {overviewApi} from '../../store/reducers/overview/overview'; import {selectSchemaObjectData} from '../../store/reducers/schema/schema'; import {TENANT_PAGES_IDS} from '../../store/reducers/tenant/constants'; import {useTenantBaseInfo} from '../../store/reducers/tenant/tenant'; import type {AdditionalTenantsProps} from '../../types/additionalProps'; import {uiFactory} from '../../uiFactory/uiFactory'; import {cn} from '../../utils/cn'; import {DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY} from '../../utils/constants'; import {useTypedDispatch, useTypedSelector} from '../../utils/hooks'; import {useSetting} from '../../utils/hooks/useSetting'; import {isAccessError} from '../../utils/response'; import {useAppTitle} from '../App/AppTitleContext'; import Diagnostics from './Diagnostics/Diagnostics'; import ObjectGeneral from './ObjectGeneral/ObjectGeneral'; import {ObjectSummary} from './ObjectSummary/ObjectSummary'; import {TreeKeyProvider} from './ObjectSummary/UpdateTreeContext'; import {TenantContextProvider} from './TenantContext'; import {TenantDrawerWrapper} from './TenantDrawerWrappers'; import {useTenantPage} from './TenantNavigation/useTenantNavigation'; import i18n from './i18n'; import {useTenantQueryParams} from './useTenantQueryParams'; import { PaneVisibilityActionTypes, paneVisibilityToggleReducer, } from './utils/paneVisibilityToggleHelpers'; import {useNavigationV2Enabled} from './utils/useNavigationV2Enabled'; import './Tenant.scss'; const b = cn('tenant-page'); interface TenantProps { additionalTenantProps?: AdditionalTenantsProps; } export function Tenant({additionalTenantProps}: TenantProps) { const useMetaProxy = useClusterWithProxy(); const {database, schema} = useTenantQueryParams(); const {name, isLoading, error} = useTenantBaseInfo(database ?? ''); if (!database) { throw new Error('Tenant name is not defined'); } const previousTenant = React.useRef(); React.useEffect(() => { if (previousTenant.current !== database) { const register = async () => { const {registerYQLCompletionItemProvider} = await import( '../../utils/monaco/yql/yql.completionItemProvider' ); registerYQLCompletionItemProvider(database); }; register().catch(console.error); previousTenant.current = database; } }, [database]); const databaseName = name ?? ''; const path = schema ?? databaseName; const dispatch = useTypedDispatch(); React.useEffect(() => { dispatch(setHeaderBreadcrumbs('tenant', {databaseName, database})); }, [databaseName, database, dispatch]); const showBlockingError = isAccessError(error); const errorProps = showBlockingError ? uiFactory.clusterOrDatabaseAccessError : undefined; const isV2Enabled = useNavigationV2Enabled(); const {tenantPage} = useTenantPage(); const showDatabaseDiagnostics = isV2Enabled && tenantPage === TENANT_PAGES_IDS.database; const title = path || i18n('title_database'); const {appTitle} = useAppTitle(); const renderContent = () => { if (showDatabaseDiagnostics) { return (
); } return ( ); }; return (
{renderContent()}
); } function TreePagesContent({ path, database, databaseName, useMetaProxy, additionalTenantProps, }: { path: string; database: string; databaseName: string; useMetaProxy?: boolean; additionalTenantProps?: AdditionalTenantsProps; }) { const { currentData: currentItem, error, isLoading, } = overviewApi.useGetOverviewQuery({ path, database, databaseFullPath: databaseName, useMetaProxy, }); const [isSummaryCollapsed, setIsSummaryCollapsed] = useSetting( DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, false, ); const [summaryVisibilityState, dispatchSummaryVisibilityAction] = React.useReducer( paneVisibilityToggleReducer, undefined, () => ({ triggerExpand: false, triggerCollapse: false, collapsed: isSummaryCollapsed, }), ); const onCollapseSummaryHandler = () => { setIsSummaryCollapsed(true); dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.triggerCollapse); }; const onExpandSummaryHandler = () => { setIsSummaryCollapsed(false); dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.triggerExpand); }; const onSplitStartDragAdditional = () => { setIsSummaryCollapsed(false); dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.clear); }; // Prevent loader when changing schema objects // Query is called here to check user rights // Once they are checked, we can show content const [initialLoading, setInitialLoading] = React.useState(true); React.useEffect(() => { if (!isLoading) { setInitialLoading(false); } }, [isLoading]); const preloadedData = useTypedSelector((state) => selectSchemaObjectData(state, path, database, databaseName, useMetaProxy), ); const accessError = isAccessError(error) ? error : undefined; const showBlockingDescribeError = Boolean(accessError && path === databaseName); const describeErrorProps = showBlockingDescribeError ? uiFactory.clusterOrDatabaseAccessError : undefined; // Use preloaded data if there is no current item data yet const currentPathType = currentItem?.PathDescription?.Self?.PathType ?? preloadedData?.PathDescription?.Self?.PathType; const currentPathSubType = currentItem?.PathDescription?.Self?.PathSubType ?? preloadedData?.PathDescription?.Self?.PathSubType; return (
); }