style: use drawer for adding worker

This commit is contained in:
jialin
2026-01-06 17:21:32 +08:00
parent 0eba1da6c4
commit 8f9fae9210
10 changed files with 118 additions and 108 deletions
+9 -1
View File
@@ -116,5 +116,13 @@ export default {
'Specify the server URL accessible from your cloud provider.', 'Specify the server URL accessible from your cloud provider.',
'clusters.form.setDefault': 'Set as Default', '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' 'clusters.addworker.noClusters': 'No available clusters',
'clusters.create.complete.tips': 'Cluster created successfully!',
'clusters.create.complete': 'Completed',
'clusters.create.dockerTips1': 'Next, add worker to this cluster.',
'clusters.create.dockerTips2':
'You can also skip this step and add them later from the cluster list.',
'clusters.create.k8sTips1': 'Next, register existing Kubernetes cluster.',
'clusters.create.k8sTips2':
'You can also skip this step and register it later from the cluster list.'
}; };
+16 -2
View File
@@ -116,7 +116,15 @@ export default {
'Specify the server URL accessible from your cloud provider.', 'Specify the server URL accessible from your cloud provider.',
'clusters.form.setDefault': 'Set as Default', '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' 'clusters.addworker.noClusters': 'No available clusters',
'clusters.create.complete.tips': 'Cluster created successfully!',
'clusters.create.complete': 'Completed',
'clusters.create.dockerTips1': 'Next, add worker to this cluster.',
'clusters.create.dockerTips2':
'You can also skip this step and add them later from the cluster list.',
'clusters.create.k8sTips1': 'Next, register existing Kubernetes cluster.',
'clusters.create.k8sTips2':
'You can also skip this step and register it later from the cluster list.'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -210,5 +218,11 @@ export default {
// 84. 'clusters.form.setDefault.tips': 'Default for deployment', // 84. 'clusters.form.setDefault.tips': 'Default for deployment',
// 85. 'clusters.addworker.enterWorkerAddress': 'Enter worker external address', // 85. 'clusters.addworker.enterWorkerAddress': 'Enter worker external address',
// 86. 'clusters.addworker.enterWorkerAddress.error': 'Please enter the worker external address.', // 86. 'clusters.addworker.enterWorkerAddress.error': 'Please enter the worker external address.',
// 87. 'clusters.addworker.noClusters': 'No available clusters' // 87. 'clusters.addworker.noClusters': 'No available clusters',
// 88. 'clusters.create.complete.tips': 'Cluster created successfully!',
// 89. 'clusters.create.complete': 'Completed',
// 90. 'clusters.create.dockerTips1': 'Next, add worker to this cluster.',
// 91. 'clusters.create.dockerTips2': 'You can also skip this step and add them later from the cluster list.',
// 92. 'clusters.create.k8sTips1': 'Next, register existing Kubernetes cluster.',
// 93. 'clusters.create.k8sTips2': 'You can also skip this step and register it later from the cluster list.'
// ========== End of To-Do List ========== // ========== End of To-Do List ==========
+16 -2
View File
@@ -117,10 +117,24 @@ export default {
'clusters.form.setDefault': 'Установить по умолчанию', 'clusters.form.setDefault': 'Установить по умолчанию',
'clusters.form.setDefault.tips': 'clusters.form.setDefault.tips':
'Использовать по умолчанию для развертывания.', 'Использовать по умолчанию для развертывания.',
'clusters.addworker.noClusters': 'No available clusters' 'clusters.addworker.noClusters': 'No available clusters',
'clusters.create.complete.tips': 'Cluster created successfully!',
'clusters.create.complete': 'Completed',
'clusters.create.dockerTips1': 'Next, add worker to this cluster.',
'clusters.create.dockerTips2':
'You can also skip this step and add them later from the cluster list.',
'clusters.create.k8sTips1': 'Next, register existing Kubernetes cluster.',
'clusters.create.k8sTips2':
'You can also skip this step and register it later from the cluster list.'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== 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>.`, // 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. 'clusters.addworker.noClusters': 'No available clusters',
// 3. 'clusters.create.complete.tips': 'Cluster created successfully!',
// 4. 'clusters.create.complete': 'Completed',
// 5. 'clusters.create.dockerTips1': 'Next, add worker to this cluster.',
// 6. 'clusters.create.dockerTips2': 'You can also skip this step and add them later from the cluster list.',
// 7. 'clusters.create.k8sTips1': 'Next, register existing Kubernetes cluster.',
// 8. 'clusters.create.k8sTips2': 'You can also skip this step and register it later from the cluster list.'
// ================================================================ // ================================================================
+7 -1
View File
@@ -113,5 +113,11 @@ export default {
'clusters.form.serverUrl.tips': '指定可从您的云服务提供商访问的服务器地址。', 'clusters.form.serverUrl.tips': '指定可从您的云服务提供商访问的服务器地址。',
'clusters.form.setDefault': '设为默认', 'clusters.form.setDefault': '设为默认',
'clusters.form.setDefault.tips': '部署时的默认集群。', 'clusters.form.setDefault.tips': '部署时的默认集群。',
'clusters.addworker.noClusters': '无可用集群' 'clusters.addworker.noClusters': '无可用集群',
'clusters.create.complete.tips': '集群创建成功!',
'clusters.create.complete': '完成',
'clusters.create.dockerTips1': '接下来,为该集群添加节点。',
'clusters.create.dockerTips2': '你也可以跳过此步骤,稍后在集群列表中添加。',
'clusters.create.k8sTips1': '接下来,注册已有的 Kubernetes 集群。',
'clusters.create.k8sTips2': '你也可以跳过此步骤,稍后在集群列表中进行注册。'
}; };
@@ -3,7 +3,6 @@ import { PageAction } from '@/config';
import { PageActionType } from '@/config/types'; import { PageActionType } from '@/config/types';
import ColumnWrapper from '@/pages/_components/column-wrapper'; import ColumnWrapper from '@/pages/_components/column-wrapper';
import { useIntl, useSearchParams } from '@umijs/max'; import { useIntl, useSearchParams } from '@umijs/max';
import { Typography } from 'antd';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import _ from 'lodash'; import _ from 'lodash';
import React, { useEffect, useMemo, useRef, useState } from 'react'; import React, { useEffect, useMemo, useRef, useState } from 'react';
@@ -30,8 +29,6 @@ import useSystemConfig from './services/use-system-config';
import { moduleMap, moduleRegistry } from './step-forms/module-registry'; import { moduleMap, moduleRegistry } from './step-forms/module-registry';
import useStepList from './step-forms/use-step-list'; import useStepList from './step-forms/use-step-list';
const { Title, Text } = Typography;
const Container = styled.div` const Container = styled.div`
width: 100%; width: 100%;
display: flex; display: flex;
@@ -1,4 +1,5 @@
import ScrollerModal from '@/components/scroller-modal'; import GSDrawer from '@/components/scroller-modal/gs-drawer';
import ColumnWrapper from '@/pages/_components/column-wrapper';
import useAddWorkerMessage from '@/pages/cluster-management/hooks/use-add-worker-message'; import useAddWorkerMessage from '@/pages/cluster-management/hooks/use-add-worker-message';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Alert } from 'antd'; import { Alert } from 'antd';
@@ -118,46 +119,55 @@ const AddWorker: React.FC<AddWorkerProps> = (props) => {
}; };
return ( return (
<ScrollerModal <GSDrawer
title={title} title={title}
open={open} open={open}
centered={true} onClose={onCancel}
onCancel={onCancel}
destroyOnHidden={true} destroyOnHidden={true}
closeIcon={true} closeIcon={false}
maskClosable={false} maskClosable={false}
keyboard={false} keyboard={false}
width={865} styles={{
style={{}} body: {
maxContentHeight={'max(calc(100vh - 200px), 600px)'} paddingBlock: 0
footer={ },
<Footer> wrapper: { width: 865 }
{addedCount > 0 && ( }}
<Alert footer={false}
style={{
textAlign: 'left',
borderColor: 'var(--ant-color-success)',
width: '100%'
}}
type="success"
title={renderMessage(addedCount)}
closable
/>
)}
</Footer>
}
> >
<AddWorkerStep <ColumnWrapper
onCancel={onCancel} styles={{
actionSource={'modal'} container: { paddingBlock: 16 }
stepList={stepList} }}
provider={provider} footer={
clusterList={clusterList} <Footer style={{ paddingInline: 24, paddingBottom: 24 }}>
clusterLoading={clusterLoading} {addedCount > 0 && (
onClusterChange={handleOnClusterChange} <Alert
registrationInfo={registrationInfo} style={{
></AddWorkerStep> textAlign: 'left',
</ScrollerModal> borderColor: 'var(--ant-color-success)',
width: '100%'
}}
type="success"
title={renderMessage(addedCount)}
closable
/>
)}
</Footer>
}
>
<AddWorkerStep
onCancel={onCancel}
actionSource={'modal'}
stepList={stepList}
provider={provider}
clusterList={clusterList}
clusterLoading={clusterLoading}
onClusterChange={handleOnClusterChange}
registrationInfo={registrationInfo}
></AddWorkerStep>
</ColumnWrapper>
</GSDrawer>
); );
}; };
@@ -1,4 +1,5 @@
import { CheckCircleFilled } from '@ant-design/icons'; import { CheckCircleFilled } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Flex, Result } from 'antd'; import { Button, Flex, Result } from 'antd';
import React from 'react'; import React from 'react';
import { ProviderValueMap } from '../config'; import { ProviderValueMap } from '../config';
@@ -8,14 +9,19 @@ const SuccessResult: React.FC<{
onSkip: () => void; onSkip: () => void;
onAddWorker: () => void; onAddWorker: () => void;
}> = ({ provider, onSkip, onAddWorker }) => { }> = ({ provider, onSkip, onAddWorker }) => {
const k8sTips = const intl = useIntl();
'Next, register this Kubernetes cluster. You can also skip this step and register it later from the cluster list.';
const k8sTips = (
<div className="flex-column">
<span>{intl.formatMessage({ id: 'clusters.create.k8sTips1' })}</span>
<span>{intl.formatMessage({ id: 'clusters.create.k8sTips2' })}</span>
</div>
);
const dockerTips = ( const dockerTips = (
<div className="flex-column"> <div className="flex-column">
<span>Next, add worker to this cluster.</span> <span>{intl.formatMessage({ id: 'clusters.create.dockerTips1' })}</span>
<span> <span>{intl.formatMessage({ id: 'clusters.create.dockerTips2' })}</span>
You can also skip this step and add them later from the cluster list.
</span>
</div> </div>
); );
@@ -33,17 +39,17 @@ const SuccessResult: React.FC<{
/> />
} }
status="success" status="success"
title="Cluster Created Successfully!" title={intl.formatMessage({ id: 'clusters.create.complete.tips' })}
subTitle={provider === ProviderValueMap.Kubernetes ? k8sTips : dockerTips} subTitle={provider === ProviderValueMap.Kubernetes ? k8sTips : dockerTips}
extra={[ extra={[
<Flex gap={16} justify="center" key="buttons"> <Flex gap={16} justify="center" key="buttons">
<Button key="buy" onClick={onSkip}> <Button key="skip" onClick={onSkip}>
Skip for now {intl.formatMessage({ id: 'clusters.create.skipfornow' })}
</Button> </Button>
<Button type="primary" key="console" onClick={onAddWorker}> <Button type="primary" key="add" onClick={onAddWorker}>
{provider === ProviderValueMap.Kubernetes {provider === ProviderValueMap.Kubernetes
? 'Register Cluster' ? intl.formatMessage({ id: 'clusters.button.register' })
: 'Add Worker'} : intl.formatMessage({ id: 'resources.button.create' })}
</Button> </Button>
</Flex> </Flex>
]} ]}
@@ -110,7 +110,7 @@ const SupportedHardware: React.FC<SupportedHardwareProps> = ({
locale: false, locale: false,
notes: AddWorkerDockerNotes[GPUDriverMap.ASCEND], notes: AddWorkerDockerNotes[GPUDriverMap.ASCEND],
link: 'https://docs.gpustack.ai/latest/installation/requirements/#ascend-npu', link: 'https://docs.gpustack.ai/latest/installation/requirements/#ascend-npu',
icon: <ProviderImage src={ascendLogo} height={32} /> icon: <ProviderImage src={ascendLogo} height={30} />
}, },
{ {
label: intl.formatMessage({ id: 'vendor.hygon' }), label: intl.formatMessage({ id: 'vendor.hygon' }),
@@ -121,7 +121,7 @@ const SupportedHardware: React.FC<SupportedHardwareProps> = ({
locale: false, locale: false,
notes: AddWorkerDockerNotes[GPUDriverMap.HYGON], notes: AddWorkerDockerNotes[GPUDriverMap.HYGON],
link: 'https://docs.gpustack.ai/latest/installation/requirements/#hygon-dcu', link: 'https://docs.gpustack.ai/latest/installation/requirements/#hygon-dcu',
icon: <ProviderImage src={hyponPNG} height={20} /> icon: <ProviderImage src={hyponPNG} height={18} />
}, },
{ {
label: intl.formatMessage({ id: 'vendor.moorthreads' }), label: intl.formatMessage({ id: 'vendor.moorthreads' }),
@@ -133,7 +133,7 @@ const SupportedHardware: React.FC<SupportedHardwareProps> = ({
locale: false, locale: false,
notes: AddWorkerDockerNotes[GPUDriverMap.MOORE_THREADS], notes: AddWorkerDockerNotes[GPUDriverMap.MOORE_THREADS],
link: 'https://docs.gpustack.ai/latest/installation/requirements/#mthreads-gpu', link: 'https://docs.gpustack.ai/latest/installation/requirements/#mthreads-gpu',
icon: <ProviderImage src={mooreLogo} height={26} /> icon: <ProviderImage src={mooreLogo} height={24} />
}, },
{ {
label: intl.formatMessage({ id: 'vendor.iluvatar' }), label: intl.formatMessage({ id: 'vendor.iluvatar' }),
@@ -145,7 +145,7 @@ const SupportedHardware: React.FC<SupportedHardwareProps> = ({
locale: false, locale: false,
notes: AddWorkerDockerNotes[GPUDriverMap.ILUVATAR], notes: AddWorkerDockerNotes[GPUDriverMap.ILUVATAR],
link: 'https://docs.gpustack.ai/latest/installation/requirements/#iluvatar-gpu', link: 'https://docs.gpustack.ai/latest/installation/requirements/#iluvatar-gpu',
icon: <ProviderImage src={iluvatarWEBP} height={26} /> icon: <ProviderImage src={iluvatarWEBP} height={24} />
}, },
{ {
label: intl.formatMessage({ id: 'vendor.cambricon' }), label: intl.formatMessage({ id: 'vendor.cambricon' }),
@@ -157,7 +157,7 @@ const SupportedHardware: React.FC<SupportedHardwareProps> = ({
locale: false, locale: false,
notes: AddWorkerDockerNotes[GPUDriverMap.CAMBRICON], notes: AddWorkerDockerNotes[GPUDriverMap.CAMBRICON],
link: 'https://docs.gpustack.ai/latest/installation/requirements/#cambricon-mlu', link: 'https://docs.gpustack.ai/latest/installation/requirements/#cambricon-mlu',
icon: <ProviderImage src={CambriconPNG} height={26} /> icon: <ProviderImage src={CambriconPNG} height={24} />
}, },
{ {
label: intl.formatMessage({ id: 'vendor.metax' }), label: intl.formatMessage({ id: 'vendor.metax' }),
@@ -1,8 +1,4 @@
import { import { resourceOverviewAtom } from '@/atoms/models';
clusterListAtom,
resourceOverviewAtom,
workerListAtom
} from '@/atoms/models';
import { queryClusterList } from '@/pages/cluster-management/apis'; import { queryClusterList } from '@/pages/cluster-management/apis';
import { queryWorkersList } from '@/pages/resources/apis'; import { queryWorkersList } from '@/pages/resources/apis';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
@@ -15,28 +11,6 @@ import { queryDashboardData } from '../../dashboard/apis';
* @returns * @returns
*/ */
export default function useClusterList() { export default function useClusterList() {
const [clusterList, setClusterList] = useState<
{
label: string;
value: number;
id: number;
state: string;
provider: string;
}[]
>([]);
const [workerList, setWorkerList] = useState<
{
cluster_id: number;
state: string;
label: string;
value: number;
id: number;
labels: { [key: string]: string };
name: string;
}[]
>([]);
const [clustersAtom, setClusterListAtom] = useAtom(clusterListAtom);
const [workersAtom, setWorkerListAtom] = useAtom(workerListAtom);
const [resourceAtom, setResourceOverview] = useAtom(resourceOverviewAtom); const [resourceAtom, setResourceOverview] = useAtom(resourceOverviewAtom);
const [resourceCount, setResourceCount] = useState<Record<string, any>>({ const [resourceCount, setResourceCount] = useState<Record<string, any>>({
cluster_count: 0, cluster_count: 0,
@@ -77,21 +51,6 @@ export default function useClusterList() {
} }
}; };
const fetchData = async () => {
const [clusters, workers] = await Promise.all([
fetchClusterList(),
fetchWorkerList()
]);
setClusterList(clusters);
setWorkerList(workers);
setClusterListAtom(clusters);
setWorkerListAtom(workers);
return {
hasClusters: clusters.length > 0,
hasWorkers: workers.length > 0
};
};
const fetchResource = async () => { const fetchResource = async () => {
try { try {
const res = await queryDashboardData(); const res = await queryDashboardData();
@@ -112,10 +71,6 @@ export default function useClusterList() {
}; };
return { return {
clusterList,
workerList,
clustersAtom,
workersAtom,
resourceAtom, resourceAtom,
resourceCount, resourceCount,
fetchResource, fetchResource,
@@ -72,7 +72,7 @@ export default function useStepList() {
beforeNext: handleBack beforeNext: handleBack
}, },
{ {
title: 'Completed', title: intl.formatMessage({ id: 'clusters.create.complete' }),
content: '', content: '',
description: '', description: '',
showButtons: (provider?: ProviderType) => { showButtons: (provider?: ProviderType) => {