fix: using select handler for provider hint

This commit is contained in:
jialin
2026-05-27 17:10:15 +08:00
committed by jialin
parent 11cf1329c8
commit 3497590d2e
3 changed files with 45 additions and 37 deletions
+20 -14
View File
@@ -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<number, { provider: ProviderType }>[]
>([]);
// 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<number>(providerHint ? 1 : 0);
const [currentStep, setCurrentStep] = useState<number>(0);
const [registrationInfo, setRegistrationInfo] = useState<{
token: string;
image: string;
@@ -84,7 +85,7 @@ const ClusterCreate: React.FC<{
cluster_id: 0
});
const [extraData, setExtraData] = useState<ClusterFormData>({
provider: (providerHint as ProviderType) ?? ProviderValueMap.Docker
provider: ProviderValueMap.Docker
} as ClusterFormData);
const [formValues, setFormValues] = useState<Record<string, any>>({});
const [submitLoading, setSubmitLoading] = useState<boolean>(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<{
<MainWrapper>
{!isAddWorkerStep && (
<StepWrapper>
<ClusterSteps steps={steps} currentStep={currentStep}></ClusterSteps>
<ClusterSteps
steps={steps}
currentStep={currentStep}
selectedProvider={extraData.provider}
></ClusterSteps>
</StepWrapper>
)}
<ColumnWrapper
@@ -357,11 +368,6 @@ const ClusterCreate: React.FC<{
>
<div style={{ flex: 1 }}>
{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".
<ProviderCatalog
cols={2}
dataList={providerList}
@@ -1,13 +1,18 @@
import { Steps } from 'antd';
import { Steps, Typography } from 'antd';
import _ from 'lodash';
import React from 'react';
import styled from 'styled-components';
import { ProviderType } from '../config';
// `description` is intentionally omitted: the upstream step list ships
// hardcoded English copy that isn't translated. Keeping it would cause the
// step to render both the localized title and the English description side
// by side. Same reason we don't surface `subTitle`.
const ANTD_STEP_KEYS = ['title', 'icon', 'status', 'disabled'] as const;
const { Text } = Typography;
const ANTD_STEP_KEYS = [
'title',
'icon',
'status',
'disabled',
'subTitle'
] as const;
const Wrapper = styled.div`
display: flex;
@@ -31,6 +36,11 @@ const Box = styled.div`
.ant-steps-item-rail-wait {
--steps-item-solid-line-color: var(--ant-color-split);
}
.ant-steps-item-subtitle {
margin-left: 6px;
font-size: 13px;
color: var(--ant-color-text-tertiary);
}
&:not(.ant-steps-panel) {
.ant-steps-item-finish {
--steps-item-icon-bg-color: var(--ant-color-primary);
@@ -43,17 +53,18 @@ const ClusterSteps: React.FC<{
currentStep: number;
onChange?: (step: number) => 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 ? <span>[{props.selectedProvider}]</span> : ''
};
});
const styles: Record<string, any> = {
root: {
+2 -11
View File
@@ -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 (
<NoResult