mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-14 17:05:53 +08:00
### What problem does this PR solve? feat: add CreateFlowModal #918 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
04487d1bce
commit
f9adeb9647
@ -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<IFlowTemplate[]> => {
|
||||
const { data } = useQuery({
|
||||
queryKey: ['fetchFlowTemplates'],
|
||||
initialData: [],
|
||||
|
@ -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 };
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
export interface ResponseType {
|
||||
export interface ResponseType<T = any> {
|
||||
retcode: number;
|
||||
data: any;
|
||||
data: T;
|
||||
retmsg: string;
|
||||
status: number;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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',
|
||||
|
@ -524,6 +524,7 @@ export default {
|
||||
fileError: '文件错误',
|
||||
},
|
||||
flow: {
|
||||
flow: '工作流',
|
||||
cite: '引用',
|
||||
citeTip: 'citeTip',
|
||||
name: '名称',
|
||||
|
@ -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 };
|
||||
|
104
web/src/pages/flow/list/create-flow-modal.tsx
Normal file
104
web/src/pages/flow/list/create-flow-modal.tsx
Normal file
@ -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<IModalManagerChildrenProps, 'showModal'> {
|
||||
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 (
|
||||
<Modal
|
||||
title={t('createFlow', { keyPrefix: 'flow' })}
|
||||
open={visible}
|
||||
onOk={handleOk}
|
||||
width={600}
|
||||
onCancel={hideModal}
|
||||
okButtonProps={{ loading }}
|
||||
confirmLoading={loading}
|
||||
>
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 4 }}
|
||||
wrapperCol={{ span: 20 }}
|
||||
autoComplete="off"
|
||||
layout={'vertical'}
|
||||
form={form}
|
||||
>
|
||||
<Form.Item<FieldType>
|
||||
label={<b>{t('name')}</b>}
|
||||
name="name"
|
||||
rules={[{ required: true, message: t('namePlaceholder') }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
<Title level={5}>Choose from templates</Title>
|
||||
<Flex vertical gap={16}>
|
||||
{list?.map((x) => (
|
||||
<Card
|
||||
key={x.id}
|
||||
className={classNames(styles.flowTemplateCard, {
|
||||
[styles.selectedFlowTemplateCard]: selectedId === x.id,
|
||||
})}
|
||||
onClick={handleItemClick(x.id)}
|
||||
>
|
||||
<Space size={'middle'}>
|
||||
<Avatar size={40} icon={<UserOutlined />} src={x.avatar} />
|
||||
<b>{x.title}</b>
|
||||
</Space>
|
||||
<p>{x.description}</p>
|
||||
</Card>
|
||||
))}
|
||||
</Flex>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateFlowModal;
|
@ -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(
|
||||
|
@ -46,3 +46,11 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.flowTemplateCard {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selectedFlowTemplateCard {
|
||||
background-color: @selectedBackgroundColor;
|
||||
}
|
||||
|
@ -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 = () => {
|
||||
)}
|
||||
</Flex>
|
||||
</Spin>
|
||||
<RenameModal
|
||||
visible={flowSettingVisible}
|
||||
onOk={onFlowOk}
|
||||
loading={flowSettingLoading}
|
||||
hideModal={hideFlowSettingModal}
|
||||
initialName=""
|
||||
></RenameModal>
|
||||
{flowSettingVisible && (
|
||||
<CreateFlowModal
|
||||
visible={flowSettingVisible}
|
||||
onOk={onFlowOk}
|
||||
loading={flowSettingLoading}
|
||||
hideModal={hideFlowSettingModal}
|
||||
initialName=""
|
||||
></CreateFlowModal>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user