mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-08-21 01:34:24 +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}`);
|
||||
};
|
||||
|
||||
export const getFlowTemplateList = () => {
|
||||
return GET<null, Array<any>>('/api/v2/serve/awel/flow/templates');
|
||||
};
|
||||
|
||||
export const getFlowTemplateById = (id: string) => {
|
||||
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) => {
|
||||
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 { useTranslation } from 'react-i18next';
|
||||
import { Edge, Node } from 'reactflow';
|
||||
|
||||
type Props = {
|
||||
isImportModalOpen: boolean;
|
||||
setNodes: React.Dispatch<React.SetStateAction<Node<any, string | undefined>[]>>;
|
||||
@ -39,7 +40,7 @@ export const ImportFlowModal: React.FC<Props> = ({ isImportModalOpen, setIsImpor
|
||||
if (res?.success) {
|
||||
messageApi.success(t('Import_Flow_Success'));
|
||||
localStorage.setItem('importFlowData', JSON.stringify(res?.data));
|
||||
CanvasWrapper(res?.data);
|
||||
CanvasWrapper();
|
||||
} else if (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 './import-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 */
|
||||
import { metadataBatch } from '@/client/api';
|
||||
import { IFlowNodeParameter } from '@/types/flow';
|
||||
import { convertKeysToCamelCase } from '@/utils/flow';
|
||||
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 { useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { metadataBatch } from '@/client/api';
|
||||
|
||||
type Props = {
|
||||
formValuesChange: any;
|
||||
@ -17,31 +17,33 @@ export const renderUpload = (params: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const urlList = useRef<string[]>([]);
|
||||
const { data, formValuesChange } = params;
|
||||
const [fileList, setFileList] = useState<UploadFile[]>([])
|
||||
const [fileList, setFileList] = useState<UploadFile[]>([]);
|
||||
|
||||
// 获取上传文件元数据
|
||||
useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (data.value) {
|
||||
let uris:string[] = []
|
||||
typeof(data.value) === 'string'? uris.push(data.value):uris = data.value
|
||||
let parameter:any = {
|
||||
uris
|
||||
}
|
||||
metadataBatch(parameter).then((res)=>{
|
||||
let urlList:UploadFile[] = []
|
||||
for (let index = 0; index < res.data.data.length; index++) {
|
||||
const element = res.data.data[index];
|
||||
urlList.push({
|
||||
let uris: string[] = [];
|
||||
typeof data.value === 'string' ? uris.push(data.value) : (uris = data.value);
|
||||
const parameter: any = {
|
||||
uris,
|
||||
};
|
||||
metadataBatch(parameter)
|
||||
.then(res => {
|
||||
const urlList: UploadFile[] = [];
|
||||
for (let index = 0; index < res.data.data.length; index++) {
|
||||
const element = res.data.data[index];
|
||||
urlList.push({
|
||||
uid: element.file_id,
|
||||
name:element.file_name,
|
||||
name: element.file_name,
|
||||
status: 'done',
|
||||
url: element.uri,
|
||||
})
|
||||
}
|
||||
setFileList(urlList)
|
||||
}).catch((error)=>{
|
||||
console.log(error)
|
||||
})
|
||||
});
|
||||
}
|
||||
setFileList(urlList);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
@ -102,11 +104,17 @@ export const renderUpload = (params: Props) => {
|
||||
|
||||
return (
|
||||
<div className='p-2 text-sm text-center'>
|
||||
<Upload onRemove={handleFileRemove} {...props} {...attr} multiple={data.is_list?true:false} accept={uploadType}>
|
||||
<Button loading={uploading} icon={<UploadOutlined />}>
|
||||
{t('Upload_Data')}
|
||||
</Button>
|
||||
</Upload>
|
||||
<Upload
|
||||
onRemove={handleFileRemove}
|
||||
{...props}
|
||||
{...attr}
|
||||
multiple={data.is_list ? true : false}
|
||||
accept={uploadType}
|
||||
>
|
||||
<Button loading={uploading} icon={<UploadOutlined />}>
|
||||
{t('Upload_Data')}
|
||||
</Button>
|
||||
</Upload>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -21,4 +21,7 @@ export const FlowEn = {
|
||||
Add_Parameter: 'Add Parameter',
|
||||
Higher_Order_Nodes: 'Higher Order',
|
||||
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: '添加参数',
|
||||
Higher_Order_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 AddNodesSider from '@/components/flow/add-nodes-sider';
|
||||
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 { IFlowData, IFlowUpdateParam } from '@/types/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 { useSearchParams } from 'next/navigation';
|
||||
import React, { DragEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||
@ -43,6 +49,7 @@ const Canvas: React.FC = () => {
|
||||
const [isSaveFlowModalOpen, setIsSaveFlowModalOpen] = useState(false);
|
||||
const [isExportFlowModalOpen, setIsExportFlowModalOpen] = useState(false);
|
||||
const [isImportModalOpen, setIsImportFlowModalOpen] = useState(false);
|
||||
const [isFlowTemplateModalOpen, setIsFlowTemplateModalOpen] = useState(false);
|
||||
|
||||
if (localStorage.getItem('importFlowData')) {
|
||||
const importFlowData = JSON.parse(localStorage.getItem('importFlowData') || '');
|
||||
@ -191,19 +198,15 @@ const Canvas: React.FC = () => {
|
||||
setIsSaveFlowModalOpen(true);
|
||||
}
|
||||
|
||||
function onExport() {
|
||||
setIsExportFlowModalOpen(true);
|
||||
}
|
||||
|
||||
function onImport() {
|
||||
setIsImportFlowModalOpen(true);
|
||||
}
|
||||
|
||||
const getButtonList = () => {
|
||||
const buttonList = [
|
||||
{
|
||||
title: t('template'),
|
||||
icon: <FileAddOutlined className='block text-xl' onClick={() => setIsFlowTemplateModalOpen(true)} />,
|
||||
},
|
||||
{
|
||||
title: t('Import'),
|
||||
icon: <ImportOutlined className='block text-xl' onClick={onImport} />,
|
||||
icon: <ImportOutlined className='block text-xl' onClick={() => setIsImportFlowModalOpen(true)} />,
|
||||
},
|
||||
{
|
||||
title: t('save'),
|
||||
@ -214,7 +217,7 @@ const Canvas: React.FC = () => {
|
||||
if (id !== '') {
|
||||
buttonList.unshift({
|
||||
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}
|
||||
/>
|
||||
|
||||
<FlowTemplateModal
|
||||
isFlowTemplateModalOpen={isFlowTemplateModalOpen}
|
||||
setIsFlowTemplateModalOpen={setIsFlowTemplateModalOpen}
|
||||
/>
|
||||
|
||||
{contextHolder}
|
||||
</>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user