balibabu
commited on
Commit
·
9ee6e3a
1
Parent(s):
591888d
feat: add CreateFlowModal #918 (#1343)
Browse files### What problem does this PR solve?
feat: add CreateFlowModal #918
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- web/src/hooks/flow-hooks.ts +3 -2
- web/src/hooks/logicHooks.ts +25 -0
- web/src/interfaces/database/base.ts +2 -2
- web/src/interfaces/database/flow.ts +13 -0
- web/src/locales/en.ts +1 -0
- web/src/locales/zh.ts +1 -0
- web/src/pages/flow/hooks.ts +1 -6
- web/src/pages/flow/list/create-flow-modal.tsx +104 -0
- web/src/pages/flow/list/hooks.ts +17 -6
- web/src/pages/flow/list/index.less +8 -0
- web/src/pages/flow/list/index.tsx +10 -8
web/src/hooks/flow-hooks.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
| 1 |
-
import {
|
|
|
|
| 2 |
import i18n from '@/locales/config';
|
| 3 |
import flowService from '@/services/flow-service';
|
| 4 |
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
| 5 |
import { message } from 'antd';
|
| 6 |
import { useParams } from 'umi';
|
| 7 |
|
| 8 |
-
export const useFetchFlowTemplates = () => {
|
| 9 |
const { data } = useQuery({
|
| 10 |
queryKey: ['fetchFlowTemplates'],
|
| 11 |
initialData: [],
|
|
|
|
| 1 |
+
import { ResponseType } from '@/interfaces/database/base';
|
| 2 |
+
import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow';
|
| 3 |
import i18n from '@/locales/config';
|
| 4 |
import flowService from '@/services/flow-service';
|
| 5 |
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
| 6 |
import { message } from 'antd';
|
| 7 |
import { useParams } from 'umi';
|
| 8 |
|
| 9 |
+
export const useFetchFlowTemplates = (): ResponseType<IFlowTemplate[]> => {
|
| 10 |
const { data } = useQuery({
|
| 11 |
queryKey: ['fetchFlowTemplates'],
|
| 12 |
initialData: [],
|
web/src/hooks/logicHooks.ts
CHANGED
|
@@ -244,3 +244,28 @@ export const useHandleMessageInputChange = () => {
|
|
| 244 |
};
|
| 245 |
|
| 246 |
// #endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
};
|
| 245 |
|
| 246 |
// #endregion
|
| 247 |
+
|
| 248 |
+
/**
|
| 249 |
+
*
|
| 250 |
+
* @param defaultId
|
| 251 |
+
* used to switch between different items, similar to radio
|
| 252 |
+
* @returns
|
| 253 |
+
*/
|
| 254 |
+
export const useSelectItem = (defaultId?: string) => {
|
| 255 |
+
const [selectedId, setSelectedId] = useState('');
|
| 256 |
+
|
| 257 |
+
const handleItemClick = useCallback(
|
| 258 |
+
(id: string) => () => {
|
| 259 |
+
setSelectedId(id);
|
| 260 |
+
},
|
| 261 |
+
[],
|
| 262 |
+
);
|
| 263 |
+
|
| 264 |
+
useEffect(() => {
|
| 265 |
+
if (defaultId) {
|
| 266 |
+
setSelectedId(defaultId);
|
| 267 |
+
}
|
| 268 |
+
}, [defaultId]);
|
| 269 |
+
|
| 270 |
+
return { selectedId, handleItemClick };
|
| 271 |
+
};
|
web/src/interfaces/database/base.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
-
export interface ResponseType {
|
| 2 |
retcode: number;
|
| 3 |
-
data:
|
| 4 |
retmsg: string;
|
| 5 |
status: number;
|
| 6 |
}
|
|
|
|
| 1 |
+
export interface ResponseType<T = any> {
|
| 2 |
retcode: number;
|
| 3 |
+
data: T;
|
| 4 |
retmsg: string;
|
| 5 |
status: number;
|
| 6 |
}
|
web/src/interfaces/database/flow.ts
CHANGED
|
@@ -42,3 +42,16 @@ export interface IFlow {
|
|
| 42 |
update_time: number;
|
| 43 |
user_id: string;
|
| 44 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
update_time: number;
|
| 43 |
user_id: string;
|
| 44 |
}
|
| 45 |
+
|
| 46 |
+
export interface IFlowTemplate {
|
| 47 |
+
avatar: string;
|
| 48 |
+
canvas_type: string;
|
| 49 |
+
create_date: string;
|
| 50 |
+
create_time: number;
|
| 51 |
+
description: string;
|
| 52 |
+
dsl: DSL;
|
| 53 |
+
id: string;
|
| 54 |
+
title: string;
|
| 55 |
+
update_date: string;
|
| 56 |
+
update_time: number;
|
| 57 |
+
}
|
web/src/locales/en.ts
CHANGED
|
@@ -557,6 +557,7 @@ The above is the content you need to summarize.`,
|
|
| 557 |
messageMsg: 'Please input message or delete this field.',
|
| 558 |
addField: 'Add field',
|
| 559 |
loop: 'Loop',
|
|
|
|
| 560 |
},
|
| 561 |
footer: {
|
| 562 |
profile: 'All rights reserved @ React',
|
|
|
|
| 557 |
messageMsg: 'Please input message or delete this field.',
|
| 558 |
addField: 'Add field',
|
| 559 |
loop: 'Loop',
|
| 560 |
+
createFlow: 'Create a workflow',
|
| 561 |
},
|
| 562 |
footer: {
|
| 563 |
profile: 'All rights reserved @ React',
|
web/src/locales/zh.ts
CHANGED
|
@@ -524,6 +524,7 @@ export default {
|
|
| 524 |
fileError: '文件错误',
|
| 525 |
},
|
| 526 |
flow: {
|
|
|
|
| 527 |
cite: '引用',
|
| 528 |
citeTip: 'citeTip',
|
| 529 |
name: '名称',
|
|
|
|
| 524 |
fileError: '文件错误',
|
| 525 |
},
|
| 526 |
flow: {
|
| 527 |
+
flow: '工作流',
|
| 528 |
cite: '引用',
|
| 529 |
citeTip: 'citeTip',
|
| 530 |
name: '名称',
|
web/src/pages/flow/hooks.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
| 1 |
import { useSetModalState } from '@/hooks/commonHooks';
|
| 2 |
-
import {
|
| 3 |
-
useFetchFlow,
|
| 4 |
-
useFetchFlowTemplates,
|
| 5 |
-
useSetFlow,
|
| 6 |
-
} from '@/hooks/flow-hooks';
|
| 7 |
import { useFetchLlmList } from '@/hooks/llmHooks';
|
| 8 |
import { IGraph } from '@/interfaces/database/flow';
|
| 9 |
import { useIsFetching } from '@tanstack/react-query';
|
|
@@ -221,7 +217,6 @@ export const useFetchDataOnMount = () => {
|
|
| 221 |
|
| 222 |
useWatchGraphChange();
|
| 223 |
|
| 224 |
-
useFetchFlowTemplates();
|
| 225 |
useFetchLlmList();
|
| 226 |
|
| 227 |
return { loading, flowDetail: data };
|
|
|
|
| 1 |
import { useSetModalState } from '@/hooks/commonHooks';
|
| 2 |
+
import { useFetchFlow, useSetFlow } from '@/hooks/flow-hooks';
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import { useFetchLlmList } from '@/hooks/llmHooks';
|
| 4 |
import { IGraph } from '@/interfaces/database/flow';
|
| 5 |
import { useIsFetching } from '@tanstack/react-query';
|
|
|
|
| 217 |
|
| 218 |
useWatchGraphChange();
|
| 219 |
|
|
|
|
| 220 |
useFetchLlmList();
|
| 221 |
|
| 222 |
return { loading, flowDetail: data };
|
web/src/pages/flow/list/create-flow-modal.tsx
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { IModalManagerChildrenProps } from '@/components/modal-manager';
|
| 2 |
+
import { useTranslate } from '@/hooks/commonHooks';
|
| 3 |
+
import { useFetchFlowTemplates } from '@/hooks/flow-hooks';
|
| 4 |
+
import { useSelectItem } from '@/hooks/logicHooks';
|
| 5 |
+
import { UserOutlined } from '@ant-design/icons';
|
| 6 |
+
import {
|
| 7 |
+
Avatar,
|
| 8 |
+
Card,
|
| 9 |
+
Flex,
|
| 10 |
+
Form,
|
| 11 |
+
Input,
|
| 12 |
+
Modal,
|
| 13 |
+
Space,
|
| 14 |
+
Typography,
|
| 15 |
+
} from 'antd';
|
| 16 |
+
import classNames from 'classnames';
|
| 17 |
+
import { useEffect } from 'react';
|
| 18 |
+
import styles from './index.less';
|
| 19 |
+
|
| 20 |
+
const { Title } = Typography;
|
| 21 |
+
interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
|
| 22 |
+
loading: boolean;
|
| 23 |
+
initialName: string;
|
| 24 |
+
onOk: (name: string, templateId: string) => void;
|
| 25 |
+
showModal?(): void;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
const CreateFlowModal = ({
|
| 29 |
+
visible,
|
| 30 |
+
hideModal,
|
| 31 |
+
loading,
|
| 32 |
+
initialName,
|
| 33 |
+
onOk,
|
| 34 |
+
}: IProps) => {
|
| 35 |
+
const [form] = Form.useForm();
|
| 36 |
+
const { t } = useTranslate('common');
|
| 37 |
+
const { data: list } = useFetchFlowTemplates();
|
| 38 |
+
const { selectedId, handleItemClick } = useSelectItem(list?.at(0)?.id);
|
| 39 |
+
|
| 40 |
+
type FieldType = {
|
| 41 |
+
name?: string;
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
+
const handleOk = async () => {
|
| 45 |
+
const ret = await form.validateFields();
|
| 46 |
+
|
| 47 |
+
return onOk(ret.name, selectedId);
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
useEffect(() => {
|
| 51 |
+
if (visible) {
|
| 52 |
+
form.setFieldValue('name', initialName);
|
| 53 |
+
}
|
| 54 |
+
}, [initialName, form, visible]);
|
| 55 |
+
|
| 56 |
+
return (
|
| 57 |
+
<Modal
|
| 58 |
+
title={t('createFlow', { keyPrefix: 'flow' })}
|
| 59 |
+
open={visible}
|
| 60 |
+
onOk={handleOk}
|
| 61 |
+
width={600}
|
| 62 |
+
onCancel={hideModal}
|
| 63 |
+
okButtonProps={{ loading }}
|
| 64 |
+
confirmLoading={loading}
|
| 65 |
+
>
|
| 66 |
+
<Form
|
| 67 |
+
name="basic"
|
| 68 |
+
labelCol={{ span: 4 }}
|
| 69 |
+
wrapperCol={{ span: 20 }}
|
| 70 |
+
autoComplete="off"
|
| 71 |
+
layout={'vertical'}
|
| 72 |
+
form={form}
|
| 73 |
+
>
|
| 74 |
+
<Form.Item<FieldType>
|
| 75 |
+
label={<b>{t('name')}</b>}
|
| 76 |
+
name="name"
|
| 77 |
+
rules={[{ required: true, message: t('namePlaceholder') }]}
|
| 78 |
+
>
|
| 79 |
+
<Input />
|
| 80 |
+
</Form.Item>
|
| 81 |
+
</Form>
|
| 82 |
+
<Title level={5}>Choose from templates</Title>
|
| 83 |
+
<Flex vertical gap={16}>
|
| 84 |
+
{list?.map((x) => (
|
| 85 |
+
<Card
|
| 86 |
+
key={x.id}
|
| 87 |
+
className={classNames(styles.flowTemplateCard, {
|
| 88 |
+
[styles.selectedFlowTemplateCard]: selectedId === x.id,
|
| 89 |
+
})}
|
| 90 |
+
onClick={handleItemClick(x.id)}
|
| 91 |
+
>
|
| 92 |
+
<Space size={'middle'}>
|
| 93 |
+
<Avatar size={40} icon={<UserOutlined />} src={x.avatar} />
|
| 94 |
+
<b>{x.title}</b>
|
| 95 |
+
</Space>
|
| 96 |
+
<p>{x.description}</p>
|
| 97 |
+
</Card>
|
| 98 |
+
))}
|
| 99 |
+
</Flex>
|
| 100 |
+
</Modal>
|
| 101 |
+
);
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
export default CreateFlowModal;
|
web/src/pages/flow/list/hooks.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
| 1 |
import { useSetModalState } from '@/hooks/commonHooks';
|
| 2 |
-
import {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import { useCallback, useState } from 'react';
|
| 4 |
import { useNavigate } from 'umi';
|
| 5 |
// import { dsl } from '../mock';
|
| 6 |
-
import headhunterZhComponents from '../../../../../graph/test/dsl_examples/headhunter_zh.json';
|
| 7 |
-
import
|
| 8 |
|
| 9 |
export const useFetchDataOnMount = () => {
|
| 10 |
const { data, loading } = useFetchFlowList();
|
|
@@ -21,12 +25,19 @@ export const useSaveFlow = () => {
|
|
| 21 |
} = useSetModalState();
|
| 22 |
const { loading, setFlow } = useSetFlow();
|
| 23 |
const navigate = useNavigate();
|
|
|
|
| 24 |
|
| 25 |
const onFlowOk = useCallback(
|
| 26 |
-
async (title: string) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
const ret = await setFlow({
|
| 28 |
title,
|
| 29 |
-
dsl:
|
| 30 |
});
|
| 31 |
|
| 32 |
if (ret?.retcode === 0) {
|
|
@@ -34,7 +45,7 @@ export const useSaveFlow = () => {
|
|
| 34 |
navigate(`/flow/${ret.data.id}`);
|
| 35 |
}
|
| 36 |
},
|
| 37 |
-
[setFlow, hideFlowSettingModal, navigate],
|
| 38 |
);
|
| 39 |
|
| 40 |
const handleShowFlowSettingModal = useCallback(
|
|
|
|
| 1 |
import { useSetModalState } from '@/hooks/commonHooks';
|
| 2 |
+
import {
|
| 3 |
+
useFetchFlowList,
|
| 4 |
+
useFetchFlowTemplates,
|
| 5 |
+
useSetFlow,
|
| 6 |
+
} from '@/hooks/flow-hooks';
|
| 7 |
import { useCallback, useState } from 'react';
|
| 8 |
import { useNavigate } from 'umi';
|
| 9 |
// import { dsl } from '../mock';
|
| 10 |
+
// import headhunterZhComponents from '../../../../../graph/test/dsl_examples/headhunter_zh.json';
|
| 11 |
+
import dslJson from '../../../../../dls.json';
|
| 12 |
|
| 13 |
export const useFetchDataOnMount = () => {
|
| 14 |
const { data, loading } = useFetchFlowList();
|
|
|
|
| 25 |
} = useSetModalState();
|
| 26 |
const { loading, setFlow } = useSetFlow();
|
| 27 |
const navigate = useNavigate();
|
| 28 |
+
const { data: list } = useFetchFlowTemplates();
|
| 29 |
|
| 30 |
const onFlowOk = useCallback(
|
| 31 |
+
async (title: string, templateId: string) => {
|
| 32 |
+
const templateItem = list.find((x) => x.id === templateId);
|
| 33 |
+
|
| 34 |
+
let dsl = templateItem?.dsl;
|
| 35 |
+
// if (dsl) {
|
| 36 |
+
// dsl.graph = headhunter_zh;
|
| 37 |
+
// }
|
| 38 |
const ret = await setFlow({
|
| 39 |
title,
|
| 40 |
+
dsl: dslJson,
|
| 41 |
});
|
| 42 |
|
| 43 |
if (ret?.retcode === 0) {
|
|
|
|
| 45 |
navigate(`/flow/${ret.data.id}`);
|
| 46 |
}
|
| 47 |
},
|
| 48 |
+
[setFlow, hideFlowSettingModal, navigate, list],
|
| 49 |
);
|
| 50 |
|
| 51 |
const handleShowFlowSettingModal = useCallback(
|
web/src/pages/flow/list/index.less
CHANGED
|
@@ -46,3 +46,11 @@
|
|
| 46 |
width: 100%;
|
| 47 |
}
|
| 48 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
width: 100%;
|
| 47 |
}
|
| 48 |
}
|
| 49 |
+
|
| 50 |
+
.flowTemplateCard {
|
| 51 |
+
cursor: pointer;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
.selectedFlowTemplateCard {
|
| 55 |
+
background-color: @selectedBackgroundColor;
|
| 56 |
+
}
|
web/src/pages/flow/list/index.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
-
import RenameModal from '@/components/rename-modal';
|
| 2 |
import { PlusOutlined } from '@ant-design/icons';
|
| 3 |
import { Button, Empty, Flex, Spin } from 'antd';
|
|
|
|
| 4 |
import FlowCard from './flow-card';
|
| 5 |
import { useFetchDataOnMount, useSaveFlow } from './hooks';
|
| 6 |
|
|
@@ -39,13 +39,15 @@ const FlowList = () => {
|
|
| 39 |
)}
|
| 40 |
</Flex>
|
| 41 |
</Spin>
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
| 49 |
</Flex>
|
| 50 |
);
|
| 51 |
};
|
|
|
|
|
|
|
| 1 |
import { PlusOutlined } from '@ant-design/icons';
|
| 2 |
import { Button, Empty, Flex, Spin } from 'antd';
|
| 3 |
+
import CreateFlowModal from './create-flow-modal';
|
| 4 |
import FlowCard from './flow-card';
|
| 5 |
import { useFetchDataOnMount, useSaveFlow } from './hooks';
|
| 6 |
|
|
|
|
| 39 |
)}
|
| 40 |
</Flex>
|
| 41 |
</Spin>
|
| 42 |
+
{flowSettingVisible && (
|
| 43 |
+
<CreateFlowModal
|
| 44 |
+
visible={flowSettingVisible}
|
| 45 |
+
onOk={onFlowOk}
|
| 46 |
+
loading={flowSettingLoading}
|
| 47 |
+
hideModal={hideFlowSettingModal}
|
| 48 |
+
initialName=""
|
| 49 |
+
></CreateFlowModal>
|
| 50 |
+
)}
|
| 51 |
</Flex>
|
| 52 |
);
|
| 53 |
};
|