mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-14 03:55:58 +08:00
### What problem does this PR solve? Feat: Add AgentTemplates component. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
c326f14fed
commit
744ff55c62
@ -46,6 +46,10 @@ export const useNavigatePage = () => {
|
||||
navigate(Routes.Agent);
|
||||
}, [navigate]);
|
||||
|
||||
const navigateToAgentTemplates = useCallback(() => {
|
||||
navigate(Routes.AgentTemplates);
|
||||
}, [navigate]);
|
||||
|
||||
const navigateToSearchList = useCallback(() => {
|
||||
navigate(Routes.Searches);
|
||||
}, [navigate]);
|
||||
@ -99,6 +103,7 @@ export const useNavigatePage = () => {
|
||||
navigateToChunk,
|
||||
navigateToAgentList,
|
||||
navigateToAgent,
|
||||
navigateToAgentTemplates,
|
||||
navigateToSearchList,
|
||||
navigateToSearch,
|
||||
};
|
||||
|
51
web/src/pages/agents/agent-templates.tsx
Normal file
51
web/src/pages/agents/agent-templates.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import { PageHeader } from '@/components/page-header';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import { useFetchFlowTemplates } from '@/hooks/flow-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CreateAgentDialog } from './create-agent-dialog';
|
||||
import { TemplateCard } from './template-card';
|
||||
|
||||
export default function AgentTemplates() {
|
||||
const { navigateToAgentList } = useNavigatePage();
|
||||
const { t } = useTranslation();
|
||||
const { data: list } = useFetchFlowTemplates();
|
||||
const {
|
||||
visible: creatingVisible,
|
||||
hideModal: hideCreatingModal,
|
||||
showModal: showCreatingModal,
|
||||
} = useSetModalState();
|
||||
|
||||
const handleOk = useCallback(async () => {
|
||||
// return onOk(name, checkedId);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<PageHeader
|
||||
back={navigateToAgentList}
|
||||
title={t('flow.createGraph')}
|
||||
></PageHeader>
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-8 max-h-[84vh] overflow-auto px-8">
|
||||
{list?.map((x) => {
|
||||
return (
|
||||
<TemplateCard
|
||||
key={x.id}
|
||||
data={x}
|
||||
showModal={showCreatingModal}
|
||||
></TemplateCard>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{creatingVisible && (
|
||||
<CreateAgentDialog
|
||||
loading={false}
|
||||
visible={creatingVisible}
|
||||
hideModal={hideCreatingModal}
|
||||
onOk={handleOk}
|
||||
></CreateAgentDialog>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
36
web/src/pages/agents/create-agent-dialog.tsx
Normal file
36
web/src/pages/agents/create-agent-dialog.tsx
Normal 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 { CreateAgentForm } from './create-agent-form';
|
||||
|
||||
export function CreateAgentDialog({
|
||||
hideModal,
|
||||
onOk,
|
||||
loading,
|
||||
}: IModalProps<any>) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Dialog open onOpenChange={hideModal}>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('flow.createGraph')}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<CreateAgentForm hideModal={hideModal} onOk={onOk}></CreateAgentForm>
|
||||
<DialogFooter>
|
||||
<LoadingButton type="submit" form={TagRenameId} loading={loading}>
|
||||
{t('common.save')}
|
||||
</LoadingButton>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
106
web/src/pages/agents/create-agent-form.tsx
Normal file
106
web/src/pages/agents/create-agent-form.tsx
Normal file
@ -0,0 +1,106 @@
|
||||
'use client';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { IModalProps } from '@/interfaces/common';
|
||||
import { TagRenameId } from '@/pages/add-knowledge/constant';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function CreateAgentForm({ hideModal, onOk }: IModalProps<any>) {
|
||||
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(),
|
||||
});
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: { name: '' },
|
||||
});
|
||||
|
||||
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
||||
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="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('common.name')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={t('common.namePlaceholder')}
|
||||
{...field}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tag"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('flow.tag')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={t('flow.tagPlaceholder')}
|
||||
{...field}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="description"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('flow.description')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={t('flow.descriptionPlaceholder')}
|
||||
{...field}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
}
|
@ -1,15 +1,17 @@
|
||||
import ListFilterBar from '@/components/list-filter-bar';
|
||||
import { useFetchFlowList } from '@/hooks/flow-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { AgentCard } from './agent-card';
|
||||
|
||||
export default function Agent() {
|
||||
const { data } = useFetchFlowList();
|
||||
const { navigateToAgentTemplates } = useNavigatePage();
|
||||
|
||||
return (
|
||||
<section>
|
||||
<div className="px-8 pt-8">
|
||||
<ListFilterBar title="Agents">
|
||||
<ListFilterBar title="Agents" showDialog={navigateToAgentTemplates}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Create app
|
||||
</ListFilterBar>
|
||||
|
45
web/src/pages/agents/template-card.tsx
Normal file
45
web/src/pages/agents/template-card.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import { IFlowTemplate } from '@/interfaces/database/flow';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface IProps {
|
||||
data: IFlowTemplate;
|
||||
}
|
||||
|
||||
export function TemplateCard({
|
||||
data,
|
||||
showModal,
|
||||
}: IProps & Pick<ReturnType<typeof useSetModalState>, 'showModal'>) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Card className="bg-colors-background-inverse-weak border-colors-outline-neutral-standard group relative">
|
||||
<CardContent className="p-4 ">
|
||||
<div className="flex justify-between mb-4">
|
||||
{data.avatar ? (
|
||||
<div
|
||||
className="w-[70px] h-[70px] rounded-xl bg-cover"
|
||||
style={{ backgroundImage: `url(${data.avatar})` }}
|
||||
/>
|
||||
) : (
|
||||
<Avatar className="w-[70px] h-[70px]">
|
||||
<AvatarImage src="https://github.com/shadcn.png" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
)}
|
||||
</div>
|
||||
<h3 className="text-xl font-bold mb-2">{data.title}</h3>
|
||||
<p className="break-words">{data.description}</p>
|
||||
<Button
|
||||
variant="tertiary"
|
||||
className="absolute bottom-4 right-4 left-4 hidden justify-end group-hover:block text-center"
|
||||
onClick={showModal}
|
||||
>
|
||||
{t('flow.useTemplate')}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
@ -5,6 +5,7 @@ export enum Routes {
|
||||
DatasetBase = '/dataset',
|
||||
Dataset = `${Routes.DatasetBase}${Routes.DatasetBase}`,
|
||||
Agent = '/agent',
|
||||
AgentTemplates = '/agent-templates',
|
||||
Agents = '/agents',
|
||||
Searches = '/next-searches',
|
||||
Search = '/next-search',
|
||||
@ -218,6 +219,11 @@ const routes = [
|
||||
layout: false,
|
||||
component: `@/pages${Routes.Agent}`,
|
||||
},
|
||||
{
|
||||
path: Routes.AgentTemplates,
|
||||
layout: false,
|
||||
component: `@/pages${Routes.Agents}${Routes.AgentTemplates}`,
|
||||
},
|
||||
{
|
||||
path: Routes.Files,
|
||||
layout: false,
|
||||
|
Loading…
x
Reference in New Issue
Block a user