Feat: Import dsl from agent list page #9869 (#10033)

### What problem does this PR solve?

Feat: Import dsl from agent list page #9869

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-09-10 18:22:16 +08:00
committed by GitHub
parent fc95d113c3
commit df8d31451b
14 changed files with 213 additions and 215 deletions

View File

@ -24,9 +24,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useDebounce } from 'ahooks'; import { useDebounce } from 'ahooks';
import { get, set } from 'lodash'; import { get, set } from 'lodash';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams, useSearchParams } from 'umi'; import { useParams, useSearchParams } from 'umi';
import { v4 as uuid } from 'uuid';
import { import {
useGetPaginationWithRouter, useGetPaginationWithRouter,
useHandleSearchChange, useHandleSearchChange,
@ -80,7 +78,7 @@ export const EmptyDsl = {
component_name: 'Begin', component_name: 'Begin',
params: {}, params: {},
}, },
downstream: ['Answer:China'], // other edge target is downstream, edge source is current node id downstream: [], // other edge target is downstream, edge source is current node id
upstream: [], // edge source is upstream, edge target is current node id upstream: [], // edge source is upstream, edge target is current node id
}, },
}, },
@ -96,21 +94,11 @@ export const EmptyDsl = {
}; };
export const useFetchAgentTemplates = () => { export const useFetchAgentTemplates = () => {
const { t } = useTranslation();
const { data } = useQuery<IFlowTemplate[]>({ const { data } = useQuery<IFlowTemplate[]>({
queryKey: [AgentApiAction.FetchAgentTemplates], queryKey: [AgentApiAction.FetchAgentTemplates],
initialData: [], initialData: [],
queryFn: async () => { queryFn: async () => {
const { data } = await agentService.listTemplates(); const { data } = await agentService.listTemplates();
if (Array.isArray(data?.data)) {
data.data.unshift({
id: uuid(),
title: t('flow.blank'),
description: t('flow.createFromNothing'),
dsl: EmptyDsl,
});
}
return data.data; return data.data;
}, },

View File

@ -41,8 +41,8 @@ export interface DSL {
path?: string[]; path?: string[];
answer?: any[]; answer?: any[];
graph?: IGraph; graph?: IGraph;
messages: Message[]; messages?: Message[];
reference: IReference[]; reference?: IReference[];
globals: Record<string, any>; globals: Record<string, any>;
retrieval: IReference[]; retrieval: IReference[];
} }

View File

@ -1,71 +1,17 @@
import { useToast } from '@/components/hooks/use-toast';
import { FileMimeType, Platform } from '@/constants/common';
import { useSetModalState } from '@/hooks/common-hooks';
import { useFetchAgent } from '@/hooks/use-agent-request'; import { useFetchAgent } from '@/hooks/use-agent-request';
import { IGraph } from '@/interfaces/database/flow';
import { downloadJsonFile } from '@/utils/file-util'; import { downloadJsonFile } from '@/utils/file-util';
import { message } from 'antd';
import isEmpty from 'lodash/isEmpty';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useBuildDslData } from './use-build-dsl'; import { useBuildDslData } from './use-build-dsl';
import { useSetGraphInfo } from './use-set-graph';
export const useHandleExportOrImportJsonFile = () => { export const useHandleExportJsonFile = () => {
const { buildDslData } = useBuildDslData(); const { buildDslData } = useBuildDslData();
const {
visible: fileUploadVisible,
hideModal: hideFileUploadModal,
showModal: showFileUploadModal,
} = useSetModalState();
const setGraphInfo = useSetGraphInfo();
const { data } = useFetchAgent(); const { data } = useFetchAgent();
const { t } = useTranslation();
const { toast } = useToast();
const onFileUploadOk = useCallback(
async ({
fileList,
platform,
}: {
fileList: File[];
platform: Platform;
}) => {
console.log('🚀 ~ useHandleExportOrImportJsonFile ~ platform:', platform);
if (fileList.length > 0) {
const file = fileList[0];
if (file.type !== FileMimeType.Json) {
toast({ title: t('flow.jsonUploadTypeErrorMessage') });
return;
}
const graphStr = await file.text();
const errorMessage = t('flow.jsonUploadContentErrorMessage');
try {
const graph = JSON.parse(graphStr);
if (graphStr && !isEmpty(graph) && Array.isArray(graph?.nodes)) {
setGraphInfo(graph ?? ({} as IGraph));
hideFileUploadModal();
} else {
message.error(errorMessage);
}
} catch (error) {
message.error(errorMessage);
}
}
},
[hideFileUploadModal, setGraphInfo, t, toast],
);
const handleExportJson = useCallback(() => { const handleExportJson = useCallback(() => {
downloadJsonFile(buildDslData().graph, `${data.title}.json`); downloadJsonFile(buildDslData().graph, `${data.title}.json`);
}, [buildDslData, data.title]); }, [buildDslData, data.title]);
return { return {
fileUploadVisible,
handleExportJson, handleExportJson,
handleImportJson: showFileUploadModal,
hideFileUploadModal,
onFileUploadOk,
}; };
}; };

View File

@ -24,7 +24,6 @@ import { ReactFlowProvider } from '@xyflow/react';
import { import {
ChevronDown, ChevronDown,
CirclePlay, CirclePlay,
Download,
History, History,
LaptopMinimalCheck, LaptopMinimalCheck,
Logs, Logs,
@ -37,7 +36,7 @@ import { useTranslation } from 'react-i18next';
import { useParams } from 'umi'; import { useParams } from 'umi';
import AgentCanvas from './canvas'; import AgentCanvas from './canvas';
import { DropdownProvider } from './canvas/context'; import { DropdownProvider } from './canvas/context';
import { useHandleExportOrImportJsonFile } from './hooks/use-export-json'; import { useHandleExportJsonFile } from './hooks/use-export-json';
import { useFetchDataOnMount } from './hooks/use-fetch-data'; import { useFetchDataOnMount } from './hooks/use-fetch-data';
import { useGetBeginNodeDataInputs } from './hooks/use-get-begin-query'; import { useGetBeginNodeDataInputs } from './hooks/use-get-begin-query';
import { import {
@ -46,7 +45,6 @@ import {
useWatchAgentChange, useWatchAgentChange,
} from './hooks/use-save-graph'; } from './hooks/use-save-graph';
import { SettingDialog } from './setting-dialog'; import { SettingDialog } from './setting-dialog';
import { UploadAgentDialog } from './upload-agent-dialog';
import { useAgentHistoryManager } from './use-agent-history-manager'; import { useAgentHistoryManager } from './use-agent-history-manager';
import { VersionDialog } from './version-dialog'; import { VersionDialog } from './version-dialog';
@ -71,13 +69,8 @@ export default function Agent() {
} = useSetModalState(); } = useSetModalState();
const { t } = useTranslation(); const { t } = useTranslation();
useAgentHistoryManager(); useAgentHistoryManager();
const {
handleExportJson, const { handleExportJson } = useHandleExportJsonFile();
handleImportJson,
fileUploadVisible,
onFileUploadOk,
hideFileUploadModal,
} = useHandleExportOrImportJsonFile();
const { saveGraph, loading } = useSaveGraph(); const { saveGraph, loading } = useSaveGraph();
const { flowDetail: agentDetail } = useFetchDataOnMount(); const { flowDetail: agentDetail } = useFetchDataOnMount();
const inputs = useGetBeginNodeDataInputs(); const inputs = useGetBeginNodeDataInputs();
@ -158,11 +151,6 @@ export default function Agent() {
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
<AgentDropdownMenuItem onClick={handleImportJson}>
<Download />
{t('flow.import')}
</AgentDropdownMenuItem>
<DropdownMenuSeparator />
<AgentDropdownMenuItem onClick={handleExportJson}> <AgentDropdownMenuItem onClick={handleExportJson}>
<Upload /> <Upload />
{t('flow.export')} {t('flow.export')}
@ -193,12 +181,6 @@ export default function Agent() {
></AgentCanvas> ></AgentCanvas>
</DropdownProvider> </DropdownProvider>
</ReactFlowProvider> </ReactFlowProvider>
{fileUploadVisible && (
<UploadAgentDialog
hideModal={hideFileUploadModal}
onOk={onFileUploadOk}
></UploadAgentDialog>
)}
{embedVisible && ( {embedVisible && (
<EmbedDialog <EmbedDialog
visible={embedVisible} visible={embedVisible}

View File

@ -112,10 +112,9 @@ export default function AgentTemplates() {
<main className="flex-1 bg-text-title-invert/50 h-dvh"> <main className="flex-1 bg-text-title-invert/50 h-dvh">
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[94vh] overflow-auto px-8 pt-8"> <div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[94vh] overflow-auto px-8 pt-8">
{tempListFilter?.map((x, index) => { {tempListFilter?.map((x) => {
return ( return (
<TemplateCard <TemplateCard
isCreate={index === 0}
key={x.id} key={x.id}
data={x} data={x}
showModal={showModal} showModal={showModal}

View File

@ -0,0 +1,4 @@
export enum FlowType {
Agent = 'agent',
Flow = 'flow',
}

View File

@ -6,31 +6,20 @@ import { z } from 'zod';
import { RAGFlowFormItem } from '@/components/ragflow-form'; import { RAGFlowFormItem } from '@/components/ragflow-form';
import { Card, CardContent } from '@/components/ui/card'; import { Card, CardContent } from '@/components/ui/card';
import { import { Form } from '@/components/ui/form';
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { IModalProps } from '@/interfaces/common'; import { IModalProps } from '@/interfaces/common';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { TagRenameId } from '@/pages/add-knowledge/constant'; import { TagRenameId } from '@/pages/add-knowledge/constant';
import { BrainCircuit, Check, Route } from 'lucide-react'; import { BrainCircuit, Check, Route } from 'lucide-react';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { FlowType } from './constant';
import { NameFormField, NameFormSchema } from './name-form-field';
export type CreateAgentFormProps = IModalProps<any> & { export type CreateAgentFormProps = IModalProps<any> & {
shouldChooseAgent?: boolean; shouldChooseAgent?: boolean;
}; };
enum FlowType {
Agent = 'agent',
Flow = 'flow',
}
type FlowTypeCardProps = { type FlowTypeCardProps = {
value?: FlowType; value?: FlowType;
onChange?: (value: FlowType) => void; onChange?: (value: FlowType) => void;
@ -51,7 +40,7 @@ function FlowTypeCards({ value, onChange }: FlowTypeCardProps) {
<Card <Card
key={val} key={val}
className={cn('flex-1 rounded-lg border bg-transparent', { className={cn('flex-1 rounded-lg border bg-transparent', {
'border-bg-base': isActive, 'border-text-primary': isActive,
'border-border-default': !isActive, 'border-border-default': !isActive,
})} })}
> >
@ -81,30 +70,28 @@ function FlowTypeCards({ value, onChange }: FlowTypeCardProps) {
); );
} }
export const FormSchema = z.object({
...NameFormSchema,
tag: z.string().trim().optional(),
description: z.string().trim().optional(),
type: z.nativeEnum(FlowType).optional(),
});
export type FormSchemaType = z.infer<typeof FormSchema>;
export function CreateAgentForm({ export function CreateAgentForm({
hideModal, hideModal,
onOk, onOk,
shouldChooseAgent = false, shouldChooseAgent = false,
}: CreateAgentFormProps) { }: CreateAgentFormProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const FormSchema = z.object({
name: z
.string()
.min(1, {
message: t('common.namePlaceholder'),
})
.trim(),
tag: z.string().trim().optional(),
description: z.string().trim().optional(),
type: z.nativeEnum(FlowType).optional(),
});
const form = useForm<z.infer<typeof FormSchema>>({ const form = useForm<FormSchemaType>({
resolver: zodResolver(FormSchema), resolver: zodResolver(FormSchema),
defaultValues: { name: '', type: FlowType.Agent }, defaultValues: { name: '', type: FlowType.Agent },
}); });
async function onSubmit(data: z.infer<typeof FormSchema>) { async function onSubmit(data: FormSchemaType) {
const ret = await onOk?.(data); const ret = await onOk?.(data);
if (ret) { if (ret) {
hideModal?.(); hideModal?.();
@ -123,23 +110,7 @@ export function CreateAgentForm({
<FlowTypeCards></FlowTypeCards> <FlowTypeCards></FlowTypeCards>
</RAGFlowFormItem> </RAGFlowFormItem>
)} )}
<FormField <NameFormField></NameFormField>
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel required>{t('common.name')}</FormLabel>
<FormControl>
<Input
placeholder={t('common.namePlaceholder')}
{...field}
autoComplete="off"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</form> </form>
</Form> </Form>
); );

View File

@ -0,0 +1,42 @@
import { useSetModalState } from '@/hooks/common-hooks';
import { EmptyDsl, useSetAgent } from '@/hooks/use-agent-request';
import { DSL } from '@/interfaces/database/agent';
import { useCallback } from 'react';
import { FlowType } from '../constant';
import { FormSchemaType } from '../create-agent-form';
export function useCreateAgentOrPipeline() {
const { loading, setAgent } = useSetAgent();
const {
visible: creatingVisible,
hideModal: hideCreatingModal,
showModal: showCreatingModal,
} = useSetModalState();
const createAgent = useCallback(
async (name: string) => {
return setAgent({ title: name, dsl: EmptyDsl as DSL });
},
[setAgent],
);
const handleCreateAgentOrPipeline = useCallback(
async (data: FormSchemaType) => {
if (data.type === FlowType.Agent) {
const ret = await createAgent(data.name);
if (ret.code === 0) {
hideCreatingModal();
}
}
},
[createAgent, hideCreatingModal],
);
return {
loading,
creatingVisible,
hideCreatingModal,
showCreatingModal,
handleCreateAgentOrPipeline,
};
}

View File

@ -8,7 +8,6 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'; } from '@/components/ui/dropdown-menu';
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination'; import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { useSetModalState } from '@/hooks/common-hooks';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useFetchAgentListByPage } from '@/hooks/use-agent-request'; import { useFetchAgentListByPage } from '@/hooks/use-agent-request';
import { t } from 'i18next'; import { t } from 'i18next';
@ -17,6 +16,9 @@ import { Clipboard, ClipboardPlus, FileInput, Plus } from 'lucide-react';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { AgentCard } from './agent-card'; import { AgentCard } from './agent-card';
import { CreateAgentDialog } from './create-agent-dialog'; import { CreateAgentDialog } from './create-agent-dialog';
import { useCreateAgentOrPipeline } from './hooks/use-create-agent';
import { UploadAgentDialog } from './upload-agent-dialog';
import { useHandleImportJsonFile } from './use-import-json';
import { useRenameAgent } from './use-rename-agent'; import { useRenameAgent } from './use-rename-agent';
export default function Agents() { export default function Agents() {
@ -34,10 +36,19 @@ export default function Agents() {
} = useRenameAgent(); } = useRenameAgent();
const { const {
visible: creatingVisible, creatingVisible,
hideModal: hideCreatingModal, hideCreatingModal,
showModal: showCreatingModal, showCreatingModal,
} = useSetModalState(); loading,
handleCreateAgentOrPipeline,
} = useCreateAgentOrPipeline();
const {
handleImportJson,
fileUploadVisible,
onFileUploadOk,
hideFileUploadModal,
} = useHandleImportJsonFile();
const handlePageChange = useCallback( const handlePageChange = useCallback(
(page: number, pageSize?: number) => { (page: number, pageSize?: number) => {
@ -77,7 +88,10 @@ export default function Agents() {
<ClipboardPlus /> <ClipboardPlus />
Create from Template Create from Template
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem justifyBetween={false}> <DropdownMenuItem
justifyBetween={false}
onClick={handleImportJson}
>
<FileInput /> <FileInput />
Import json file Import json file
</DropdownMenuItem> </DropdownMenuItem>
@ -115,13 +129,19 @@ export default function Agents() {
)} )}
{creatingVisible && ( {creatingVisible && (
<CreateAgentDialog <CreateAgentDialog
loading={false} loading={loading}
visible={creatingVisible} visible={creatingVisible}
hideModal={hideCreatingModal} hideModal={hideCreatingModal}
shouldChooseAgent shouldChooseAgent
onOk={() => {}} onOk={handleCreateAgentOrPipeline}
></CreateAgentDialog> ></CreateAgentDialog>
)} )}
{fileUploadVisible && (
<UploadAgentDialog
hideModal={hideFileUploadModal}
onOk={onFileUploadOk}
></UploadAgentDialog>
)}
</section> </section>
); );
} }

View File

@ -0,0 +1,28 @@
import { RAGFlowFormItem } from '@/components/ragflow-form';
import { Input } from '@/components/ui/input';
import i18n from '@/locales/config';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
export const NameFormSchema = {
name: z
.string()
.min(1, {
message: i18n.t('common.namePlaceholder'),
})
.trim(),
};
export function NameFormField() {
const { t } = useTranslation();
return (
<RAGFlowFormItem
name="name"
required
label={t('common.name')}
tooltip={t('flow.sqlStatementTip')}
>
<Input placeholder={t('common.namePlaceholder')} autoComplete="off" />
</RAGFlowFormItem>
);
}

View File

@ -3,7 +3,6 @@ import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card'; import { Card, CardContent } from '@/components/ui/card';
import { IFlowTemplate } from '@/interfaces/database/flow'; import { IFlowTemplate } from '@/interfaces/database/flow';
import i18n from '@/locales/config'; import i18n from '@/locales/config';
import { Plus } from 'lucide-react';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
interface IProps { interface IProps {
@ -12,7 +11,7 @@ interface IProps {
showModal(record: IFlowTemplate): void; showModal(record: IFlowTemplate): void;
} }
export function TemplateCard({ data, showModal, isCreate = false }: IProps) { export function TemplateCard({ data, showModal }: IProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const handleClick = useCallback(() => { const handleClick = useCallback(() => {
@ -26,28 +25,13 @@ export function TemplateCard({ data, showModal, isCreate = false }: IProps) {
return ( return (
<Card className="border-colors-outline-neutral-standard group relative min-h-40"> <Card className="border-colors-outline-neutral-standard group relative min-h-40">
<CardContent className="p-4 "> <CardContent className="p-4 ">
{isCreate && (
<div
className="flex flex-col justify-center items-center gap-4 mb-4 absolute top-0 right-0 left-0 bottom-0 cursor-pointer "
onClick={handleClick}
>
<Plus size={50} fontWeight={700} />
<div>{t('flow.createAgent')}</div>
</div>
)}
{!isCreate && (
<>
<div className="flex justify-start items-center gap-4 mb-4"> <div className="flex justify-start items-center gap-4 mb-4">
<RAGFlowAvatar <RAGFlowAvatar
className="w-7 h-7" className="w-7 h-7"
avatar={ avatar={data.avatar ? data.avatar : 'https://github.com/shadcn.png'}
data.avatar ? data.avatar : 'https://github.com/shadcn.png'
}
name={data?.title[language] || 'CN'} name={data?.title[language] || 'CN'}
></RAGFlowAvatar> ></RAGFlowAvatar>
<div className="text-[18px] font-bold "> <div className="text-[18px] font-bold ">{data?.title[language]}</div>
{data?.title[language]}
</div>
</div> </div>
<p className="break-words">{data?.description[language]}</p> <p className="break-words">{data?.description[language]}</p>
<div className="group-hover:bg-gradient-to-t from-black/70 from-10% via-black/0 via-50% to-black/0 w-full h-full group-hover:block absolute top-0 left-0 hidden rounded-xl"> <div className="group-hover:bg-gradient-to-t from-black/70 from-10% via-black/0 via-50% to-black/0 w-full h-full group-hover:block absolute top-0 left-0 hidden rounded-xl">
@ -59,8 +43,6 @@ export function TemplateCard({ data, showModal, isCreate = false }: IProps) {
{t('flow.useTemplate')} {t('flow.useTemplate')}
</Button> </Button>
</div> </div>
</>
)}
</CardContent> </CardContent>
</Card> </Card>
); );

View File

@ -1,3 +1,4 @@
import { ButtonLoading } from '@/components/ui/button';
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -5,7 +6,6 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from '@/components/ui/dialog'; } from '@/components/ui/dialog';
import { LoadingButton } from '@/components/ui/loading-button';
import { IModalProps } from '@/interfaces/common'; import { IModalProps } from '@/interfaces/common';
import { TagRenameId } from '@/pages/add-knowledge/constant'; import { TagRenameId } from '@/pages/add-knowledge/constant';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -26,9 +26,9 @@ export function UploadAgentDialog({
</DialogHeader> </DialogHeader>
<UploadAgentForm hideModal={hideModal} onOk={onOk}></UploadAgentForm> <UploadAgentForm hideModal={hideModal} onOk={onOk}></UploadAgentForm>
<DialogFooter> <DialogFooter>
<LoadingButton type="submit" form={TagRenameId} loading={loading}> <ButtonLoading type="submit" form={TagRenameId} loading={loading}>
{t('common.save')} {t('common.save')}
</LoadingButton> </ButtonLoading>
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>
</Dialog> </Dialog>

View File

@ -13,32 +13,24 @@ import {
FormLabel, FormLabel,
FormMessage, FormMessage,
} from '@/components/ui/form'; } from '@/components/ui/form';
import { FileMimeType, Platform } from '@/constants/common'; import { FileMimeType } from '@/constants/common';
import { IModalProps } from '@/interfaces/common'; import { IModalProps } from '@/interfaces/common';
import { TagRenameId } from '@/pages/add-knowledge/constant'; import { TagRenameId } from '@/pages/add-knowledge/constant';
import { useTranslation } from 'react-i18next'; import { NameFormField, NameFormSchema } from '../name-form-field';
// const options = Object.values(Platform).map((x) => ({ label: x, value: x })); export const FormSchema = z.object({
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)), fileList: z.array(z.instanceof(File)),
}); ...NameFormSchema,
});
export type FormSchemaType = z.infer<typeof FormSchema>;
export function UploadAgentForm({ hideModal, onOk }: IModalProps<any>) {
const form = useForm<z.infer<typeof FormSchema>>({ const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema), resolver: zodResolver(FormSchema),
defaultValues: { platform: Platform.RAGFlow }, defaultValues: { name: '' },
}); });
async function onSubmit(data: z.infer<typeof FormSchema>) { async function onSubmit(data: FormSchemaType) {
console.log('🚀 ~ onSubmit ~ data:', data);
const ret = await onOk?.(data); const ret = await onOk?.(data);
if (ret) { if (ret) {
hideModal?.(); hideModal?.();
@ -52,12 +44,13 @@ export function UploadAgentForm({ hideModal, onOk }: IModalProps<any>) {
className="space-y-6" className="space-y-6"
id={TagRenameId} id={TagRenameId}
> >
<NameFormField></NameFormField>
<FormField <FormField
control={form.control} control={form.control}
name="fileList" name="fileList"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>{t('common.name')}</FormLabel> <FormLabel required>DSL</FormLabel>
<FormControl> <FormControl>
<FileUploader <FileUploader
value={field.value} value={field.value}
@ -70,19 +63,6 @@ export function UploadAgentForm({ hideModal, onOk }: IModalProps<any>) {
</FormItem> </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>
</Form> </Form>
); );

View File

@ -0,0 +1,56 @@
import { useToast } from '@/components/hooks/use-toast';
import { FileMimeType } from '@/constants/common';
import { useSetModalState } from '@/hooks/common-hooks';
import { EmptyDsl, useSetAgent } from '@/hooks/use-agent-request';
import { message } from 'antd';
import isEmpty from 'lodash/isEmpty';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FormSchemaType } from './upload-agent-dialog/upload-agent-form';
export const useHandleImportJsonFile = () => {
const {
visible: fileUploadVisible,
hideModal: hideFileUploadModal,
showModal: showFileUploadModal,
} = useSetModalState();
const { t } = useTranslation();
const { toast } = useToast();
const { loading, setAgent } = useSetAgent();
const onFileUploadOk = useCallback(
async ({ fileList, name }: FormSchemaType) => {
if (fileList.length > 0) {
const file = fileList[0];
if (file.type !== FileMimeType.Json) {
toast({ title: t('flow.jsonUploadTypeErrorMessage') });
return;
}
const graphStr = await file.text();
const errorMessage = t('flow.jsonUploadContentErrorMessage');
try {
const graph = JSON.parse(graphStr);
if (graphStr && !isEmpty(graph) && Array.isArray(graph?.nodes)) {
const dsl = { ...EmptyDsl, graph };
setAgent({ title: name, dsl });
hideFileUploadModal();
} else {
message.error(errorMessage);
}
} catch (error) {
message.error(errorMessage);
}
}
},
[hideFileUploadModal, setAgent, t, toast],
);
return {
fileUploadVisible,
handleImportJson: showFileUploadModal,
hideFileUploadModal,
onFileUploadOk,
loading,
};
};