fix: using select handler for provider hint
This commit is contained in:
@@ -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: {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user