diff --git a/web/src/hooks/flow-hooks.ts b/web/src/hooks/flow-hooks.ts index 39b00ed82..8dc501a65 100644 --- a/web/src/hooks/flow-hooks.ts +++ b/web/src/hooks/flow-hooks.ts @@ -1,11 +1,12 @@ -import { DSL, IFlow } from '@/interfaces/database/flow'; +import { ResponseType } from '@/interfaces/database/base'; +import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow'; import i18n from '@/locales/config'; import flowService from '@/services/flow-service'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { message } from 'antd'; import { useParams } from 'umi'; -export const useFetchFlowTemplates = () => { +export const useFetchFlowTemplates = (): ResponseType => { const { data } = useQuery({ queryKey: ['fetchFlowTemplates'], initialData: [], diff --git a/web/src/hooks/logicHooks.ts b/web/src/hooks/logicHooks.ts index 36c5e7984..9fa960189 100644 --- a/web/src/hooks/logicHooks.ts +++ b/web/src/hooks/logicHooks.ts @@ -244,3 +244,28 @@ export const useHandleMessageInputChange = () => { }; // #endregion + +/** + * + * @param defaultId + * used to switch between different items, similar to radio + * @returns + */ +export const useSelectItem = (defaultId?: string) => { + const [selectedId, setSelectedId] = useState(''); + + const handleItemClick = useCallback( + (id: string) => () => { + setSelectedId(id); + }, + [], + ); + + useEffect(() => { + if (defaultId) { + setSelectedId(defaultId); + } + }, [defaultId]); + + return { selectedId, handleItemClick }; +}; diff --git a/web/src/interfaces/database/base.ts b/web/src/interfaces/database/base.ts index f4df72379..fe504cba7 100644 --- a/web/src/interfaces/database/base.ts +++ b/web/src/interfaces/database/base.ts @@ -1,6 +1,6 @@ -export interface ResponseType { +export interface ResponseType { retcode: number; - data: any; + data: T; retmsg: string; status: number; } diff --git a/web/src/interfaces/database/flow.ts b/web/src/interfaces/database/flow.ts index a06c7029f..8ddb56f30 100644 --- a/web/src/interfaces/database/flow.ts +++ b/web/src/interfaces/database/flow.ts @@ -42,3 +42,16 @@ export interface IFlow { update_time: number; user_id: string; } + +export interface IFlowTemplate { + avatar: string; + canvas_type: string; + create_date: string; + create_time: number; + description: string; + dsl: DSL; + id: string; + title: string; + update_date: string; + update_time: number; +} diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 924324ca3..6aeb4baa8 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -557,6 +557,7 @@ The above is the content you need to summarize.`, messageMsg: 'Please input message or delete this field.', addField: 'Add field', loop: 'Loop', + createFlow: 'Create a workflow', }, footer: { profile: 'All rights reserved @ React', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index eadb692bd..15f726a4a 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -524,6 +524,7 @@ export default { fileError: '文件错误', }, flow: { + flow: '工作流', cite: '引用', citeTip: 'citeTip', name: '名称', diff --git a/web/src/pages/flow/hooks.ts b/web/src/pages/flow/hooks.ts index be573ad31..77e351aba 100644 --- a/web/src/pages/flow/hooks.ts +++ b/web/src/pages/flow/hooks.ts @@ -1,9 +1,5 @@ import { useSetModalState } from '@/hooks/commonHooks'; -import { - useFetchFlow, - useFetchFlowTemplates, - useSetFlow, -} from '@/hooks/flow-hooks'; +import { useFetchFlow, useSetFlow } from '@/hooks/flow-hooks'; import { useFetchLlmList } from '@/hooks/llmHooks'; import { IGraph } from '@/interfaces/database/flow'; import { useIsFetching } from '@tanstack/react-query'; @@ -221,7 +217,6 @@ export const useFetchDataOnMount = () => { useWatchGraphChange(); - useFetchFlowTemplates(); useFetchLlmList(); return { loading, flowDetail: data }; diff --git a/web/src/pages/flow/list/create-flow-modal.tsx b/web/src/pages/flow/list/create-flow-modal.tsx new file mode 100644 index 000000000..e344f6f9c --- /dev/null +++ b/web/src/pages/flow/list/create-flow-modal.tsx @@ -0,0 +1,104 @@ +import { IModalManagerChildrenProps } from '@/components/modal-manager'; +import { useTranslate } from '@/hooks/commonHooks'; +import { useFetchFlowTemplates } from '@/hooks/flow-hooks'; +import { useSelectItem } from '@/hooks/logicHooks'; +import { UserOutlined } from '@ant-design/icons'; +import { + Avatar, + Card, + Flex, + Form, + Input, + Modal, + Space, + Typography, +} from 'antd'; +import classNames from 'classnames'; +import { useEffect } from 'react'; +import styles from './index.less'; + +const { Title } = Typography; +interface IProps extends Omit { + loading: boolean; + initialName: string; + onOk: (name: string, templateId: string) => void; + showModal?(): void; +} + +const CreateFlowModal = ({ + visible, + hideModal, + loading, + initialName, + onOk, +}: IProps) => { + const [form] = Form.useForm(); + const { t } = useTranslate('common'); + const { data: list } = useFetchFlowTemplates(); + const { selectedId, handleItemClick } = useSelectItem(list?.at(0)?.id); + + type FieldType = { + name?: string; + }; + + const handleOk = async () => { + const ret = await form.validateFields(); + + return onOk(ret.name, selectedId); + }; + + useEffect(() => { + if (visible) { + form.setFieldValue('name', initialName); + } + }, [initialName, form, visible]); + + return ( + +
+ + label={{t('name')}} + name="name" + rules={[{ required: true, message: t('namePlaceholder') }]} + > + + + + Choose from templates + + {list?.map((x) => ( + + + } src={x.avatar} /> + {x.title} + +

{x.description}

+
+ ))} +
+
+ ); +}; + +export default CreateFlowModal; diff --git a/web/src/pages/flow/list/hooks.ts b/web/src/pages/flow/list/hooks.ts index 41172071d..d11797611 100644 --- a/web/src/pages/flow/list/hooks.ts +++ b/web/src/pages/flow/list/hooks.ts @@ -1,10 +1,14 @@ import { useSetModalState } from '@/hooks/commonHooks'; -import { useFetchFlowList, useSetFlow } from '@/hooks/flow-hooks'; +import { + useFetchFlowList, + useFetchFlowTemplates, + useSetFlow, +} from '@/hooks/flow-hooks'; import { useCallback, useState } from 'react'; import { useNavigate } from 'umi'; // import { dsl } from '../mock'; -import headhunterZhComponents from '../../../../../graph/test/dsl_examples/headhunter_zh.json'; -import headhunter_zh from '../headhunter_zh.json'; +// import headhunterZhComponents from '../../../../../graph/test/dsl_examples/headhunter_zh.json'; +import dslJson from '../../../../../dls.json'; export const useFetchDataOnMount = () => { const { data, loading } = useFetchFlowList(); @@ -21,12 +25,19 @@ export const useSaveFlow = () => { } = useSetModalState(); const { loading, setFlow } = useSetFlow(); const navigate = useNavigate(); + const { data: list } = useFetchFlowTemplates(); const onFlowOk = useCallback( - async (title: string) => { + async (title: string, templateId: string) => { + const templateItem = list.find((x) => x.id === templateId); + + let dsl = templateItem?.dsl; + // if (dsl) { + // dsl.graph = headhunter_zh; + // } const ret = await setFlow({ title, - dsl: { ...headhunterZhComponents, graph: headhunter_zh }, + dsl: dslJson, }); if (ret?.retcode === 0) { @@ -34,7 +45,7 @@ export const useSaveFlow = () => { navigate(`/flow/${ret.data.id}`); } }, - [setFlow, hideFlowSettingModal, navigate], + [setFlow, hideFlowSettingModal, navigate, list], ); const handleShowFlowSettingModal = useCallback( diff --git a/web/src/pages/flow/list/index.less b/web/src/pages/flow/list/index.less index 6c171193f..7b4555488 100644 --- a/web/src/pages/flow/list/index.less +++ b/web/src/pages/flow/list/index.less @@ -46,3 +46,11 @@ width: 100%; } } + +.flowTemplateCard { + cursor: pointer; +} + +.selectedFlowTemplateCard { + background-color: @selectedBackgroundColor; +} diff --git a/web/src/pages/flow/list/index.tsx b/web/src/pages/flow/list/index.tsx index b4448106a..0f4b61453 100644 --- a/web/src/pages/flow/list/index.tsx +++ b/web/src/pages/flow/list/index.tsx @@ -1,6 +1,6 @@ -import RenameModal from '@/components/rename-modal'; import { PlusOutlined } from '@ant-design/icons'; import { Button, Empty, Flex, Spin } from 'antd'; +import CreateFlowModal from './create-flow-modal'; import FlowCard from './flow-card'; import { useFetchDataOnMount, useSaveFlow } from './hooks'; @@ -39,13 +39,15 @@ const FlowList = () => { )} - + {flowSettingVisible && ( + + )} ); };