refactor: improve error

This commit is contained in:
Mauricio Siu
2025-01-18 23:07:36 -06:00
parent 5e7d344110
commit e68465f9e6
2 changed files with 143 additions and 115 deletions

View File

@@ -16,6 +16,7 @@ import { useEffect, useState } from "react";
import ReactMarkdown from "react-markdown";
import { toast } from "sonner";
import type { TemplateInfo } from "./template-generator";
import { AlertBlock } from "@/components/shared/alert-block";
export interface StepProps {
nextStep: () => void;
@@ -35,7 +36,8 @@ export const StepTwo = ({
useState<TemplateInfo["details"]>();
const [showValues, setShowValues] = useState<Record<string, boolean>>({});
const { mutateAsync, isLoading } = api.ai.suggest.useMutation();
const { mutateAsync, isLoading, error, isError } =
api.ai.suggest.useMutation();
useEffect(() => {
mutateAsync({
@@ -48,7 +50,6 @@ export const StepTwo = ({
setSuggestions(data);
})
.catch((error) => {
console.error("Error details:", error);
toast.error("Error generating suggestions");
});
}, [templateInfo.userInput]);
@@ -75,6 +76,7 @@ export const StepTwo = ({
if (!selectedVariant) return;
const updatedEnvVariables = [...selectedVariant.envVariables];
// @ts-ignore
updatedEnvVariables[index] = {
...updatedEnvVariables[index],
[field]: value,
@@ -151,7 +153,26 @@ export const StepTwo = ({
],
});
};
if (isError) {
return (
<div className="flex flex-col items-center justify-center h-full space-y-4">
<Bot className="w-16 h-16 text-primary animate-pulse" />
<h2 className="text-2xl font-semibold animate-pulse">Error</h2>
<AlertBlock type="error">
{error?.message || "Error generating suggestions"}
</AlertBlock>
<Button
onClick={() =>
selectedVariant ? setSelectedVariant(undefined) : prevStep()
}
variant="outline"
>
{selectedVariant ? "Change Variant" : "Back"}
</Button>
</div>
);
}
if (isLoading) {
return (
<div className="flex flex-col items-center justify-center h-full space-y-4">

View File

@@ -1,145 +1,152 @@
import { slugify } from "@/lib/slug";
import {
adminProcedure,
createTRPCRouter,
protectedProcedure,
adminProcedure,
createTRPCRouter,
protectedProcedure,
} from "@/server/api/trpc";
import { generatePassword } from "@/templates/utils";
import { IS_CLOUD } from "@dokploy/server/constants";
import {
apiCreateAi,
apiUpdateAi,
deploySuggestionSchema,
apiCreateAi,
apiUpdateAi,
deploySuggestionSchema,
} from "@dokploy/server/db/schema/ai";
import { createDomain } from "@dokploy/server/index";
import {
deleteAiSettings,
getAiSettingById,
getAiSettingsByAdminId,
saveAiSettings,
suggestVariants,
deleteAiSettings,
getAiSettingById,
getAiSettingsByAdminId,
saveAiSettings,
suggestVariants,
} from "@dokploy/server/services/ai";
import { createComposeByTemplate } from "@dokploy/server/services/compose";
import { findProjectById } from "@dokploy/server/services/project";
import {
addNewService,
checkServiceAccess,
addNewService,
checkServiceAccess,
} from "@dokploy/server/services/user";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
export const aiRouter = createTRPCRouter({
one: protectedProcedure
.input(z.object({ aiId: z.string() }))
.query(async ({ ctx, input }) => {
const aiSetting = await getAiSettingById(input.aiId);
if (aiSetting.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this AI configuration",
});
}
return aiSetting;
}),
create: adminProcedure.input(apiCreateAi).mutation(async ({ ctx, input }) => {
return await saveAiSettings(ctx.user.adminId, input);
}),
one: protectedProcedure
.input(z.object({ aiId: z.string() }))
.query(async ({ ctx, input }) => {
const aiSetting = await getAiSettingById(input.aiId);
if (aiSetting.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this AI configuration",
});
}
return aiSetting;
}),
create: adminProcedure.input(apiCreateAi).mutation(async ({ ctx, input }) => {
return await saveAiSettings(ctx.user.adminId, input);
}),
update: protectedProcedure
.input(apiUpdateAi)
.mutation(async ({ ctx, input }) => {
return await saveAiSettings(ctx.user.adminId, input);
}),
update: protectedProcedure
.input(apiUpdateAi)
.mutation(async ({ ctx, input }) => {
return await saveAiSettings(ctx.user.adminId, input);
}),
getAll: adminProcedure.query(async ({ ctx }) => {
return await getAiSettingsByAdminId(ctx.user.adminId);
}),
getAll: adminProcedure.query(async ({ ctx }) => {
return await getAiSettingsByAdminId(ctx.user.adminId);
}),
get: protectedProcedure
.input(z.object({ aiId: z.string() }))
.query(async ({ ctx, input }) => {
const aiSetting = await getAiSettingById(input.aiId);
if (aiSetting.adminId !== ctx.user.authId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this AI configuration",
});
}
return aiSetting;
}),
get: protectedProcedure
.input(z.object({ aiId: z.string() }))
.query(async ({ ctx, input }) => {
const aiSetting = await getAiSettingById(input.aiId);
if (aiSetting.adminId !== ctx.user.authId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this AI configuration",
});
}
return aiSetting;
}),
delete: protectedProcedure
.input(z.object({ aiId: z.string() }))
.mutation(async ({ ctx, input }) => {
const aiSetting = await getAiSettingById(input.aiId);
if (aiSetting.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this AI configuration",
});
}
return await deleteAiSettings(input.aiId);
}),
delete: protectedProcedure
.input(z.object({ aiId: z.string() }))
.mutation(async ({ ctx, input }) => {
const aiSetting = await getAiSettingById(input.aiId);
if (aiSetting.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this AI configuration",
});
}
return await deleteAiSettings(input.aiId);
}),
suggest: protectedProcedure
.input(
z.object({
aiId: z.string(),
input: z.string(),
serverId: z.string().optional(),
}),
)
.mutation(async ({ ctx, input }) => {
return await suggestVariants({
...input,
adminId: ctx.user.adminId,
});
}),
deploy: protectedProcedure
.input(deploySuggestionSchema)
.mutation(async ({ ctx, input }) => {
if (ctx.user.rol === "user") {
await checkServiceAccess(ctx.user.adminId, input.projectId, "create");
}
suggest: protectedProcedure
.input(
z.object({
aiId: z.string(),
input: z.string(),
serverId: z.string().optional(),
})
)
.mutation(async ({ ctx, input }) => {
try {
return await suggestVariants({
...input,
adminId: ctx.user.adminId,
});
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
message: error instanceof Error ? error?.message : `Error: ${error}`,
});
}
}),
deploy: protectedProcedure
.input(deploySuggestionSchema)
.mutation(async ({ ctx, input }) => {
if (ctx.user.rol === "user") {
await checkServiceAccess(ctx.user.adminId, input.projectId, "create");
}
if (IS_CLOUD && !input.serverId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You need to use a server to create a compose",
});
}
if (IS_CLOUD && !input.serverId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You need to use a server to create a compose",
});
}
const project = await findProjectById(input.projectId);
const project = await findProjectById(input.projectId);
const projectName = slugify(`${project.name} ${input.id}`);
const projectName = slugify(`${project.name} ${input.id}`);
console.log(input);
console.log(input);
const compose = await createComposeByTemplate({
...input,
composeFile: input.dockerCompose,
env: input.envVariables,
serverId: input.serverId,
name: input.name,
sourceType: "raw",
appName: `${projectName}-${generatePassword(6)}`,
});
const compose = await createComposeByTemplate({
...input,
composeFile: input.dockerCompose,
env: input.envVariables,
serverId: input.serverId,
name: input.name,
sourceType: "raw",
appName: `${projectName}-${generatePassword(6)}`,
});
if (input.domains && input.domains?.length > 0) {
for (const domain of input.domains) {
await createDomain({
...domain,
domainType: "compose",
certificateType: "none",
composeId: compose.composeId,
});
}
}
if (input.domains && input.domains?.length > 0) {
for (const domain of input.domains) {
await createDomain({
...domain,
domainType: "compose",
certificateType: "none",
composeId: compose.composeId,
});
}
}
if (ctx.user.rol === "user") {
await addNewService(ctx.user.authId, compose.composeId);
}
if (ctx.user.rol === "user") {
await addNewService(ctx.user.authId, compose.composeId);
}
return null;
}),
return null;
}),
});