Feat: Add AgentTemplates component. #3221 (#5194)

### 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:
balibabu 2025-02-20 17:02:42 +08:00 committed by GitHub
parent c326f14fed
commit 744ff55c62
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 252 additions and 1 deletions

View File

@ -46,6 +46,10 @@ export const useNavigatePage = () => {
navigate(Routes.Agent); navigate(Routes.Agent);
}, [navigate]); }, [navigate]);
const navigateToAgentTemplates = useCallback(() => {
navigate(Routes.AgentTemplates);
}, [navigate]);
const navigateToSearchList = useCallback(() => { const navigateToSearchList = useCallback(() => {
navigate(Routes.Searches); navigate(Routes.Searches);
}, [navigate]); }, [navigate]);
@ -99,6 +103,7 @@ export const useNavigatePage = () => {
navigateToChunk, navigateToChunk,
navigateToAgentList, navigateToAgentList,
navigateToAgent, navigateToAgent,
navigateToAgentTemplates,
navigateToSearchList, navigateToSearchList,
navigateToSearch, navigateToSearch,
}; };

View 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>
);
}

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 { 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>
);
}

View 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>
);
}

View File

@ -1,15 +1,17 @@
import ListFilterBar from '@/components/list-filter-bar'; import ListFilterBar from '@/components/list-filter-bar';
import { useFetchFlowList } from '@/hooks/flow-hooks'; import { useFetchFlowList } from '@/hooks/flow-hooks';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { AgentCard } from './agent-card'; import { AgentCard } from './agent-card';
export default function Agent() { export default function Agent() {
const { data } = useFetchFlowList(); const { data } = useFetchFlowList();
const { navigateToAgentTemplates } = useNavigatePage();
return ( return (
<section> <section>
<div className="px-8 pt-8"> <div className="px-8 pt-8">
<ListFilterBar title="Agents"> <ListFilterBar title="Agents" showDialog={navigateToAgentTemplates}>
<Plus className="mr-2 h-4 w-4" /> <Plus className="mr-2 h-4 w-4" />
Create app Create app
</ListFilterBar> </ListFilterBar>

View 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>
);
}

View File

@ -5,6 +5,7 @@ export enum Routes {
DatasetBase = '/dataset', DatasetBase = '/dataset',
Dataset = `${Routes.DatasetBase}${Routes.DatasetBase}`, Dataset = `${Routes.DatasetBase}${Routes.DatasetBase}`,
Agent = '/agent', Agent = '/agent',
AgentTemplates = '/agent-templates',
Agents = '/agents', Agents = '/agents',
Searches = '/next-searches', Searches = '/next-searches',
Search = '/next-search', Search = '/next-search',
@ -218,6 +219,11 @@ const routes = [
layout: false, layout: false,
component: `@/pages${Routes.Agent}`, component: `@/pages${Routes.Agent}`,
}, },
{
path: Routes.AgentTemplates,
layout: false,
component: `@/pages${Routes.Agents}${Routes.AgentTemplates}`,
},
{ {
path: Routes.Files, path: Routes.Files,
layout: false, layout: false,