Feat: Upload agent file #3221 (#5311)

### What problem does this PR solve?

Feat: Upload agent file #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-02-24 19:30:33 +08:00
committed by GitHub
parent fda9b58ab7
commit 033a4cf21e
12 changed files with 450 additions and 45 deletions

View File

@ -1,9 +1,10 @@
import { FileMimeType } from '@/constants/common';
import { useToast } from '@/components/hooks/use-toast';
import { FileMimeType, Platform } from '@/constants/common';
import { useSetModalState } from '@/hooks/common-hooks';
import { useFetchFlow } from '@/hooks/flow-hooks';
import { IGraph } from '@/interfaces/database/flow';
import { downloadJsonFile } from '@/utils/file-util';
import { message, UploadFile } from 'antd';
import { message } from 'antd';
import isEmpty from 'lodash/isEmpty';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
@ -20,13 +21,21 @@ export const useHandleExportOrImportJsonFile = () => {
const setGraphInfo = useSetGraphInfo();
const { data } = useFetchFlow();
const { t } = useTranslation();
const { toast } = useToast();
const onFileUploadOk = useCallback(
async (fileList: UploadFile[]) => {
async ({
fileList,
platform,
}: {
fileList: File[];
platform: Platform;
}) => {
console.log('🚀 ~ useHandleExportOrImportJsonFile ~ platform:', platform);
if (fileList.length > 0) {
const file: File = fileList[0] as unknown as File;
const file = fileList[0];
if (file.type !== FileMimeType.Json) {
message.error(t('flow.jsonUploadTypeErrorMessage'));
toast({ title: t('flow.jsonUploadTypeErrorMessage') });
return;
}
@ -45,7 +54,7 @@ export const useHandleExportOrImportJsonFile = () => {
}
}
},
[hideFileUploadModal, setGraphInfo, t],
[hideFileUploadModal, setGraphInfo, t, toast],
);
const handleExportJson = useCallback(() => {

View File

@ -1,12 +1,35 @@
import { PageHeader } from '@/components/page-header';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar';
import { useSetModalState } from '@/hooks/common-hooks';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { Trash2 } from 'lucide-react';
import { CodeXml, EllipsisVertical, Forward, Import, Key } from 'lucide-react';
import { ComponentPropsWithoutRef } from 'react';
import { useTranslation } from 'react-i18next';
import { AgentSidebar } from './agent-sidebar';
import FlowCanvas from './canvas';
import { useHandleExportOrImportJsonFile } from './hooks/use-export-json';
import { useFetchDataOnMount } from './hooks/use-fetch-data';
import { useOpenDocument } from './hooks/use-open-document';
import { UploadAgentDialog } from './upload-agent-dialog';
function AgentDropdownMenuItem({
children,
...props
}: ComponentPropsWithoutRef<typeof DropdownMenuItem>) {
return (
<DropdownMenuItem className="flex justify-between items-center" {...props}>
{children}
</DropdownMenuItem>
);
}
export default function Agent() {
const { navigateToAgentList } = useNavigatePage();
@ -15,6 +38,15 @@ export default function Agent() {
hideModal: hideChatDrawer,
showModal: showChatDrawer,
} = useSetModalState();
const { t } = useTranslation();
const openDocument = useOpenDocument();
const {
handleExportJson,
handleImportJson,
fileUploadVisible,
onFileUploadOk,
hideFileUploadModal,
} = useHandleExportOrImportJsonFile();
useFetchDataOnMount();
@ -22,15 +54,38 @@ export default function Agent() {
<section>
<PageHeader back={navigateToAgentList} title="Agent 01">
<div className="flex items-center gap-2">
<Button variant={'icon'} size={'icon'}>
<Trash2 />
</Button>
<DropdownMenu>
<DropdownMenuTrigger>
<Button variant={'icon'} size={'icon'}>
<EllipsisVertical />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<AgentDropdownMenuItem onClick={openDocument}>
API
<Key />
</AgentDropdownMenuItem>
<DropdownMenuSeparator />
<AgentDropdownMenuItem onClick={handleImportJson}>
Import
<Import />
</AgentDropdownMenuItem>
<DropdownMenuSeparator />
<AgentDropdownMenuItem onClick={handleExportJson}>
Export
<Forward />
</AgentDropdownMenuItem>
<DropdownMenuSeparator />
<AgentDropdownMenuItem>
{t('common.embedIntoSite')}
<CodeXml />
</AgentDropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Button variant={'outline'} size={'sm'}>
Save
</Button>
<Button variant={'outline'} size={'sm'}>
API
</Button>
<Button variant={'outline'} size={'sm'}>
Run app
</Button>
@ -54,6 +109,12 @@ export default function Agent() {
</div>
</SidebarProvider>
</div>
{fileUploadVisible && (
<UploadAgentDialog
hideModal={hideFileUploadModal}
onOk={onFileUploadOk}
></UploadAgentDialog>
)}
</section>
);
}

View File

@ -0,0 +1,36 @@
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { LoadingButton } from '@/components/ui/loading-button';
import { IModalProps } from '@/interfaces/common';
import { TagRenameId } from '@/pages/add-knowledge/constant';
import { useTranslation } from 'react-i18next';
import { UploadAgentForm } from './upload-agent-form';
export function UploadAgentDialog({
hideModal,
onOk,
loading,
}: IModalProps<any>) {
const { t } = useTranslation();
return (
<Dialog open onOpenChange={hideModal}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>{t('fileManager.uploadFile')}</DialogTitle>
</DialogHeader>
<UploadAgentForm hideModal={hideModal} onOk={onOk}></UploadAgentForm>
<DialogFooter>
<LoadingButton type="submit" form={TagRenameId} loading={loading}>
{t('common.save')}
</LoadingButton>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

View File

@ -0,0 +1,91 @@
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { FileUploader } from '@/components/file-uploader';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { RAGFlowSelect } from '@/components/ui/select';
import { FileMimeType, Platform } from '@/constants/common';
import { IModalProps } from '@/interfaces/common';
import { TagRenameId } from '@/pages/add-knowledge/constant';
import { useTranslation } from 'react-i18next';
const options = Object.values(Platform).map((x) => ({ label: x, value: x }));
export function UploadAgentForm({ hideModal, onOk }: IModalProps<any>) {
const { t } = useTranslation();
const FormSchema = z.object({
platform: z
.string()
.min(1, {
message: t('common.namePlaceholder'),
})
.trim(),
fileList: z.array(z.instanceof(File)),
});
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: { platform: Platform.RAGFlow },
});
async function onSubmit(data: z.infer<typeof FormSchema>) {
console.log('🚀 ~ onSubmit ~ data:', data);
const ret = await onOk?.(data);
if (ret) {
hideModal?.();
}
}
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-6"
id={TagRenameId}
>
<FormField
control={form.control}
name="fileList"
render={({ field }) => (
<FormItem>
<FormLabel>{t('common.name')}</FormLabel>
<FormControl>
<FileUploader
value={field.value}
onValueChange={field.onChange}
maxFileCount={1}
maxSize={4 * 1024 * 1024}
accept={{ '*.json': [FileMimeType.Json] }}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="platform"
render={({ field }) => (
<FormItem>
<FormLabel>{t('common.name')}</FormLabel>
<FormControl>
<RAGFlowSelect {...field} options={options} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</form>
</Form>
);
}