refactor: create cluster by steps
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
import { PageAction } from '@/config';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import { PageContainer } from '@ant-design/pro-components';
|
||||
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { queryClusterList } from './apis';
|
||||
import ClusterSteps from './components/cluster-steps';
|
||||
import FooterButtons from './components/footer-buttons';
|
||||
import ProviderCatalog from './components/provider-catalog';
|
||||
import { providerList, ProviderType } from './config';
|
||||
import { ClusterFormData } from './config/types';
|
||||
import { moduleMap, moduleRegistry } from './step-forms/module-registry';
|
||||
import useStepList from './step-forms/use-step-list';
|
||||
|
||||
const Container = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const Content = styled.div`
|
||||
width: 600px;
|
||||
`;
|
||||
|
||||
const HeaderContainer = styled.div`
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
align-items: center;
|
||||
padding-inline: var(--layout-content-header-inlinepadding);
|
||||
border-bottom: 1px solid var(--ant-color-split);
|
||||
min-height: 72px;
|
||||
.text {
|
||||
margin-right: 16px;
|
||||
padding-right: 16px;
|
||||
border-right: 1px solid var(--ant-color-split);
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
margin-right: 32px;
|
||||
}
|
||||
`;
|
||||
|
||||
const ClusterCreate = () => {
|
||||
const intl = useIntl();
|
||||
const stepList = useStepList();
|
||||
const [searchParams] = useSearchParams();
|
||||
const action =
|
||||
(searchParams.get('action') as PageActionType) || PageAction.CREATE;
|
||||
const navigate = useNavigate();
|
||||
const [credentialList, setCredentialList] = useState<
|
||||
Global.BaseOption<number>[]
|
||||
>([]);
|
||||
const [currentStep, setCurrentStep] = useState<number>(0);
|
||||
const [registrationInfo, setRegistrationInfo] = useState<{
|
||||
token: string;
|
||||
image: string;
|
||||
server_url: string;
|
||||
cluster_id: number;
|
||||
}>({
|
||||
token: '',
|
||||
image: '',
|
||||
server_url: '',
|
||||
cluster_id: 0
|
||||
});
|
||||
const [extraData, setExtraData] = useState<ClusterFormData>({
|
||||
provider: null
|
||||
} as ClusterFormData);
|
||||
const [formValues, setFormValues] = useState<Record<string, any>>({});
|
||||
|
||||
const formRefs: Record<string, any> = {
|
||||
[moduleMap.BasicForm]: useRef<any>(null),
|
||||
[moduleMap.WorkerPoolForm]: useRef<any>(null)
|
||||
};
|
||||
|
||||
const steps = useMemo(() => {
|
||||
if (!extraData.provider) {
|
||||
return stepList.filter((step) => step.defaultShow);
|
||||
}
|
||||
|
||||
return stepList
|
||||
.filter((step) =>
|
||||
step.providers?.length
|
||||
? step.providers.includes(extraData.provider as never)
|
||||
: true
|
||||
)
|
||||
.map((step, index) => ({
|
||||
...step,
|
||||
disabled: action === PageAction.CREATE
|
||||
}));
|
||||
}, [action, extraData.provider, stepList]);
|
||||
|
||||
const handleStepChange = (newStep: number) => {
|
||||
setCurrentStep(newStep);
|
||||
console.log('step========', newStep);
|
||||
};
|
||||
const customizer = (objValue: any, srcValue: any) => {
|
||||
if (Array.isArray(objValue)) {
|
||||
return srcValue;
|
||||
}
|
||||
};
|
||||
const getFormFieldsValue = () => {
|
||||
setFormValues((prev) => {
|
||||
const newFormValues = _.cloneDeep(prev);
|
||||
for (const [formKey, formRef] of Object.entries(formRefs)) {
|
||||
const formValues = formRef?.current?.getFieldsValue?.();
|
||||
if (formValues) {
|
||||
newFormValues[formKey] = formValues;
|
||||
}
|
||||
}
|
||||
return newFormValues;
|
||||
});
|
||||
};
|
||||
|
||||
const onPrevious = () => {
|
||||
getFormFieldsValue();
|
||||
setCurrentStep((prev) => Math.max(prev - 1, 0));
|
||||
};
|
||||
|
||||
const validateForms = async () => {
|
||||
const step = steps[currentStep];
|
||||
const formKeys = step?.showForms || [];
|
||||
if (formKeys?.length > 0) {
|
||||
const results = await Promise.allSettled(
|
||||
formKeys.map((key) => formRefs[key].current?.validateFields())
|
||||
);
|
||||
|
||||
console.log('results========', results);
|
||||
|
||||
const resultsMap = new Map<string, any>();
|
||||
results.forEach((result, index) => {
|
||||
if (result.status === 'rejected') {
|
||||
const values = result.reason?.values || {};
|
||||
resultsMap.set(formKeys[index], values);
|
||||
} else if (result.status === 'fulfilled') {
|
||||
resultsMap.set(formKeys[index], result.value);
|
||||
}
|
||||
});
|
||||
const newValues = _.merge(formValues, Object.fromEntries(resultsMap));
|
||||
|
||||
setFormValues(newValues);
|
||||
|
||||
const isValid = results.every((result) => result.status === 'fulfilled');
|
||||
if (!isValid) {
|
||||
return false;
|
||||
}
|
||||
return Object.assign({}, ...Object.values(newValues));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const onNext = async (callback?: (values: ClusterFormData) => void) => {
|
||||
try {
|
||||
const result = await validateForms();
|
||||
console.log('results========2', result);
|
||||
if (result) {
|
||||
await callback?.(result as ClusterFormData);
|
||||
const step = steps[currentStep];
|
||||
step.beforeNext?.();
|
||||
setCurrentStep((prev) => Math.min(prev + 1, steps.length - 1));
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('next error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectProvider = (value: ProviderType) => {
|
||||
setExtraData({
|
||||
provider: value
|
||||
} as ClusterFormData);
|
||||
onNext();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const res = await queryClusterList({ page: 1, perPage: 100 });
|
||||
const list = res.items?.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
}));
|
||||
setCredentialList(list);
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const renderForms = () => {
|
||||
const step = steps[currentStep];
|
||||
const formKeys = step?.showForms || [];
|
||||
if (formKeys.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formKeys.map((key) => {
|
||||
console.log('renderForms key========', key, formValues);
|
||||
const FormComponent = moduleRegistry[key];
|
||||
return FormComponent ? (
|
||||
<FormComponent
|
||||
key={key}
|
||||
ref={formRefs[key]}
|
||||
action={action}
|
||||
provider={extraData.provider}
|
||||
credentialList={credentialList}
|
||||
currentData={formValues[key]}
|
||||
/>
|
||||
) : null;
|
||||
});
|
||||
};
|
||||
|
||||
const renderModules = () => {
|
||||
const step = steps[currentStep];
|
||||
const moduleKeys = step?.showModules || [];
|
||||
if (moduleKeys.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return moduleKeys.map((key) => {
|
||||
const ModuleComponent = moduleRegistry[key];
|
||||
return ModuleComponent ? (
|
||||
<ModuleComponent key={key} registrationInfo={registrationInfo} />
|
||||
) : null;
|
||||
});
|
||||
};
|
||||
|
||||
const showButtons = useMemo(() => {
|
||||
const step = steps[currentStep];
|
||||
return step?.showButtons ? step?.showButtons(extraData.provider) : {};
|
||||
}, [currentStep, steps, extraData.provider]);
|
||||
|
||||
const submit = async (values: ClusterFormData) => {
|
||||
const data = {
|
||||
...extraData,
|
||||
...(typeof values === 'object' ? values : {})
|
||||
};
|
||||
console.log('submit values====:', data);
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
onNext(submit);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
navigate(-1);
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer
|
||||
ghost
|
||||
fixedHeader
|
||||
affixProps={{
|
||||
offsetTop: 0
|
||||
}}
|
||||
footer={[
|
||||
<FooterButtons
|
||||
key="buttons"
|
||||
onPrevious={onPrevious}
|
||||
onNext={onNext}
|
||||
handleCancel={handleCancel}
|
||||
handleSubmit={handleSubmit}
|
||||
showButtons={showButtons}
|
||||
/>
|
||||
]}
|
||||
pageHeaderRender={() => (
|
||||
<HeaderContainer>
|
||||
<span className="text">
|
||||
<span>Create Cluster</span>
|
||||
</span>
|
||||
<ClusterSteps
|
||||
steps={steps}
|
||||
currentStep={currentStep}
|
||||
onChange={handleStepChange}
|
||||
></ClusterSteps>
|
||||
</HeaderContainer>
|
||||
)}
|
||||
>
|
||||
{currentStep === 0 && (
|
||||
<ProviderCatalog
|
||||
dataList={providerList}
|
||||
onSelect={handleSelectProvider}
|
||||
clickable={true}
|
||||
currentProvider={extraData.provider}
|
||||
/>
|
||||
)}
|
||||
{renderModules()}
|
||||
<Container>
|
||||
<Content>{renderForms()}</Content>
|
||||
</Container>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default ClusterCreate;
|
||||
Reference in New Issue
Block a user