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:
gitlawr
2026-05-11 20:28:29 +08:00
committed by jialin
parent e25d48cc89
commit 125a5be91f
5 changed files with 76 additions and 30 deletions
+12 -3
View File
@@ -11,7 +11,15 @@ import { GPU_DEVICES_API, queryGpuDevicesList } from '../apis';
import { GPUDeviceItem } from '../config/types';
import useGPUColumns from '../hooks/use-gpu-columns';
const GPUList = () => {
// Optional ``clusterId`` pins the list to a single cluster (used by
// the cluster-detail page) and hides the cluster-filter dropdown so
// the user can't change scope away from the cluster they're already
// inside.
interface GPUListProps {
clusterId?: number;
}
const GPUList: React.FC<GPUListProps> = ({ clusterId }) => {
const {
dataSource,
queryParams,
@@ -26,7 +34,8 @@ const GPUList = () => {
key: PaginationKey.GPUs,
fetchAPI: queryGpuDevicesList,
polling: true,
API: GPU_DEVICES_API
API: GPU_DEVICES_API,
defaultQueryParams: clusterId ? { cluster_id: clusterId } : undefined
});
const [searchParams] = useSearchParams();
const page = searchParams.get('page');
@@ -100,7 +109,7 @@ const GPUList = () => {
handleInputChange={handleNameChange}
handleSelectChange={handleClusterChange}
selectOptions={clusterList}
showSelect={true}
showSelect={!clusterId}
></FilterBar>
<ConfigProvider renderEmpty={renderEmpty}>
<Table
+12 -3
View File
@@ -26,7 +26,15 @@ import UpdateLabels from './update-labels';
import WorkerDetailModal from './worker-detail-modal';
import WorkerRightActions from './worker-right-actions';
const Workers = () => {
// Optional ``clusterId`` pins the list to a single cluster (used by
// the cluster-detail page) and hides the cluster-filter dropdown so
// the user can't change scope away from the cluster they're already
// inside.
interface WorkersProps {
clusterId?: number;
}
const Workers: React.FC<WorkersProps> = ({ clusterId }) => {
const {
dataSource,
rowSelection,
@@ -50,7 +58,8 @@ const Workers = () => {
contentForDelete: 'resources.worker',
watch: true,
API: WORKERS_API,
updateManually: true
updateManually: true,
defaultQueryParams: clusterId ? { cluster_id: clusterId } : undefined
});
const { goToGrafana, ActionButton } = useGranfanaLink({
type: 'worker'
@@ -251,7 +260,7 @@ const Workers = () => {
<>
<PageBox>
<FilterBar
showSelect={true}
showSelect={!clusterId}
selectHolder={intl.formatMessage({ id: 'clusters.filterBy.cluster' })}
marginBottom={22}
marginTop={30}