import useAddWorkerMessage from '@/pages/cluster-management/hooks/use-add-worker-message'; import { useIntl } from '@umijs/max'; import React, { useMemo } from 'react'; import styled from 'styled-components'; import { ProviderType, ProviderValueMap } from '../../config'; import { ClusterListItem } from '../../config/types'; import { AddWorkerContext } from './add-worker-context'; import AddedMessage from './added-message'; import CheckEnvironment from './check-environment'; import { StepName, StepNamesMap } from './config'; import DockerRunCommand from './docker-run-command'; import K8sRunCommand from './k8s-run-command'; import SelectCluster from './select-cluster'; import SelectVendor from './select-vendor'; import SpecifyArguments from './specify-arguments'; import useSummaryStatus from './use-summary-status'; const Container = styled.div` margin: 0 auto; display: flex; flex-direction: column; gap: 16px; .command-info { margin-bottom: 8px; } `; /** * clusterList and onClusterChange are only required when from worker page. */ type AddWorkerProps = { actionSource?: 'modal' | 'page'; provider: ProviderType; clusterList?: Global.BaseOption[]; clusterLoading?: boolean; stepList: StepName[]; onClusterChange?: (value: number, row?: any) => void; onCancel?: () => void; registrationInfo: { token: string; image: string; server_url: string; cluster_id: number | null; [key: string]: any; }; }; /** * both add worker and register cluster use this component * @param props * @returns */ const AddWorkerSteps: React.FC = (props) => { const { actionSource, registrationInfo, provider, clusterList, clusterLoading, stepList = [], onCancel, onClusterChange } = props || {}; const intl = useIntl(); const [collapseKey, setCollapseKey] = React.useState>( new Set([stepList[0]]) ); const { update, summary, register } = useSummaryStatus(); const { addedCount, createModelsChunkRequest } = useAddWorkerMessage(); const onToggle = (open: boolean, key: string) => { setCollapseKey(open ? new Set([key]) : new Set()); }; const handleOnClusterChange = (value: number, row?: any) => { onClusterChange?.(value, row); }; React.useEffect(() => { // reset collapseKey when stepList changes setCollapseKey(new Set([stepList[0]])); }, [stepList]); React.useEffect(() => { // this effect is only triggered when used in cluster create page inner if (actionSource === 'page' && registrationInfo?.cluster_id) { createModelsChunkRequest({ cluster_id: registrationInfo?.cluster_id }); } }, [actionSource, registrationInfo?.cluster_id]); const disabled = useMemo(() => { return ( stepList.includes(StepNamesMap.SelectCluster) && !clusterList?.length ); }, [clusterList, stepList, StepNamesMap]); // Downstream steps (check env, run command, ...) only make sense after a // GPU vendor has been chosen. If the user toggled off every vendor in // multi-select, gate them shut so the wrong panel can't be opened. // Exception: for K8s clusters, Run Command is always accessible (CPU-only // workers don't need a GPU vendor). const selectedGPUs = (summary.get('selectedGPUs') as string[] | undefined) || []; const currentGPU = (summary.get('currentGPU') as string | undefined) || ''; const noVendorSelected = !currentGPU && selectedGPUs.length === 0; const isK8s = provider === ProviderValueMap.Kubernetes; // For non-K8s providers, all downstream steps are gated by vendor selection. // For K8s, both CheckEnv and RunCommand are always accessible — CheckEnv // shows a ready-nodes check when no vendor is selected (CPU-only workers). const downstreamDisabled = disabled || (noVendorSelected && !isK8s); React.useEffect(() => { // If the user just deselected everything on a non-K8s provider, collapse // any downstream panel back to the GPU step so they aren't left looking at // a stale disabled-but-open command. For K8s, CheckEnv stays open with a // ready-nodes check, so no collapsing needed. if (!noVendorSelected || isK8s) return; setCollapseKey((prev) => prev.has(StepNamesMap.SelectGPU) ? prev : new Set([StepNamesMap.SelectGPU]) ); }, [noVendorSelected, isK8s]); return ( {stepList.includes(StepNamesMap.SelectCluster) && ( )} {/* render the steps only when there is at least one cluster available or cluster selection is not required */} {((clusterList && clusterList.length > 0) || !stepList.includes(StepNamesMap.SelectCluster)) && ( <> {(isK8s || !noVendorSelected) && ( )} {provider === ProviderValueMap.Kubernetes && ( )} {provider === ProviderValueMap.Docker && ( <> )} )} {actionSource === 'modal' && ( // show in cluster create page inner )} ); }; export default AddWorkerSteps;