chore: Update AddFlowVariable component to remove unnecessary code in parameter management (#1948)

This commit is contained in:
Dreammy23 2024-09-03 17:32:20 +08:00 committed by GitHub
commit 7661de8602
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 185 additions and 102 deletions

View File

@ -1,78 +1,115 @@
import { apiInterceptors, getFlowNodes } from '@/client/api'; // import { IFlowNode } from '@/types/flow';
import { IFlowNode } from '@/types/flow';
import { FLOW_NODES_KEY } from '@/utils';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, Form, Input, Modal } from 'antd'; import { Button, Form, Input, Modal, Select, Space } from 'antd';
import React, { useEffect, useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
type GroupType = { category: string; categoryLabel: string; nodes: IFlowNode[] }; // ype GroupType = { category: string; categoryLabel: string; nodes: IFlowNode[] };
type ValueType = 'str' | 'int' | 'float' | 'bool' | 'ref';
const { Option } = Select;
const DAG_PARAM_KEY = 'dbgpt.core.flow.params';
const DAG_PARAM_SCOPE = 'flow_priv';
const AddFlowVariable: React.FC = () => { const AddFlowVariable: React.FC = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const [operators, setOperators] = useState<Array<IFlowNode>>([]); // const [operators, setOperators] = useState<Array<IFlowNode>>([]);
const [resources, setResources] = useState<Array<IFlowNode>>([]); // const [resources, setResources] = useState<Array<IFlowNode>>([]);
const [operatorsGroup, setOperatorsGroup] = useState<GroupType[]>([]); // const [operatorsGroup, setOperatorsGroup] = useState<GroupType[]>([]);
const [resourcesGroup, setResourcesGroup] = useState<GroupType[]>([]); // const [resourcesGroup, setResourcesGroup] = useState<GroupType[]>([]);
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const [form] = Form.useForm(); // const [form] = Form.useForm<IFlowUpdateParam>();
const showModal = () => { const showModal = () => {
setIsModalOpen(true); setIsModalOpen(true);
}; };
useEffect(() => { // TODO: get keys
getNodes(); // useEffect(() => {
}, []); // getNodes();
// }, []);
async function getNodes() { // async function getNodes() {
const [_, data] = await apiInterceptors(getFlowNodes()); // const [_, data] = await apiInterceptors(getFlowNodes());
if (data && data.length > 0) { // if (data && data.length > 0) {
localStorage.setItem(FLOW_NODES_KEY, JSON.stringify(data)); // localStorage.setItem(FLOW_NODES_KEY, JSON.stringify(data));
const operatorNodes = data.filter(node => node.flow_type === 'operator'); // const operatorNodes = data.filter(node => node.flow_type === 'operator');
const resourceNodes = data.filter(node => node.flow_type === 'resource'); // const resourceNodes = data.filter(node => node.flow_type === 'resource');
setOperators(operatorNodes); // setOperators(operatorNodes);
setResources(resourceNodes); // setResources(resourceNodes);
setOperatorsGroup(groupNodes(operatorNodes)); // setOperatorsGroup(groupNodes(operatorNodes));
setResourcesGroup(groupNodes(resourceNodes)); // setResourcesGroup(groupNodes(resourceNodes));
} // }
} // }
function groupNodes(data: IFlowNode[]) { // function groupNodes(data: IFlowNode[]) {
const groups: GroupType[] = []; // const groups: GroupType[] = [];
const categoryMap: Record<string, { category: string; categoryLabel: string; nodes: IFlowNode[] }> = {}; // const categoryMap: Record<string, { category: string; categoryLabel: string; nodes: IFlowNode[] }> = {};
data.forEach(item => { // data.forEach(item => {
const { category, category_label } = item; // const { category, category_label } = item;
if (!categoryMap[category]) { // if (!categoryMap[category]) {
categoryMap[category] = { category, categoryLabel: category_label, nodes: [] }; // categoryMap[category] = { category, categoryLabel: category_label, nodes: [] };
groups.push(categoryMap[category]); // groups.push(categoryMap[category]);
} // }
categoryMap[category].nodes.push(item); // categoryMap[category].nodes.push(item);
}); // });
return groups; // return groups;
} // }
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 4 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 },
},
};
const formItemLayoutWithOutLabel = {
wrapperCol: {
xs: { span: 24, offset: 0 },
sm: { span: 20, offset: 2 },
},
};
const onFinish = (values: any) => { const onFinish = (values: any) => {
console.log('Received values of form:', values); console.log('Received values of form:', values);
}; };
function onNameChange(e: React.ChangeEvent<HTMLInputElement>, index: number) {
const name = e.target.value;
const result = name
?.split('_')
?.map(word => word.charAt(0).toUpperCase() + word.slice(1))
?.join(' ');
form.setFields([
{
name: ['parameters', index, 'label'],
value: result,
},
]);
// change value to ref
const type = form.getFieldValue(['parameters', index, 'value_type']);
if (type === 'ref') {
const parameters = form.getFieldValue('parameters');
const param = parameters?.[index];
if (param) {
const { name = '' } = param;
param.value = `${DAG_PARAM_KEY}:${name}@scope:${DAG_PARAM_SCOPE}`;
form.setFieldsValue({
parameters: [...parameters],
});
}
}
}
function onValueTypeChange(type: ValueType, index: number) {
if (type === 'ref') {
const parameters = form.getFieldValue('parameters');
const param = parameters?.[index];
if (param) {
const { name = '' } = param;
param.value = `${DAG_PARAM_KEY}:${name}@scope:${DAG_PARAM_SCOPE}`;
form.setFieldsValue({
parameters: [...parameters],
});
}
}
}
return ( return (
<> <>
<Button <Button
@ -83,64 +120,111 @@ const AddFlowVariable: React.FC = () => {
onClick={showModal} onClick={showModal}
/> />
<Modal title={t('Add_Global_Variable_of_Flow')} open={isModalOpen} footer={null}> <Modal
<Form name='dynamic_form_item' {...formItemLayoutWithOutLabel} onFinish={onFinish} className='mt-8'> title={t('Add_Global_Variable_of_Flow')}
<Form.List open={isModalOpen}
name='names' footer={null}
rules={[ width={1000}
{ styles={{
validator: async (_, names) => { body: {
if (!names || names.length < 2) { maxHeight: '70vh',
return Promise.reject(new Error('At least 2 passengers')); overflow: 'scroll',
} backgroundColor: 'rgba(0,0,0,0.02)',
padding: '0 8px',
borderRadius: 4,
}, },
}, }}
]} onClose={() => setIsModalOpen(false)}
> >
{(fields, { add, remove }, { errors }) => ( <Form
name='dynamic_form_nest_item'
onFinish={onFinish}
form={form}
autoComplete='off'
layout='vertical'
className='mt-8'
initialValues={{ parameters: [{}] }}
>
<Form.List name='parameters'>
{(fields, { add, remove }) => (
<> <>
{fields.map((field, index) => ( {fields.map(({ key, name, ...restField }, index) => (
<Space key={key} style={{ display: 'flex', marginBottom: 8 }} align='baseline'>
<Form.Item <Form.Item
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)} {...restField}
label={index === 0 ? 'Passengers' : ''} name={[name, 'name']}
required={false} label={`参数 ${index + 1} 名称`}
key={field.key} style={{ width: 140 }}
>
<Form.Item
{...field}
validateTrigger={['onChange', 'onBlur']}
rules={[ rules={[
{ required: true, message: 'Missing parameter name' },
{ {
required: true, pattern: /^[a-zA-Z0-9]+(_[a-zA-Z0-9]+)*$/,
whitespace: true, message: '名称必须是字母、数字或下划线,并使用下划线分隔多个单词',
message: "Please input passenger's name or delete this field.",
}, },
]} ]}
noStyle
> >
<Input placeholder='passenger name' style={{ width: '60%' }} /> <Input placeholder='Parameter Name' onChange={e => onNameChange(e, index)} />
</Form.Item> </Form.Item>
{fields.length > 1 ? (
<MinusCircleOutlined className='dynamic-delete-button' onClick={() => remove(field.name)} /> <Form.Item
) : null} {...restField}
name={[name, 'label']}
label='标题'
style={{ width: 130 }}
rules={[{ required: true, message: 'Missing parameter label' }]}
>
<Input placeholder='Parameter Label' />
</Form.Item> </Form.Item>
<Form.Item
{...restField}
name={[name, 'value_type']}
label='类型'
style={{ width: 100 }}
rules={[{ required: true, message: 'Missing parameter type' }]}
>
<Select placeholder='Select' onChange={value => onValueTypeChange(value, index)}>
{['str', 'int', 'float', 'bool', 'ref'].map(type => (
<Option key={type} value={type}>
{type}
</Option>
))}
</Select>
</Form.Item>
<Form.Item
{...restField}
name={[name, 'value']}
label='值'
style={{ width: 320 }}
rules={[{ required: true, message: 'Missing parameter value' }]}
>
<Input placeholder='Parameter Value' />
</Form.Item>
<Form.Item {...restField} name={[name, 'description']} label='描述' style={{ width: 170 }}>
<Input placeholder='Parameter Description' />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</Space>
))} ))}
<Form.Item> <Form.Item>
<Button type='dashed' onClick={() => add()} className='w-full' icon={<PlusOutlined />}> <Button type='dashed' onClick={() => add()} block icon={<PlusOutlined />}>
Add field {t('Add_Parameter')}
</Button> </Button>
<Form.ErrorList errors={errors} />
</Form.Item> </Form.Item>
</> </>
)} )}
</Form.List> </Form.List>
<Form.Item wrapperCol={{ offset: 20, span: 4 }}>
<Form.Item wrapperCol={{ offset: 18, span: 8 }}> <Space>
<Button onClick={() => setIsModalOpen(false)}>{t('cancel')}</Button>
<Button type='primary' htmlType='submit'> <Button type='primary' htmlType='submit'>
Submit {t('verify')}
</Button> </Button>
</Space>
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>

View File

@ -43,7 +43,6 @@ export const ExportFlowModal: React.FC<Props> = ({
return ( return (
<> <>
<Modal <Modal
centered
title={t('Export_Flow')} title={t('Export_Flow')}
open={isExportFlowModalOpen} open={isExportFlowModalOpen}
onCancel={() => setIsExportFlowModalOpen(false)} onCancel={() => setIsExportFlowModalOpen(false)}

View File

@ -61,7 +61,6 @@ export const ImportFlowModal: React.FC<Props> = ({ isImportModalOpen, setIsImpor
return ( return (
<> <>
<Modal <Modal
centered
title={t('Import_Flow')} title={t('Import_Flow')}
open={isImportModalOpen} open={isImportModalOpen}
onCancel={() => setIsImportFlowModalOpen(false)} onCancel={() => setIsImportFlowModalOpen(false)}

View File

@ -89,7 +89,6 @@ export const SaveFlowModal: React.FC<Props> = ({
return ( return (
<> <>
<Modal <Modal
centered
title={t('flow_modal_title')} title={t('flow_modal_title')}
open={isSaveFlowModalOpen} open={isSaveFlowModalOpen}
onCancel={() => { onCancel={() => {
@ -142,7 +141,7 @@ export const SaveFlowModal: React.FC<Props> = ({
<TextArea rows={3} /> <TextArea rows={3} />
</Form.Item> </Form.Item>
<Form.Item label='Editable' name='editable' initialValue={flowInfo?.editable} valuePropName='checked'> <Form.Item label='Editable' name='editable' initialValue={flowInfo?.editable || true} valuePropName='checked'>
<Checkbox /> <Checkbox />
</Form.Item> </Form.Item>

View File

@ -18,4 +18,5 @@ export const FlowEn = {
No: 'No', No: 'No',
Please_Add_Nodes_First: 'Please add nodes first', Please_Add_Nodes_First: 'Please add nodes first',
Add_Global_Variable_of_Flow: 'Add global variable of flow', Add_Global_Variable_of_Flow: 'Add global variable of flow',
Add_Parameter: 'Add Parameter',
}; };

View File

@ -18,4 +18,5 @@ export const FlowZn = {
No: '否', No: '否',
Please_Add_Nodes_First: '请先添加节点', Please_Add_Nodes_First: '请先添加节点',
Add_Global_Variable_of_Flow: '添加 Flow 全局变量', Add_Global_Variable_of_Flow: '添加 Flow 全局变量',
Add_Parameter: '添加参数',
}; };