import {
regionInstanceTypeListAtom,
regionOSImageListAtom
} from '@/atoms/clusters';
import CollapsibleContainer, {
CollapsibleContainerProps
} from '@/components/collapse-container';
import IconFont from '@/components/icon-font';
import LabelSelector from '@/components/label-selector';
import AutoComplete from '@/components/seal-form/auto-complete';
import SealInputNumber from '@/components/seal-form/input-number';
import SealInput from '@/components/seal-form/seal-input';
import SealSelect from '@/components/seal-form/seal-select';
import { PageAction } from '@/config';
import { PageActionType } from '@/config/types';
import useAppUtils from '@/hooks/use-app-utils';
import { CardContainer } from '@/pages/llmodels/components/gpu-card';
import { DeleteOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Form } from 'antd';
import { useAtom } from 'jotai';
import _ from 'lodash';
import React, {
forwardRef,
useEffect,
useImperativeHandle,
useState
} from 'react';
import styled from 'styled-components';
import { ProviderType, instanceTypeFieldMap, vendorIconMap } from '../config';
import { NodePoolFormData as FormData } from '../config/types';
import VolumesConfig from './volumes-config';
const Container = styled.div`
pointer-events: auto;
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 0 16px;
.ant-form-item:nth-child(1) {
grid-column: 1 / 3;
}
.ant-form-item:nth-child(2) {
grid-column: 1 / 3;
}
.ant-form-item:nth-child(5) {
grid-column: 1 / 3;
}
.ant-form-item:nth-child(6) {
grid-column: 1 / 3;
}
.ant-form-item:nth-child(7) {
grid-column: 1 / 3;
}
`;
const NoContent = styled.div`
display: flex;
justify-content: center;
align-items: center;
padding-block: 12px;
`;
const OptionItem = styled.div.attrs({
className: 'option-item'
})`
display: flex;
gap: 8px;
align-items: center;
`;
const DescriptionWrapper = styled.div`
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 4px 8px;
font-weight: 400;
`;
const NotFoundContent = () => {
const intl = useIntl();
return (
{intl.formatMessage({ id: 'clusters.create.noInstanceTypes' })}
);
};
const NotFoundImageContent = () => {
const intl = useIntl();
return (
{intl.formatMessage({ id: 'clusters.create.noImages' })}
);
};
const RenderLabel = (data: {
label: React.ReactNode;
vendor: string;
style?: React.CSSProperties;
}) => {
const { label, vendor, style } = data;
return (
{label}
);
};
export const RenderOption = (option: any) => {
const { data = {}, styles } = option;
const entries = Object.entries(data?.specInfo || {});
return (
}
description={
entries.length > 0 && (
{Object.entries(data?.specInfo)
.filter(([key, value]) => value)
.map(([key, value]) => (
{_.get(instanceTypeFieldMap, key, key)}:
{value as string}
))}
)
}
/>
);
};
type AddModalProps = {
ref: any;
name?: string;
action: PageActionType;
provider: ProviderType; // 'kubernetes' | 'custom' | 'digitalocean';
currentData?: FormData | null;
onFinish: (values: FormData) => void;
onDelete?: () => void;
showDelete?: boolean;
collapseProps?: CollapsibleContainerProps;
};
const InstanceSpecData: React.FC<{ instanceSpec: Record }> = ({
instanceSpec
}) => {
return (
<>
{Object.entries(instanceSpec)
.filter(([key, value]) => value)
.map(([key, value]) => (
))}
>
);
};
const PoolForm: React.FC = forwardRef((props, ref) => {
const {
action,
name = 'workerPoolForm',
onFinish,
onDelete,
showDelete,
currentData,
collapseProps
} = props;
const [instanceTypeList] = useAtom(regionInstanceTypeListAtom);
const [osImageList] = useAtom(regionOSImageListAtom);
const { collapsible, onToggle, ...restCollapseProps } = collapseProps || {};
const [form] = Form.useForm();
const intl = useIntl();
const { getRuleMessage } = useAppUtils();
const labels = Form.useWatch('labels', form);
const title = Form.useWatch('name', form);
const [instanceSpec, setInstanceSpec] = useState>({});
useEffect(() => {
if (currentData) {
form.setFieldsValue({
...currentData
});
setInstanceSpec({
...currentData.instance_spec
});
}
}, [currentData]);
const imageLabelRender = (data: {
label: React.ReactNode;
value: string | number;
}) => {
if (action === PageAction.EDIT) {
const vendor = _.split(currentData?.image_name || '', ' ')[0];
const iconType = _.get(vendorIconMap, vendor.toLowerCase());
return (
{iconType && }
{currentData?.image_name || currentData?.os_image}
);
}
const selectImage = osImageList.find((item) => item.value === data.value);
if (selectImage) {
return (
);
}
return data.value;
};
const instanceLabelRender = (data: {
label: React.ReactNode;
value: string | number;
}) => {
const currentInstanceSpec =
instanceTypeList.find((item) => item.value === data.value) ||
instanceSpec;
return (
);
};
const handleOsImageChange = (value: string) => {
form.setFieldsValue({
image_name:
osImageList.find((item) => item.value === value)?.label || value
});
};
const handleInstanceTypeChange = (value: string, option: any) => {
setInstanceSpec({
...option.specInfo,
label: option.label,
vendor: option.vendor,
description: option.description
});
form.setFieldsValue({
instance_spec: {
...option.specInfo,
label: option.label,
vendor: option.vendor,
description: option.description
}
});
};
const filterInstanceOption = (inputValue: string, option: any) => {
return (
option.label.toLowerCase().includes(inputValue.toLowerCase()) ||
option.description.toLowerCase().includes(inputValue.toLowerCase())
);
};
useImperativeHandle(ref, () => ({
resetFields: () => {
form.resetFields();
},
submit: () => {
form.submit();
},
setFieldsValue: (values: any) => {
form.setFieldsValue(values);
},
getFieldsValue: () => {
return form.getFieldsValue();
},
validateFields: async () => {
return await form.validateFields();
}
}));
return (
}
danger
type="text"
variant="filled"
color="danger"
size="small"
>
)
}
>
);
});
export default PoolForm;