feat(web): copy awel flow (#1200)

Co-authored-by: Fangyin Cheng <staneyffer@gmail.com>
This commit is contained in:
Hzh_97
2024-02-28 21:03:23 +08:00
committed by GitHub
parent 0837da48ba
commit 673ddaab5b
68 changed files with 898 additions and 190 deletions

View File

@@ -24,7 +24,7 @@ const edgeTypes = { buttonedge: ButtonEdge };
const Canvas: React.FC<Props> = () => {
const { t } = useTranslation();
const [messageApi, contextHolder] = message.useMessage();
const [form] = Form.useForm();
const [form] = Form.useForm<IFlowUpdateParam>();
const searchParams = useSearchParams();
const id = searchParams?.get('id') || '';
const reactFlow = useReactFlow();
@@ -35,6 +35,7 @@ const Canvas: React.FC<Props> = () => {
const reactFlowWrapper = useRef<HTMLDivElement>(null);
const [isModalVisible, setIsModalVisible] = useState(false);
const [flowInfo, setFlowInfo] = useState<IFlowUpdateParam>();
const [deploy, setDeploy] = useState(true);
async function getFlowData() {
setLoading(true);
@@ -175,10 +176,11 @@ const Canvas: React.FC<Props> = () => {
}
async function handleSaveFlow() {
const { name, label, description = '', editable = false } = form.getFieldsValue();
const { name, label, description = '', editable = false, state = 'deployed' } = form.getFieldsValue();
console.log(form.getFieldsValue());
const reactFlowObject = mapHumpToUnderline(reactFlow.toObject() as IFlowData);
if (id) {
const [, , res] = await apiInterceptors(updateFlowById(id, { name, label, description, editable, uid: id, flow_data: reactFlowObject }));
const [, , res] = await apiInterceptors(updateFlowById(id, { name, label, description, editable, uid: id, flow_data: reactFlowObject, state }));
setIsModalVisible(false);
if (res?.success) {
messageApi.success(t('save_flow_success'));
@@ -186,7 +188,7 @@ const Canvas: React.FC<Props> = () => {
messageApi.error(res?.err_msg);
}
} else {
const [_, res] = await apiInterceptors(addFlow({ name, label, description, editable, flow_data: reactFlowObject }));
const [_, res] = await apiInterceptors(addFlow({ name, label, description, editable, flow_data: reactFlowObject, state }));
if (res?.uid) {
messageApi.success(t('save_flow_success'));
const history = window.history;
@@ -271,7 +273,21 @@ const Canvas: React.FC<Props> = () => {
<TextArea rows={3} />
</Form.Item>
<Form.Item label="Editable" name="editable" initialValue={flowInfo?.editable} valuePropName="checked">
<Checkbox></Checkbox>
<Checkbox />
</Form.Item>
<Form.Item hidden name="state">
<Input />
</Form.Item>
<Form.Item label="Deploy">
<Checkbox
defaultChecked={flowInfo?.state === 'deployed' || flowInfo?.state === 'running'}
value={deploy}
onChange={(e) => {
const val = e.target.checked;
form.setFieldValue('state', val ? 'deployed' : 'developing');
setDeploy(val);
}}
/>
</Form.Item>
<Form.Item wrapperCol={{ offset: 8, span: 16 }}>
<Space>

View File

@@ -1,16 +1,28 @@
import { apiInterceptors, getFlows } from '@/client/api';
import { addFlow, apiInterceptors, getFlows } from '@/client/api';
import MyEmpty from '@/components/common/MyEmpty';
import MuiLoading from '@/components/common/loading';
import FlowCard from '@/components/flow/flow-card';
import { IFlow } from '@/types/flow';
import { IFlow, IFlowUpdateParam } from '@/types/flow';
import { PlusOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import { Button, Checkbox, Form, Input, Modal, message } from 'antd';
import Link from 'next/link';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
type FormFields = Pick<IFlow, 'label' | 'name'>;
function Flow() {
const { t } = useTranslation();
const [showModal, setShowModal] = useState(false);
const [loading, setLoading] = useState(false);
const [flowList, setFlowList] = useState<Array<IFlow>>([]);
const [deploy, setDeploy] = useState(false);
const [messageApi, contextHolder] = message.useMessage();
const [form] = Form.useForm<Pick<IFlow, 'label' | 'name'>>();
const copyFlowTemp = useRef<IFlow>();
async function getFlowList() {
setLoading(true);
@@ -27,8 +39,34 @@ function Flow() {
setFlowList((flows) => flows.filter((flow) => flow.uid !== uid));
}
const handleCopy = (flow: IFlow) => {
copyFlowTemp.current = flow;
form.setFieldValue('label', `${flow.label} Copy`);
form.setFieldValue('name', `${flow.name}_copy`);
setDeploy(false);
setShowModal(true);
};
const onFinish = async (val: { name: string; label: string }) => {
if (!copyFlowTemp.current) return;
const { source, uid, dag_id, gmt_created, gmt_modified, state, ...params } = copyFlowTemp.current;
const data: IFlowUpdateParam = {
...params,
editable: true,
state: deploy ? 'deployed' : 'developing',
...val,
};
const [err] = await apiInterceptors(addFlow(data));
if (!err) {
messageApi.success(t('save_flow_success'));
setShowModal(false);
getFlowList();
}
};
return (
<div className="relative p-4 md:p-6 min-h-full overflow-y-auto">
{contextHolder}
<MuiLoading visible={loading} />
<div className="mb-4">
<Link href="/flow/canvas">
@@ -39,10 +77,41 @@ function Flow() {
</div>
<div className="flex flex-wrap gap-2 md:gap-4 justify-start items-stretch">
{flowList.map((flow) => (
<FlowCard key={flow.uid} flow={flow} deleteCallback={updateFlowList} />
<FlowCard key={flow.uid} flow={flow} deleteCallback={updateFlowList} onCopy={handleCopy} />
))}
{flowList.length === 0 && <MyEmpty description="No flow found" />}
</div>
<Modal
open={showModal}
title="Copy AWEL Flow"
onCancel={() => {
setShowModal(false);
}}
footer={false}
>
<Form form={form} onFinish={onFinish} className="mt-6">
<Form.Item name="name" label="Name" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="label" label="Label" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item label="Deploy">
<Checkbox
value={deploy}
onChange={(e) => {
const val = e.target.checked;
setDeploy(val);
}}
/>
</Form.Item>
<div className="flex justify-end">
<Button type="primary" htmlType="submit">
{t('Submit')}
</Button>
</div>
</Form>
</Modal>
</div>
);
}