feat: restore cluster detail surface, gate cluster-list name link via plugin
The "chore: hide cluster detail" change had commented out both the cluster-detail route and the cluster name link in the list. The detail page component still ships in the OSS tree, so reach is restored but the link is plugin-gated rather than unconditional: plain OSS renders the name as a span; with a registered `clusterDetail.linkableName` flag the name turns into a `Typography.Link` that fires the parent's existing `onCellClick` (which navigates to the detail route). Detail tabs adjustments for the in-cluster context: - Drop the Deployments tab (deployments are managed from the top-level Models page; the detail view is scoped to a single cluster's hardware). - `WorkerList` and `GPUList` accept an optional `clusterId`. When set, the list pins `cluster_id` in its query and hides the cluster-filter dropdown so the user can't scope away from the cluster they're inside. `clusterDetail.extraTabs(clusterId, intl)` exposes a plugin slot that appends additional tab items — used by the enterprise plugin to inject per-cluster Access / Quotas surfaces. No-op without a plugin.
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { clusterDetailAtom } from '@/atoms/clusters';
|
||||
import Deployments from '@/pages/llmodels/deployments';
|
||||
import GPUList from '@/pages/resources/components/gpus';
|
||||
import WorkerList from '@/pages/resources/components/workers';
|
||||
import { getGPUStackPlugin } from '@/plugins';
|
||||
import { IconFont } from '@gpustack/core-ui';
|
||||
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
||||
import { Tabs } from 'antd';
|
||||
import { Tabs, type TabsProps } from 'antd';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { PageContainerInner } from '../_components/page-box';
|
||||
import PageBreadcrumb from '../_components/page-breadcrumb';
|
||||
@@ -29,6 +29,22 @@ const ClusterDetailModal = () => {
|
||||
}
|
||||
];
|
||||
|
||||
// Extension slot: a registered plugin may inject additional tab
|
||||
// items (e.g. per-cluster access / quota panels) by exporting
|
||||
// ``clusterDetail.extraTabs(clusterId, intl)`` that returns an
|
||||
// ``items`` array. The plugin's items are appended after the
|
||||
// built-in tabs; without a plugin this is just ``[]`` and the
|
||||
// tab strip is unchanged. ``intl`` is threaded through so plugin
|
||||
// tabs can resolve i18n labels to plain strings — antd Tabs'
|
||||
// icon-text gap collapses when ``label`` is a ReactNode rather
|
||||
// than a string, so matching the built-in tabs' shape keeps the
|
||||
// gap visually consistent.
|
||||
type TabItem = NonNullable<TabsProps['items']>[number];
|
||||
const extraTabs = (getGPUStackPlugin()?.clusterDetail?.extraTabs?.(
|
||||
Number(id),
|
||||
intl
|
||||
) ?? []) as TabItem[];
|
||||
|
||||
return (
|
||||
<PageContainerInner
|
||||
header={{
|
||||
@@ -46,20 +62,15 @@ const ClusterDetailModal = () => {
|
||||
key: 'workers',
|
||||
label: `Workers`,
|
||||
icon: <IconFont type="icon-resources" />,
|
||||
children: <WorkerList />
|
||||
},
|
||||
{
|
||||
key: 'deployments',
|
||||
label: `Deployments`,
|
||||
icon: <IconFont type="icon-rocket-launch1" />,
|
||||
children: <Deployments></Deployments>
|
||||
children: <WorkerList clusterId={Number(id)} />
|
||||
},
|
||||
{
|
||||
key: 'gpus',
|
||||
label: `GPUs`,
|
||||
icon: <IconFont type="icon-gpu1" />,
|
||||
children: <GPUList />
|
||||
}
|
||||
children: <GPUList clusterId={Number(id)} />
|
||||
},
|
||||
...extraTabs
|
||||
]}
|
||||
/>
|
||||
</PageContainerInner>
|
||||
|
||||
Reference in New Issue
Block a user