fix: no clusters tips in adding worker modal

This commit is contained in:
jialin
2026-01-06 17:21:32 +08:00
parent f8ae7680ad
commit 0ba8300959
18 changed files with 91 additions and 63 deletions
@@ -27,6 +27,12 @@ const CardStyled = styled(Card)`
}
}
}
&.disabled {
.ant-card-head {
cursor: not-allowed;
background-color: var(--ant-color-fill-quaternary) !important;
}
}
`;
const useStyles = createStyles(({ css, token }) => {
+2 -1
View File
@@ -115,5 +115,6 @@ export default {
'clusters.form.serverUrl.tips':
'Specify the server URL accessible from your cloud provider.',
'clusters.form.setDefault': 'Set as Default',
'clusters.form.setDefault.tips': 'Default for deployment.'
'clusters.form.setDefault.tips': 'Default for deployment.',
'clusters.addworker.noClusters': 'No available clusters'
};
+3 -1
View File
@@ -115,7 +115,8 @@ export default {
'clusters.form.serverUrl.tips':
'Specify the server URL accessible from your cloud provider.',
'clusters.form.setDefault': 'Set as Default',
'clusters.form.setDefault.tips': 'Default for deployment.'
'clusters.form.setDefault.tips': 'Default for deployment.',
'clusters.addworker.noClusters': 'No available clusters'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -209,4 +210,5 @@ export default {
// 84. 'clusters.form.setDefault.tips': 'Default for deployment',
// 85. 'clusters.addworker.enterWorkerAddress': 'Enter worker external address',
// 86. 'clusters.addworker.enterWorkerAddress.error': 'Please enter the worker external address.',
// 87. 'clusters.addworker.noClusters': 'No available clusters'
// ========== End of To-Do List ==========
+3 -1
View File
@@ -116,9 +116,11 @@ export default {
'Укажите URL сервера, доступный из вашего облачного провайдера.',
'clusters.form.setDefault': 'Установить по умолчанию',
'clusters.form.setDefault.tips':
'Использовать по умолчанию для развертывания.'
'Использовать по умолчанию для развертывания.',
'clusters.addworker.noClusters': 'No available clusters'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
// 1. 'clusters.addworker.hygonNotes': `If <span class="bold-text">/opt/hyhal</span> or <span class="bold-text">/opt/dtk</span> does not exist, create symbolic links pointing to the corresponding Hygon installation paths, for example: <span class="desc-fill">ln -s /path/to/hyhal /opt/hyhal</span> <span class="desc-fill">ln -s /path/to/dtk /opt/dtk</span>.`,
// 2. 'clusters.addworker.noClusters': 'No available clusters'
// ================================================================
+2 -1
View File
@@ -112,5 +112,6 @@ export default {
'clusters.table.ip.external': '外',
'clusters.form.serverUrl.tips': '指定可从您的云服务提供商访问的服务器地址。',
'clusters.form.setDefault': '设为默认',
'clusters.form.setDefault.tips': '部署时的默认集群。'
'clusters.form.setDefault.tips': '部署时的默认集群。',
'clusters.addworker.noClusters': '无可用集群'
};
@@ -3,7 +3,7 @@ import useAddWorkerMessage from '@/pages/cluster-management/hooks/use-add-worker
import { ExclamationCircleFilled } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Alert } from 'antd';
import React from 'react';
import React, { useMemo } from 'react';
import styled from 'styled-components';
import { ProviderType, ProviderValueMap } from '../../config';
import { ClusterListItem } from '../../config/types';
@@ -107,6 +107,12 @@ const AddWorkerSteps: React.FC<AddWorkerProps> = (props) => {
);
};
const disabled = useMemo(() => {
return (
stepList.includes(StepNamesMap.SelectCluster) && !clusterList?.length
);
}, [clusterList, stepList, StepNamesMap]);
return (
<AddWorkerContext.Provider
value={{
@@ -127,7 +133,7 @@ const AddWorkerSteps: React.FC<AddWorkerProps> = (props) => {
>
<Container>
{stepList.includes(StepNamesMap.SelectCluster) && (
<SelectCluster></SelectCluster>
<SelectCluster disabled={disabled}></SelectCluster>
)}
{stepList.includes(StepNamesMap.SelectCluster) &&
!clusterList?.length && (
@@ -141,22 +147,21 @@ const AddWorkerSteps: React.FC<AddWorkerProps> = (props) => {
})}
></AlertBlockInfo>
)}
{/* 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)) && (
<>
<SelectVendor></SelectVendor>
<CheckEnvironment></CheckEnvironment>
<SelectVendor disabled={disabled}></SelectVendor>
<CheckEnvironment disabled={disabled}></CheckEnvironment>
{provider === ProviderValueMap.Kubernetes && (
<K8sRunCommand></K8sRunCommand>
<K8sRunCommand disabled={disabled}></K8sRunCommand>
)}
{provider === ProviderValueMap.Docker && (
<>
<SpecifyArguments></SpecifyArguments>
<DockerRunCommand></DockerRunCommand>
<SpecifyArguments disabled={disabled}></SpecifyArguments>
<DockerRunCommand disabled={disabled}></DockerRunCommand>
</>
)}
</>
@@ -1,13 +1,13 @@
import { BulbOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Alert } from 'antd';
import { Alert, Typography } from 'antd';
import CheckEnvCommand from '../check-env-command';
import { useAddWorkerContext } from './add-worker-context';
import { StepNamesMap } from './config';
import { Tips, Title } from './constainers';
import { AddWorkerStepProps, StepNamesMap } from './config';
import { Title } from './constainers';
import StepCollapse from './step-collapse';
const CheckEnvironment = () => {
const CheckEnvironment: React.FC<AddWorkerStepProps> = ({ disabled }) => {
const { stepList, summary, provider } = useAddWorkerContext();
const intl = useIntl();
const currentGPU = summary.get('currentGPU');
@@ -21,6 +21,7 @@ const CheckEnvironment = () => {
return (
<StepCollapse
disabled={disabled}
name={StepNamesMap.CheckEnv}
title={
<Title>
@@ -47,9 +48,9 @@ const CheckEnvironment = () => {
></span>
}
></Alert>
<Tips style={{ marginBottom: 8, color: 'var(--ant-color-text)' }}>
<Typography.Paragraph style={{ marginBottom: 8 }}>
{intl.formatMessage({ id: 'cluster.create.checkEnv.tips' })}
</Tips>
</Typography.Paragraph>
<CheckEnvCommand provider={provider} currentGPU={currentGPU} />
</StepCollapse>
);
@@ -71,3 +71,7 @@ export type SummaryDataMap = {
};
export type SummaryDataKey = keyof SummaryDataKeys;
export interface AddWorkerStepProps {
disabled?: boolean;
}
@@ -48,7 +48,7 @@ export const SwitchWrapper = styled.div`
export const Tips = styled.div`
margin-top: 0px;
color: var(--ant-color-text-secondary);
color: var(--ant-color-text-tertiary);
`;
export const NotesWrapper = styled.ol`
@@ -1,13 +1,14 @@
import { useIntl } from '@umijs/max';
import { Typography } from 'antd';
import AddWorkerCommand from '../add-worker-command';
import { useAddWorkerContext } from './add-worker-context';
import { StepNamesMap } from './config';
import { Tips, Title } from './constainers';
import { AddWorkerStepProps, StepNamesMap } from './config';
import { Title } from './constainers';
import StepCollapse from './step-collapse';
import SummaryData from './summary-data';
import VendorNotes from './vendor-notes';
const DockerRunCommand = () => {
const DockerRunCommand: React.FC<AddWorkerStepProps> = ({ disabled }) => {
const intl = useIntl();
const { registrationInfo, stepList, summary } = useAddWorkerContext();
const workerIPConfig = summary.get('workerIPConfig') || {
@@ -44,6 +45,7 @@ const DockerRunCommand = () => {
return (
<StepCollapse
disabled={disabled}
name={StepNamesMap.RunCommand}
title={
<Title>
@@ -54,16 +56,15 @@ const DockerRunCommand = () => {
>
<SummaryData></SummaryData>
<VendorNotes></VendorNotes>
<Tips
<Typography.Paragraph
style={{
marginBottom: 8,
color: 'var(--ant-color-text)'
marginBottom: 8
}}
>
{intl.formatMessage({
id: 'clusters.create.addCommand.tips'
})}
</Tips>
</Typography.Paragraph>
<AddWorkerCommand
registrationInfo={registrationInfo}
advertisAddress={
@@ -1,11 +1,12 @@
import { useIntl } from '@umijs/max';
import { Typography } from 'antd';
import RegisterClusterInner from '../register-cluster-inner';
import { useAddWorkerContext } from './add-worker-context';
import { StepNamesMap } from './config';
import { Tips, Title } from './constainers';
import { AddWorkerStepProps, StepNamesMap } from './config';
import { Title } from './constainers';
import StepCollapse from './step-collapse';
const K8sRunCommand = () => {
const K8sRunCommand: React.FC<AddWorkerStepProps> = ({ disabled }) => {
const { registrationInfo, stepList } = useAddWorkerContext();
const intl = useIntl();
@@ -13,6 +14,7 @@ const K8sRunCommand = () => {
return (
<StepCollapse
disabled={disabled}
name={StepNamesMap.RunCommand}
title={
<Title>
@@ -21,16 +23,15 @@ const K8sRunCommand = () => {
</Title>
}
>
<Tips
<Typography.Paragraph
style={{
marginBottom: 8,
color: 'var(--ant-color-text)'
marginBottom: 8
}}
>
{intl.formatMessage({
id: 'clusters.create.addCommand.tips'
})}
</Tips>
</Typography.Paragraph>
<RegisterClusterInner registrationInfo={registrationInfo} />
</StepCollapse>
);
@@ -1,7 +1,7 @@
import { useIntl } from '@umijs/max';
import { Input, Switch } from 'antd';
import React from 'react';
import { SwitchWrapper, Tips } from './constainers';
import { SwitchWrapper } from './constainers';
const NetworkConfig = () => {
const intl = useIntl();
@@ -28,9 +28,6 @@ const NetworkConfig = () => {
}
></Switch>
</div>
<Tips>
Enter the NIC name to use for distributed inference (e.g., mlx5_0).
</Tips>
{networkInterface.enable && (
<>
<Input
@@ -1,13 +1,13 @@
import BaseSelect from '@/components/seal-form/base/select';
import { useIntl } from '@umijs/max';
import { Spin } from 'antd';
import { Spin, Typography } from 'antd';
import { useEffect } from 'react';
import { useAddWorkerContext } from './add-worker-context';
import { StepNamesMap } from './config';
import { AddWorkerStepProps, StepNamesMap } from './config';
import { Title } from './constainers';
import StepCollapse from './step-collapse';
const SelectCluster = () => {
const SelectCluster: React.FC<AddWorkerStepProps> = ({ disabled }) => {
const {
clusterList,
clusterLoading,
@@ -42,6 +42,7 @@ const SelectCluster = () => {
return (
<StepCollapse
disabled={disabled}
name={StepNamesMap.SelectCluster}
title={
<div>
@@ -65,6 +66,11 @@ const SelectCluster = () => {
onChange={onClusterChange}
style={{ width: '100%' }}
/>
{!clusterLoading && !clusterList?.length && (
<Typography.Text type="danger">
{intl.formatMessage({ id: 'clusters.addworker.noClusters' })}
</Typography.Text>
)}
</Spin>
</StepCollapse>
);
@@ -6,11 +6,11 @@ import { useIntl } from '@umijs/max';
import React, { useEffect } from 'react';
import SupportedGPUs from '../support-gpus';
import { useAddWorkerContext } from './add-worker-context';
import { StepNamesMap } from './config';
import { AddWorkerStepProps, StepNamesMap } from './config';
import { Title } from './constainers';
import StepCollapse from './step-collapse';
const SelectVendor = () => {
const SelectVendor: React.FC<AddWorkerStepProps> = ({ disabled }) => {
const { stepList, registerField, updateField } = useAddWorkerContext();
const intl = useIntl();
@@ -52,6 +52,7 @@ const SelectVendor = () => {
return (
<StepCollapse
disabled={disabled}
name={StepNamesMap.SelectGPU}
title={
<Title>
@@ -1,12 +1,12 @@
import AlertInfoBlock from '@/components/alert-info/block';
import { ExclamationCircleFilled } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Input, Switch } from 'antd';
import { Input, Switch, Typography } from 'antd';
import React, { useEffect } from 'react';
import styled from 'styled-components';
import { useAddWorkerContext } from './add-worker-context';
import { StepNamesMap } from './config';
import { NotesWrapper, SwitchWrapper, Tips, Title } from './constainers';
import { AddWorkerStepProps, StepNamesMap } from './config';
import { NotesWrapper, SwitchWrapper, Title } from './constainers';
import StepCollapse from './step-collapse';
const ButtonWrapper = styled.div`
@@ -47,14 +47,16 @@ const SwitchSetting: React.FC<{
{showSwitch && <Switch checked={checked} onChange={onChange}></Switch>}
</ButtonWrapper>
{tips && (
<Tips
dangerouslySetInnerHTML={{
__html: tips
}}
></Tips>
<Typography.Text type="secondary">
<div
dangerouslySetInnerHTML={{
__html: tips
}}
></div>
</Typography.Text>
)}
{checked && (
<>
<div>
<Input
style={{ width: '100%' }}
value={value}
@@ -62,22 +64,16 @@ const SwitchSetting: React.FC<{
onChange={(e) => onInputChange?.(e.target.value)}
/>
{errorMessage && (
<Tips
style={{
color: 'var(--ant-color-error)'
}}
>
{errorMessage}
</Tips>
<Typography.Text type="danger">{errorMessage}</Typography.Text>
)}
</>
</div>
)}
{extra}
</SwitchWrapper>
);
};
const SpecifyArguments = () => {
const SpecifyArguments: React.FC<AddWorkerStepProps> = ({ disabled }) => {
const intl = useIntl();
const { stepList, summary, updateField, registerField } =
useAddWorkerContext();
@@ -215,6 +211,7 @@ const SpecifyArguments = () => {
return (
<StepCollapse
disabled={disabled}
beforeNext={beforeNext}
name={StepNamesMap.SpecifyArgs}
title={
@@ -9,6 +9,7 @@ interface StepItemProps {
title: React.ReactNode;
children?: React.ReactNode;
name: string;
disabled?: boolean;
beforeNext?: () => Promise<boolean> | void;
}
@@ -39,6 +40,7 @@ const StepCollapse: React.FC<StepItemProps> = ({
title,
children,
name = '',
disabled = false,
beforeNext = async () => true,
...rest
}) => {
@@ -82,6 +84,7 @@ const StepCollapse: React.FC<StepItemProps> = ({
}
}}
title={title}
disabled={disabled}
onToggle={(open) => onToggle?.(open, name || '')}
{...rest}
>
@@ -95,7 +98,7 @@ const StepCollapse: React.FC<StepItemProps> = ({
)}
{!isLastStep && (
<Button type="primary" onClick={handleOnNext}>
<Button type="primary" onClick={handleOnNext} disabled={disabled}>
{intl.formatMessage({ id: 'common.button.next' })}
</Button>
)}
@@ -7,7 +7,7 @@ type AddModalProps = {
token: string;
image: string;
server_url: string;
cluster_id: number;
cluster_id: number | null;
};
};
const AddCluster: React.FC<AddModalProps> = ({ registrationInfo }) => {
@@ -98,7 +98,7 @@ const SupportedHardware: React.FC<SupportedHardwareProps> = ({
icon: (
<IconFont
type="icon-amd-logo"
style={{ fontSize: 60, color: 'var(--ant-color-text)' }}
style={{ fontSize: 64, color: 'var(--ant-color-text)' }}
/>
)
},