mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor: improve error
This commit is contained in:
@@ -16,6 +16,7 @@ import { useEffect, useState } from "react";
|
|||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import type { TemplateInfo } from "./template-generator";
|
import type { TemplateInfo } from "./template-generator";
|
||||||
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
|
|
||||||
export interface StepProps {
|
export interface StepProps {
|
||||||
nextStep: () => void;
|
nextStep: () => void;
|
||||||
@@ -35,7 +36,8 @@ export const StepTwo = ({
|
|||||||
useState<TemplateInfo["details"]>();
|
useState<TemplateInfo["details"]>();
|
||||||
const [showValues, setShowValues] = useState<Record<string, boolean>>({});
|
const [showValues, setShowValues] = useState<Record<string, boolean>>({});
|
||||||
|
|
||||||
const { mutateAsync, isLoading } = api.ai.suggest.useMutation();
|
const { mutateAsync, isLoading, error, isError } =
|
||||||
|
api.ai.suggest.useMutation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
@@ -48,7 +50,6 @@ export const StepTwo = ({
|
|||||||
setSuggestions(data);
|
setSuggestions(data);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Error details:", error);
|
|
||||||
toast.error("Error generating suggestions");
|
toast.error("Error generating suggestions");
|
||||||
});
|
});
|
||||||
}, [templateInfo.userInput]);
|
}, [templateInfo.userInput]);
|
||||||
@@ -75,6 +76,7 @@ export const StepTwo = ({
|
|||||||
if (!selectedVariant) return;
|
if (!selectedVariant) return;
|
||||||
|
|
||||||
const updatedEnvVariables = [...selectedVariant.envVariables];
|
const updatedEnvVariables = [...selectedVariant.envVariables];
|
||||||
|
// @ts-ignore
|
||||||
updatedEnvVariables[index] = {
|
updatedEnvVariables[index] = {
|
||||||
...updatedEnvVariables[index],
|
...updatedEnvVariables[index],
|
||||||
[field]: value,
|
[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) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center h-full space-y-4">
|
<div className="flex flex-col items-center justify-center h-full space-y-4">
|
||||||
|
|||||||
@@ -1,145 +1,152 @@
|
|||||||
import { slugify } from "@/lib/slug";
|
import { slugify } from "@/lib/slug";
|
||||||
import {
|
import {
|
||||||
adminProcedure,
|
adminProcedure,
|
||||||
createTRPCRouter,
|
createTRPCRouter,
|
||||||
protectedProcedure,
|
protectedProcedure,
|
||||||
} from "@/server/api/trpc";
|
} from "@/server/api/trpc";
|
||||||
import { generatePassword } from "@/templates/utils";
|
import { generatePassword } from "@/templates/utils";
|
||||||
import { IS_CLOUD } from "@dokploy/server/constants";
|
import { IS_CLOUD } from "@dokploy/server/constants";
|
||||||
import {
|
import {
|
||||||
apiCreateAi,
|
apiCreateAi,
|
||||||
apiUpdateAi,
|
apiUpdateAi,
|
||||||
deploySuggestionSchema,
|
deploySuggestionSchema,
|
||||||
} from "@dokploy/server/db/schema/ai";
|
} from "@dokploy/server/db/schema/ai";
|
||||||
import { createDomain } from "@dokploy/server/index";
|
import { createDomain } from "@dokploy/server/index";
|
||||||
import {
|
import {
|
||||||
deleteAiSettings,
|
deleteAiSettings,
|
||||||
getAiSettingById,
|
getAiSettingById,
|
||||||
getAiSettingsByAdminId,
|
getAiSettingsByAdminId,
|
||||||
saveAiSettings,
|
saveAiSettings,
|
||||||
suggestVariants,
|
suggestVariants,
|
||||||
} from "@dokploy/server/services/ai";
|
} from "@dokploy/server/services/ai";
|
||||||
import { createComposeByTemplate } from "@dokploy/server/services/compose";
|
import { createComposeByTemplate } from "@dokploy/server/services/compose";
|
||||||
import { findProjectById } from "@dokploy/server/services/project";
|
import { findProjectById } from "@dokploy/server/services/project";
|
||||||
import {
|
import {
|
||||||
addNewService,
|
addNewService,
|
||||||
checkServiceAccess,
|
checkServiceAccess,
|
||||||
} from "@dokploy/server/services/user";
|
} from "@dokploy/server/services/user";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const aiRouter = createTRPCRouter({
|
export const aiRouter = createTRPCRouter({
|
||||||
one: protectedProcedure
|
one: protectedProcedure
|
||||||
.input(z.object({ aiId: z.string() }))
|
.input(z.object({ aiId: z.string() }))
|
||||||
.query(async ({ ctx, input }) => {
|
.query(async ({ ctx, input }) => {
|
||||||
const aiSetting = await getAiSettingById(input.aiId);
|
const aiSetting = await getAiSettingById(input.aiId);
|
||||||
if (aiSetting.adminId !== ctx.user.adminId) {
|
if (aiSetting.adminId !== ctx.user.adminId) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED",
|
||||||
message: "You don't have access to this AI configuration",
|
message: "You don't have access to this AI configuration",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return aiSetting;
|
return aiSetting;
|
||||||
}),
|
}),
|
||||||
create: adminProcedure.input(apiCreateAi).mutation(async ({ ctx, input }) => {
|
create: adminProcedure.input(apiCreateAi).mutation(async ({ ctx, input }) => {
|
||||||
return await saveAiSettings(ctx.user.adminId, input);
|
return await saveAiSettings(ctx.user.adminId, input);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
update: protectedProcedure
|
update: protectedProcedure
|
||||||
.input(apiUpdateAi)
|
.input(apiUpdateAi)
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
return await saveAiSettings(ctx.user.adminId, input);
|
return await saveAiSettings(ctx.user.adminId, input);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getAll: adminProcedure.query(async ({ ctx }) => {
|
getAll: adminProcedure.query(async ({ ctx }) => {
|
||||||
return await getAiSettingsByAdminId(ctx.user.adminId);
|
return await getAiSettingsByAdminId(ctx.user.adminId);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
get: protectedProcedure
|
get: protectedProcedure
|
||||||
.input(z.object({ aiId: z.string() }))
|
.input(z.object({ aiId: z.string() }))
|
||||||
.query(async ({ ctx, input }) => {
|
.query(async ({ ctx, input }) => {
|
||||||
const aiSetting = await getAiSettingById(input.aiId);
|
const aiSetting = await getAiSettingById(input.aiId);
|
||||||
if (aiSetting.adminId !== ctx.user.authId) {
|
if (aiSetting.adminId !== ctx.user.authId) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED",
|
||||||
message: "You don't have access to this AI configuration",
|
message: "You don't have access to this AI configuration",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return aiSetting;
|
return aiSetting;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
delete: protectedProcedure
|
delete: protectedProcedure
|
||||||
.input(z.object({ aiId: z.string() }))
|
.input(z.object({ aiId: z.string() }))
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const aiSetting = await getAiSettingById(input.aiId);
|
const aiSetting = await getAiSettingById(input.aiId);
|
||||||
if (aiSetting.adminId !== ctx.user.adminId) {
|
if (aiSetting.adminId !== ctx.user.adminId) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED",
|
||||||
message: "You don't have access to this AI configuration",
|
message: "You don't have access to this AI configuration",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return await deleteAiSettings(input.aiId);
|
return await deleteAiSettings(input.aiId);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
suggest: protectedProcedure
|
suggest: protectedProcedure
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
aiId: z.string(),
|
aiId: z.string(),
|
||||||
input: z.string(),
|
input: z.string(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
return await suggestVariants({
|
try {
|
||||||
...input,
|
return await suggestVariants({
|
||||||
adminId: ctx.user.adminId,
|
...input,
|
||||||
});
|
adminId: ctx.user.adminId,
|
||||||
}),
|
});
|
||||||
deploy: protectedProcedure
|
} catch (error) {
|
||||||
.input(deploySuggestionSchema)
|
throw new TRPCError({
|
||||||
.mutation(async ({ ctx, input }) => {
|
code: "BAD_REQUEST",
|
||||||
if (ctx.user.rol === "user") {
|
message: error instanceof Error ? error?.message : `Error: ${error}`,
|
||||||
await checkServiceAccess(ctx.user.adminId, input.projectId, "create");
|
});
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
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) {
|
if (IS_CLOUD && !input.serverId) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED",
|
||||||
message: "You need to use a server to create a compose",
|
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({
|
const compose = await createComposeByTemplate({
|
||||||
...input,
|
...input,
|
||||||
composeFile: input.dockerCompose,
|
composeFile: input.dockerCompose,
|
||||||
env: input.envVariables,
|
env: input.envVariables,
|
||||||
serverId: input.serverId,
|
serverId: input.serverId,
|
||||||
name: input.name,
|
name: input.name,
|
||||||
sourceType: "raw",
|
sourceType: "raw",
|
||||||
appName: `${projectName}-${generatePassword(6)}`,
|
appName: `${projectName}-${generatePassword(6)}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (input.domains && input.domains?.length > 0) {
|
if (input.domains && input.domains?.length > 0) {
|
||||||
for (const domain of input.domains) {
|
for (const domain of input.domains) {
|
||||||
await createDomain({
|
await createDomain({
|
||||||
...domain,
|
...domain,
|
||||||
domainType: "compose",
|
domainType: "compose",
|
||||||
certificateType: "none",
|
certificateType: "none",
|
||||||
composeId: compose.composeId,
|
composeId: compose.composeId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.user.rol === "user") {
|
if (ctx.user.rol === "user") {
|
||||||
await addNewService(ctx.user.authId, compose.composeId);
|
await addNewService(ctx.user.authId, compose.composeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user