feat(cluster): drop detail page; host Cluster Access drawer

Remove the cluster-detail route and the name-link navigation; the
cluster name is now plain text. Mount the plugin-provided
clusterDetail.AccessDrawer so the enterprise row action can open it.
This commit is contained in:
jialin
2026-07-14 17:37:53 +08:00
committed by jialin
parent 046d466e16
commit 97179365bb
3 changed files with 17 additions and 42 deletions
+1 -11
View File
@@ -273,7 +273,7 @@ const baseRoutes = [
selectedIcon: 'icon-cluster2-filled',
defaultIcon: 'icon-cluster2-outline',
component: './cluster-management/clusters',
subMenu: ['/resources/clusters/detail', '/resources/clusters/create']
subMenu: ['/resources/clusters/create']
},
{
name: 'workers',
@@ -301,16 +301,6 @@ const baseRoutes = [
selectedIcon: 'icon-credential-filled',
defaultIcon: 'icon-credential-outline',
component: './cluster-management/credentials'
},
{
name: 'clusterDetail',
path: '/resources/clusters/detail',
key: 'clusterDetail',
icon: 'icon-cluster2-outline',
selectedIcon: 'icon-cluster2-filled',
defaultIcon: 'icon-cluster2-outline',
hideInMenu: true,
component: './cluster-management/cluster-detail'
}
]
},
+8 -11
View File
@@ -5,6 +5,7 @@ import type { PageActionType } from '@/config/types';
import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
import useTableFetch from '@/hooks/use-table-fetch';
import useWatchList from '@/hooks/use-watch-list';
import { getGPUStackPlugin } from '@/plugins';
import {
DeleteModal,
FilterBar,
@@ -14,7 +15,7 @@ import {
TableOrder,
TableProvider
} from '@gpustack/core-ui';
import { useIntl, useNavigate } from '@umijs/max';
import { useIntl } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { message } from 'antd';
import { useAtom } from 'jotai';
@@ -82,10 +83,13 @@ const Clusters: React.FC = () => {
mine: true
}
});
const navigate = useNavigate();
const { goToGrafana, ActionButton } = useGranfanaLink({
type: 'cluster'
});
// Cluster Access lives in the enterprise plugin: it contributes the
// row action and this self-controlled drawer, owning its own
// open/close state. OSS just mounts it (nothing without a plugin).
const AccessDrawer = getGPUStackPlugin()?.clusterDetail?.AccessDrawer;
const { watchDataList: allWorkerPoolList } = useWatchList(WORKER_POOLS_API);
const [expandAtom] = useAtom(expandKeysAtom);
const [clusterSession, setClusterSession] = useAtom(clusterSessionAtom);
@@ -272,14 +276,6 @@ const Clusters: React.FC = () => {
);
};
const handleOnCell = useMemoizedFn((record: ClusterListItem, dataIndex) => {
if (dataIndex === 'name') {
navigate(
`/resources/clusters/detail?id=${record.id}&name=${record.name}&page=clusters`
);
}
});
useEffect(() => {
const fetchCredentialList = async () => {
const data = await queryCredentialList({ page: -1 });
@@ -366,7 +362,7 @@ const Clusters: React.FC = () => {
);
};
const columns = useClusterColumns(handleSelect, handleOnCell);
const columns = useClusterColumns(handleSelect);
return (
<>
@@ -482,6 +478,7 @@ const Clusters: React.FC = () => {
onClose={handleClusterModalClose}
></ClusterModal>
{AddWorkerModal}
{AccessDrawer && <AccessDrawer />}
</>
);
};
@@ -13,7 +13,7 @@ import {
type TableColumnProps as SealColumnProps
} from '@gpustack/core-ui';
import { useIntl } from '@umijs/max';
import { Tooltip, Typography } from 'antd';
import { Tooltip } from 'antd';
import dayjs from 'dayjs';
import { useAtomValue } from 'jotai';
import { useMemo } from 'react';
@@ -85,21 +85,15 @@ const clusterActionList = [
];
const useClusterColumns = (
handleSelect: (val: string, record: ClusterListItem, item?: any) => void,
onCellClick?: (record: ClusterListItem, dataIndex: string) => void
handleSelect: (val: string, record: ClusterListItem, item?: any) => void
): SealColumnProps[] => {
const intl = useIntl();
const systemConfig = useAtomValue(systemConfigAtom);
const pluginCols = usePluginListColumns('clusters');
// The cluster-detail page is shipped in OSS source, but OSS keeps
// it unreachable from the cluster list — the link is only
// surfaced when a plugin opts in via
// `clusterDetail.linkableName`. Without a plugin we render the
// name as plain text (matches the pre-restore behaviour); with one
// we use Typography.Link wired to the parent's `onCellClick`.
const { linkableName: nameLinkable, useGenerateActions } =
getGPUStackPlugin()?.clusterDetail || {};
// The cluster name is plain text: there is no cluster-detail page
// to route into. A plugin may still contribute extra row actions
// (topology, Cluster Access) via `clusterDetail.useGenerateActions`.
const { useGenerateActions } = getGPUStackPlugin()?.clusterDetail || {};
const actionList =
useGenerateActions?.({ actions: clusterActionList }) || clusterActionList;
@@ -160,13 +154,7 @@ const useClusterColumns = (
render: (text: string, record: ClusterListItem) => (
<>
<AutoTooltip ghost title={text}>
{nameLinkable ? (
<Typography.Link onClick={() => onCellClick?.(record, 'name')}>
{record.name}
</Typography.Link>
) : (
<span className="text-primary">{record.name}</span>
)}
<span className="text-primary">{record.name}</span>
</AutoTooltip>
{record.is_default && (
<Tooltip
@@ -258,7 +246,7 @@ const useClusterColumns = (
)
}
];
}, [handleSelect, onCellClick, intl, pluginCols]);
}, [handleSelect, intl, pluginCols]);
};
export default useClusterColumns;