mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-08-22 02:04:37 +00:00
feat: Bring In Template (#1975)
# Description Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. # How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration # Snapshots: Include snapshots for easier review. # Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have already rebased the commits and make the commit message conform to the project standard. - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] Any dependent changes have been merged and published in downstream modules
This commit is contained in:
commit
59bbe9ba7a
@ -67,14 +67,14 @@ export const downloadFile = (fileId: string) => {
|
|||||||
return GET<null, any>(`/api/v2/serve/file/files/dbgpt/${fileId}`);
|
return GET<null, any>(`/api/v2/serve/file/files/dbgpt/${fileId}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getFlowTemplateList = () => {
|
|
||||||
return GET<null, Array<any>>('/api/v2/serve/awel/flow/templates');
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getFlowTemplateById = (id: string) => {
|
export const getFlowTemplateById = (id: string) => {
|
||||||
return GET<null, any>(`/api/v2/serve/awel/flow/templates/${id}`);
|
return GET<null, any>(`/api/v2/serve/awel/flow/templates/${id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getFlowTemplates = () => {
|
||||||
|
return GET<null, any>(`/api/v2/serve/awel/flow/templates`);
|
||||||
|
};
|
||||||
|
|
||||||
export const getKeys = (data?: IGetKeysRequestParams) => {
|
export const getKeys = (data?: IGetKeysRequestParams) => {
|
||||||
return GET<IGetKeysRequestParams, Array<IGetKeysResponseData>>('/api/v2/serve/awel/variables/keys', data);
|
return GET<IGetKeysRequestParams, Array<IGetKeysResponseData>>('/api/v2/serve/awel/variables/keys', data);
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,7 @@ import { Button, Form, GetProp, Modal, Radio, Upload, UploadFile, UploadProps, m
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Edge, Node } from 'reactflow';
|
import { Edge, Node } from 'reactflow';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isImportModalOpen: boolean;
|
isImportModalOpen: boolean;
|
||||||
setNodes: React.Dispatch<React.SetStateAction<Node<any, string | undefined>[]>>;
|
setNodes: React.Dispatch<React.SetStateAction<Node<any, string | undefined>[]>>;
|
||||||
@ -39,7 +40,7 @@ export const ImportFlowModal: React.FC<Props> = ({ isImportModalOpen, setIsImpor
|
|||||||
if (res?.success) {
|
if (res?.success) {
|
||||||
messageApi.success(t('Import_Flow_Success'));
|
messageApi.success(t('Import_Flow_Success'));
|
||||||
localStorage.setItem('importFlowData', JSON.stringify(res?.data));
|
localStorage.setItem('importFlowData', JSON.stringify(res?.data));
|
||||||
CanvasWrapper(res?.data);
|
CanvasWrapper();
|
||||||
} else if (res?.err_msg) {
|
} else if (res?.err_msg) {
|
||||||
messageApi.error(res?.err_msg);
|
messageApi.error(res?.err_msg);
|
||||||
}
|
}
|
||||||
|
@ -2,3 +2,4 @@ export * from './add-flow-variable-modal';
|
|||||||
export * from './export-flow-modal';
|
export * from './export-flow-modal';
|
||||||
export * from './import-flow-modal';
|
export * from './import-flow-modal';
|
||||||
export * from './save-flow-modal';
|
export * from './save-flow-modal';
|
||||||
|
export * from './template-flow-modal';
|
||||||
|
78
web/components/flow/canvas-modal/template-flow-modal.tsx
Normal file
78
web/components/flow/canvas-modal/template-flow-modal.tsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { getFlowTemplates } from '@/client/api';
|
||||||
|
import CanvasWrapper from '@/pages/construct/flow/canvas/index';
|
||||||
|
import type { TableProps } from 'antd';
|
||||||
|
import { Button, Modal, Space, Table } from 'antd';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isFlowTemplateModalOpen: boolean;
|
||||||
|
setIsFlowTemplateModalOpen: (value: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface DataType {
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
address: string;
|
||||||
|
tags: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FlowTemplateModal: React.FC<Props> = ({ isFlowTemplateModalOpen, setIsFlowTemplateModalOpen }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [dataSource, setDataSource] = useState([]);
|
||||||
|
|
||||||
|
const onTemplateImport = (record: DataType) => {
|
||||||
|
if (record?.name) {
|
||||||
|
localStorage.setItem('importFlowData', JSON.stringify(record));
|
||||||
|
CanvasWrapper();
|
||||||
|
setIsFlowTemplateModalOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns: TableProps<DataType>['columns'] = [
|
||||||
|
{
|
||||||
|
title: t('Template_Name'),
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Template_Action'),
|
||||||
|
key: 'action',
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space size='middle'>
|
||||||
|
<Button
|
||||||
|
type='link'
|
||||||
|
onClick={() => {
|
||||||
|
onTemplateImport(record);
|
||||||
|
}}
|
||||||
|
block
|
||||||
|
>
|
||||||
|
{t('Import_From_Template')}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getFlowTemplates().then(res => {
|
||||||
|
console.log(res);
|
||||||
|
setDataSource(res?.data?.data?.items);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Modal
|
||||||
|
title={t('Import_From_Template')}
|
||||||
|
open={isFlowTemplateModalOpen}
|
||||||
|
onCancel={() => setIsFlowTemplateModalOpen(false)}
|
||||||
|
cancelButtonProps={{ className: 'hidden' }}
|
||||||
|
okButtonProps={{ className: 'hidden' }}
|
||||||
|
>
|
||||||
|
<Table dataSource={dataSource} columns={columns} />;
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -1,12 +1,12 @@
|
|||||||
/* eslint-disable react-hooks/rules-of-hooks */
|
/* eslint-disable react-hooks/rules-of-hooks */
|
||||||
|
import { metadataBatch } from '@/client/api';
|
||||||
import { IFlowNodeParameter } from '@/types/flow';
|
import { IFlowNodeParameter } from '@/types/flow';
|
||||||
import { convertKeysToCamelCase } from '@/utils/flow';
|
import { convertKeysToCamelCase } from '@/utils/flow';
|
||||||
import { UploadOutlined } from '@ant-design/icons';
|
import { UploadOutlined } from '@ant-design/icons';
|
||||||
import type { UploadProps,UploadFile } from 'antd';
|
import type { UploadFile, UploadProps } from 'antd';
|
||||||
import { Button, Upload, message } from 'antd';
|
import { Button, Upload, message } from 'antd';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { metadataBatch } from '@/client/api';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
formValuesChange: any;
|
formValuesChange: any;
|
||||||
@ -17,31 +17,33 @@ export const renderUpload = (params: Props) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const urlList = useRef<string[]>([]);
|
const urlList = useRef<string[]>([]);
|
||||||
const { data, formValuesChange } = params;
|
const { data, formValuesChange } = params;
|
||||||
const [fileList, setFileList] = useState<UploadFile[]>([])
|
const [fileList, setFileList] = useState<UploadFile[]>([]);
|
||||||
|
|
||||||
// 获取上传文件元数据
|
// 获取上传文件元数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data.value) {
|
if (data.value) {
|
||||||
let uris:string[] = []
|
let uris: string[] = [];
|
||||||
typeof(data.value) === 'string'? uris.push(data.value):uris = data.value
|
typeof data.value === 'string' ? uris.push(data.value) : (uris = data.value);
|
||||||
let parameter:any = {
|
const parameter: any = {
|
||||||
uris
|
uris,
|
||||||
}
|
};
|
||||||
metadataBatch(parameter).then((res)=>{
|
metadataBatch(parameter)
|
||||||
let urlList:UploadFile[] = []
|
.then(res => {
|
||||||
|
const urlList: UploadFile[] = [];
|
||||||
for (let index = 0; index < res.data.data.length; index++) {
|
for (let index = 0; index < res.data.data.length; index++) {
|
||||||
const element = res.data.data[index];
|
const element = res.data.data[index];
|
||||||
urlList.push({
|
urlList.push({
|
||||||
uid: element.file_id,
|
uid: element.file_id,
|
||||||
name:element.file_name,
|
name: element.file_name,
|
||||||
status: 'done',
|
status: 'done',
|
||||||
url: element.uri,
|
url: element.uri,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
setFileList(urlList)
|
setFileList(urlList);
|
||||||
}).catch((error)=>{
|
|
||||||
console.log(error)
|
|
||||||
})
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -102,7 +104,13 @@ export const renderUpload = (params: Props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='p-2 text-sm text-center'>
|
<div className='p-2 text-sm text-center'>
|
||||||
<Upload onRemove={handleFileRemove} {...props} {...attr} multiple={data.is_list?true:false} accept={uploadType}>
|
<Upload
|
||||||
|
onRemove={handleFileRemove}
|
||||||
|
{...props}
|
||||||
|
{...attr}
|
||||||
|
multiple={data.is_list ? true : false}
|
||||||
|
accept={uploadType}
|
||||||
|
>
|
||||||
<Button loading={uploading} icon={<UploadOutlined />}>
|
<Button loading={uploading} icon={<UploadOutlined />}>
|
||||||
{t('Upload_Data')}
|
{t('Upload_Data')}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -21,4 +21,7 @@ export const FlowEn = {
|
|||||||
Add_Parameter: 'Add Parameter',
|
Add_Parameter: 'Add Parameter',
|
||||||
Higher_Order_Nodes: 'Higher Order',
|
Higher_Order_Nodes: 'Higher Order',
|
||||||
All_Nodes: 'All',
|
All_Nodes: 'All',
|
||||||
|
Import_From_Template: 'Import from template',
|
||||||
|
Template_Name: 'Template Name',
|
||||||
|
Template_Action: 'Action',
|
||||||
};
|
};
|
||||||
|
@ -21,4 +21,7 @@ export const FlowZn = {
|
|||||||
Add_Parameter: '添加参数',
|
Add_Parameter: '添加参数',
|
||||||
Higher_Order_Nodes: '高阶',
|
Higher_Order_Nodes: '高阶',
|
||||||
All_Nodes: '所有',
|
All_Nodes: '所有',
|
||||||
|
Import_Template: '从模版导入',
|
||||||
|
Template_Name: '模版名称',
|
||||||
|
Template_Action: '操作',
|
||||||
};
|
};
|
||||||
|
@ -2,11 +2,17 @@ import { apiInterceptors, getFlowById } from '@/client/api';
|
|||||||
import MuiLoading from '@/components/common/loading';
|
import MuiLoading from '@/components/common/loading';
|
||||||
import AddNodesSider from '@/components/flow/add-nodes-sider';
|
import AddNodesSider from '@/components/flow/add-nodes-sider';
|
||||||
import ButtonEdge from '@/components/flow/button-edge';
|
import ButtonEdge from '@/components/flow/button-edge';
|
||||||
import { AddFlowVariableModal, ExportFlowModal, ImportFlowModal, SaveFlowModal } from '@/components/flow/canvas-modal';
|
import {
|
||||||
|
AddFlowVariableModal,
|
||||||
|
ExportFlowModal,
|
||||||
|
FlowTemplateModal,
|
||||||
|
ImportFlowModal,
|
||||||
|
SaveFlowModal,
|
||||||
|
} from '@/components/flow/canvas-modal';
|
||||||
import CanvasNode from '@/components/flow/canvas-node';
|
import CanvasNode from '@/components/flow/canvas-node';
|
||||||
import { IFlowData, IFlowUpdateParam } from '@/types/flow';
|
import { IFlowData, IFlowUpdateParam } from '@/types/flow';
|
||||||
import { checkFlowDataRequied, getUniqueNodeId, mapUnderlineToHump } from '@/utils/flow';
|
import { checkFlowDataRequied, getUniqueNodeId, mapUnderlineToHump } from '@/utils/flow';
|
||||||
import { ExportOutlined, FrownOutlined, ImportOutlined, SaveOutlined } from '@ant-design/icons';
|
import { ExportOutlined, FileAddOutlined, FrownOutlined, ImportOutlined, SaveOutlined } from '@ant-design/icons';
|
||||||
import { Divider, Space, Tooltip, message, notification } from 'antd';
|
import { Divider, Space, Tooltip, message, notification } from 'antd';
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
import React, { DragEvent, useCallback, useEffect, useRef, useState } from 'react';
|
import React, { DragEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
@ -43,6 +49,7 @@ const Canvas: React.FC = () => {
|
|||||||
const [isSaveFlowModalOpen, setIsSaveFlowModalOpen] = useState(false);
|
const [isSaveFlowModalOpen, setIsSaveFlowModalOpen] = useState(false);
|
||||||
const [isExportFlowModalOpen, setIsExportFlowModalOpen] = useState(false);
|
const [isExportFlowModalOpen, setIsExportFlowModalOpen] = useState(false);
|
||||||
const [isImportModalOpen, setIsImportFlowModalOpen] = useState(false);
|
const [isImportModalOpen, setIsImportFlowModalOpen] = useState(false);
|
||||||
|
const [isFlowTemplateModalOpen, setIsFlowTemplateModalOpen] = useState(false);
|
||||||
|
|
||||||
if (localStorage.getItem('importFlowData')) {
|
if (localStorage.getItem('importFlowData')) {
|
||||||
const importFlowData = JSON.parse(localStorage.getItem('importFlowData') || '');
|
const importFlowData = JSON.parse(localStorage.getItem('importFlowData') || '');
|
||||||
@ -191,19 +198,15 @@ const Canvas: React.FC = () => {
|
|||||||
setIsSaveFlowModalOpen(true);
|
setIsSaveFlowModalOpen(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onExport() {
|
|
||||||
setIsExportFlowModalOpen(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onImport() {
|
|
||||||
setIsImportFlowModalOpen(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const getButtonList = () => {
|
const getButtonList = () => {
|
||||||
const buttonList = [
|
const buttonList = [
|
||||||
|
{
|
||||||
|
title: t('template'),
|
||||||
|
icon: <FileAddOutlined className='block text-xl' onClick={() => setIsFlowTemplateModalOpen(true)} />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t('Import'),
|
title: t('Import'),
|
||||||
icon: <ImportOutlined className='block text-xl' onClick={onImport} />,
|
icon: <ImportOutlined className='block text-xl' onClick={() => setIsImportFlowModalOpen(true)} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('save'),
|
title: t('save'),
|
||||||
@ -214,7 +217,7 @@ const Canvas: React.FC = () => {
|
|||||||
if (id !== '') {
|
if (id !== '') {
|
||||||
buttonList.unshift({
|
buttonList.unshift({
|
||||||
title: t('Export'),
|
title: t('Export'),
|
||||||
icon: <ExportOutlined className='block text-xl' onClick={onExport} />,
|
icon: <ExportOutlined className='block text-xl' onClick={() => setIsExportFlowModalOpen(true)} />,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,6 +293,11 @@ const Canvas: React.FC = () => {
|
|||||||
setIsImportFlowModalOpen={setIsImportFlowModalOpen}
|
setIsImportFlowModalOpen={setIsImportFlowModalOpen}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FlowTemplateModal
|
||||||
|
isFlowTemplateModalOpen={isFlowTemplateModalOpen}
|
||||||
|
setIsFlowTemplateModalOpen={setIsFlowTemplateModalOpen}
|
||||||
|
/>
|
||||||
|
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user