chore(release): 1.2.4-rc.1

This commit is contained in:
Théo LAGACHE
2026-01-28 15:54:03 +01:00
parent 4942591d7f
commit 2a6d631719
34 changed files with 329 additions and 331 deletions
+48
View File
@@ -0,0 +1,48 @@
"use server";
import {ActionError, userAction} from "@/lib/safe-actions/actions";
import {AgentSchema} from "@/features/agents/agents.schema";
import {z} from "zod";
import {eq, and, ne, count} from "drizzle-orm";
import {db} from "@/db";
import * as drizzleDb from "@/db";
import {slugify} from "@/utils/slugify";
const verifySlugUniqueness = async (slug: string, agentId?: string) => {
const conditions = agentId ? and(eq(drizzleDb.schemas.agent.slug, slug), ne(drizzleDb.schemas.agent.id, agentId)) : eq(drizzleDb.schemas.agent.slug, slug);
const [countResult] = await db.select({count: count()}).from(drizzleDb.schemas.agent).where(conditions);
if (countResult.count > 0) {
throw new ActionError("Slug already exists");
}
};
export const createAgentAction = userAction.schema(AgentSchema).action(async ({parsedInput}) => {
const slug = slugify(parsedInput.name);
await verifySlugUniqueness(slug);
const [createdAgent] = await db.insert(drizzleDb.schemas.agent).values({...parsedInput, slug: slug}).returning();
return {
data: createdAgent,
};
});
export const updateAgentAction = userAction
.schema(
z.object({
id: z.string(),
data: AgentSchema,
})
)
.action(async ({parsedInput}) => {
const slug = slugify(parsedInput.data.name);
await verifySlugUniqueness(slug, parsedInput.id);
const [updatedAgent] = await db.update(drizzleDb.schemas.agent).set({
...parsedInput.data,
slug: slug
}).where(eq(drizzleDb.schemas.agent.id, parsedInput.id)).returning();
return {
data: updatedAgent,
};
});
+8
View File
@@ -0,0 +1,8 @@
import { z } from "zod";
export const AgentSchema = z.object({
name: z.string().nonempty("Name is required"),
description: z.string(),
});
export type AgentType = z.infer<typeof AgentSchema>;
@@ -0,0 +1,42 @@
"use client";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {AgentForm} from "@/features/agents/components/agent.form";
import {useState} from "react";
import {Button} from "@/components/ui/button";
import {Plus} from "lucide-react";
import {AgentType} from "@/features/agents/agents.schema";
type AgentDialogProps = {
children?: React.ReactNode;
agent?: AgentType & { id: string };
};
export const AgentDialog = ({children, agent}: AgentDialogProps) => {
const [open, setOpen] = useState(false);
const isEdit = !!agent;
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
{children ? children : <Button><Plus className="mr-2 h-4 w-4"/> Create Agent</Button>}
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>{isEdit ? `Edit ${agent.name}` : "Create new agent"}</DialogTitle>
</DialogHeader>
<AgentForm
onSuccess={() => setOpen(false)}
defaultValues={agent}
agentId={agent?.id}
/>
</DialogContent>
</Dialog>
);
};
@@ -0,0 +1,114 @@
"use client";
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
useZodForm
} from "@/components/ui/form";
import {Input} from "@/components/ui/input";
import {Form} from "@/components/ui/form";
import {Button} from "@/components/ui/button";
import {useRouter} from "next/navigation";
import {useMutation} from "@tanstack/react-query";
import {TooltipProvider} from "@/components/ui/tooltip";
import {AgentSchema, AgentType} from "@/features/agents/agents.schema";
import {toast} from "sonner";
import {createAgentAction, updateAgentAction} from "@/features/agents/agents.action";
export type agentFormProps = {
defaultValues?: AgentType;
agentId?: string;
onSuccess?: (data: any) => void;
};
export const AgentForm = (props: agentFormProps) => {
const isCreate = !Boolean(props.defaultValues);
const form = useZodForm({
schema: AgentSchema,
defaultValues: props.defaultValues,
});
const router = useRouter();
const mutation = useMutation({
mutationFn: async (values: AgentType) => {
const createAgent = isCreate
? await createAgentAction(values)
: await updateAgentAction({
id: props.agentId ?? "-",
data: values,
});
const data = createAgent?.data?.data;
if (createAgent?.serverError || !data) {
toast.error(createAgent?.serverError);
return;
}
toast.success(`Success ${isCreate ? "creating" : "updating"} agent`);
router.refresh();
if (props.onSuccess) {
props.onSuccess(data);
} else {
router.push(`/dashboard/agents/${data.id}`);
}
},
});
return (
<TooltipProvider>
<Form
form={form}
className="flex flex-col gap-4"
onSubmit={async (values) => {
await mutation.mutateAsync(values);
}}
>
<FormField
control={form.control}
name="name"
defaultValue=""
render={({field}) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="Agent 1" {...field} />
</FormControl>
<FormDescription>Your agent project name</FormDescription>
<FormMessage/>
</FormItem>
)}
/>
<FormField
control={form.control}
defaultValue=""
name="description"
render={({field}) => (
<FormItem>
<FormLabel>Description</FormLabel>
<FormControl>
<Input placeholder="This agent is for the client exemple.com" {...field}
value={field.value ?? ""}/>
</FormControl>
<FormDescription>Enter your project agent description</FormDescription>
<FormMessage/>
</FormItem>
)}
/>
<div className="flex justify-end">
<Button type="submit">
{isCreate ? "Create" : "Update"}
</Button>
</div>
</Form>
</TooltipProvider>
);
};