diff --git a/src/pages/cluster-management/cluster-create.tsx b/src/pages/cluster-management/cluster-create.tsx index 30832691..af4358bb 100644 --- a/src/pages/cluster-management/cluster-create.tsx +++ b/src/pages/cluster-management/cluster-create.tsx @@ -5,7 +5,13 @@ import { ColumnWrapper } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { useAtom } from 'jotai'; import _ from 'lodash'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import React, { + useEffect, + useLayoutEffect, + useMemo, + useRef, + useState +} from 'react'; import styled from 'styled-components'; import { createCluster, @@ -55,9 +61,6 @@ const MainWrapper = styled.div` const ClusterCreate: React.FC<{ action: PageActionType; - // Preselect a provider and skip the provider-catalog step. Set by - // empty-state CTAs that already know which kind of cluster the user - // is heading for (e.g. GPU Service's "Add a Kubernetes Cluster"). providerHint?: string; setCurrentTitle?: (title: string) => void; onClose?: () => void; @@ -68,9 +71,7 @@ const ClusterCreate: React.FC<{ const [credentialList, setCredentialList] = useState< Global.BaseOption[] >([]); - // When the caller already picked a provider for us, start one step - // in — provider catalog is step 0; configure is step 1. - const [currentStep, setCurrentStep] = useState(providerHint ? 1 : 0); + const [currentStep, setCurrentStep] = useState(0); const [registrationInfo, setRegistrationInfo] = useState<{ token: string; image: string; @@ -84,7 +85,7 @@ const ClusterCreate: React.FC<{ cluster_id: 0 }); const [extraData, setExtraData] = useState({ - provider: (providerHint as ProviderType) ?? ProviderValueMap.Docker + provider: ProviderValueMap.Docker } as ClusterFormData); const [formValues, setFormValues] = useState>({}); const [submitLoading, setSubmitLoading] = useState(false); @@ -217,6 +218,12 @@ const ClusterCreate: React.FC<{ fetchData(); }, []); + useLayoutEffect(() => { + if (providerHint) { + handleSelectProvider(providerHint); + } + }, [providerHint]); + const renderForms = () => { const step = steps[currentStep]; const formKeys = step?.showForms || []; @@ -331,7 +338,11 @@ const ClusterCreate: React.FC<{ {!isAddWorkerStep && ( - + )}
{currentStep === 0 && ( - // Catalog belongs to step 0 only. The previous gate used - // ``startStep`` which is 1 when ``providerHint`` skips the - // catalog — that wrongly re-rendered it on top of the - // configure form for entry points like "Add a Kubernetes - // Cluster". void; steps: any[]; + selectedProvider?: ProviderType; }> = (props) => { const { steps, currentStep = 0, onChange } = props; - // Pick only props antd's Step accepts — the upstream step objects carry - // custom keys (showModules/showForms/showButtons/...) that would otherwise - // be forwarded to the DOM and trigger "React does not recognize the X - // prop on a DOM element" warnings. _.pick keeps missing keys missing - // (rather than explicitly `undefined`) so antd's defaults still kick in. const visibleSteps = steps .filter((step) => !step.hideInSteps) - .map((step) => _.pick(step, ANTD_STEP_KEYS)); + .map((step, index) => { + return { + ..._.pick(step, ANTD_STEP_KEYS), + subTitle: index === 0 ? [{props.selectedProvider}] : '' + }; + }); const styles: Record = { root: { diff --git a/src/pages/gpu-service/instances/index.tsx b/src/pages/gpu-service/instances/index.tsx index 12342a63..c7e3af71 100644 --- a/src/pages/gpu-service/instances/index.tsx +++ b/src/pages/gpu-service/instances/index.tsx @@ -97,14 +97,10 @@ const GPUService: React.FC = () => { fetchClusterList({ page: -1 }); }, []); - // GPU Service today is Kubernetes-only — Docker / cloud clusters - // can't host the CRDs. Filter so the page reflects scheduling - // reality even when the caller owns non-K8s clusters. - const k8sClusterList = useMemo( - () => clusterList.filter((c) => c.provider === ProviderValueMap.Kubernetes), + const hasK8sCluster = useMemo( + () => clusterList.some((c) => c.provider === ProviderValueMap.Kubernetes), [clusterList] ); - const hasK8sCluster = k8sClusterList.length > 0; const handleModalOk = async (data: FormData) => { try { @@ -157,11 +153,6 @@ const GPUService: React.FC = () => { const renderEmpty = (type?: string) => { if (type !== 'Table') return; - // No K8s cluster the caller can schedule on — replace the "no - // instances" empty state with a cluster-bootstrap prompt. The - // "Add cluster" CTA is reserved for callers who can actually - // create one (platform admin / Org owner); members see the - // explanation without a misleading button. if (!clusterLoading && !hasK8sCluster) { return (