mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat: add remote logs error when is not reachable
This commit is contained in:
@@ -17,8 +17,15 @@ interface Props {
|
|||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
serverId?: string;
|
serverId?: string;
|
||||||
|
errorMessage?: string;
|
||||||
}
|
}
|
||||||
export const ShowDeployment = ({ logPath, open, onClose, serverId }: Props) => {
|
export const ShowDeployment = ({
|
||||||
|
logPath,
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
serverId,
|
||||||
|
errorMessage,
|
||||||
|
}: Props) => {
|
||||||
const [data, setData] = useState("");
|
const [data, setData] = useState("");
|
||||||
const [showExtraLogs, setShowExtraLogs] = useState(false);
|
const [showExtraLogs, setShowExtraLogs] = useState(false);
|
||||||
const [filteredLogs, setFilteredLogs] = useState<LogLine[]>([]);
|
const [filteredLogs, setFilteredLogs] = useState<LogLine[]>([]);
|
||||||
@@ -99,6 +106,8 @@ export const ShowDeployment = ({ logPath, open, onClose, serverId }: Props) => {
|
|||||||
}
|
}
|
||||||
}, [filteredLogs, autoScroll]);
|
}, [filteredLogs, autoScroll]);
|
||||||
|
|
||||||
|
const optionalErrors = parseLogs(errorMessage || "");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={open}
|
open={open}
|
||||||
@@ -157,9 +166,17 @@ export const ShowDeployment = ({ logPath, open, onClose, serverId }: Props) => {
|
|||||||
<TerminalLine key={index} log={log} noTimestamp />
|
<TerminalLine key={index} log={log} noTimestamp />
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<div className="flex justify-center items-center h-full text-muted-foreground">
|
<>
|
||||||
<Loader2 className="h-6 w-6 animate-spin" />
|
{optionalErrors.length > 0 ? (
|
||||||
</div>
|
optionalErrors.map((log: LogLine, index: number) => (
|
||||||
|
<TerminalLine key={`extra-${index}`} log={log} noTimestamp />
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="flex justify-center items-center h-full text-muted-foreground">
|
||||||
|
<Loader2 className="h-6 w-6 animate-spin" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { api } from "@/utils/api";
|
import { api, type RouterOutputs } from "@/utils/api";
|
||||||
import { RocketIcon } from "lucide-react";
|
import { RocketIcon } from "lucide-react";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { CancelQueues } from "./cancel-queues";
|
import { CancelQueues } from "./cancel-queues";
|
||||||
@@ -18,8 +18,11 @@ import { ShowDeployment } from "./show-deployment";
|
|||||||
interface Props {
|
interface Props {
|
||||||
applicationId: string;
|
applicationId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ShowDeployments = ({ applicationId }: Props) => {
|
export const ShowDeployments = ({ applicationId }: Props) => {
|
||||||
const [activeLog, setActiveLog] = useState<string | null>(null);
|
const [activeLog, setActiveLog] = useState<
|
||||||
|
RouterOutputs["deployment"]["all"][number] | null
|
||||||
|
>(null);
|
||||||
const { data } = api.application.one.useQuery({ applicationId });
|
const { data } = api.application.one.useQuery({ applicationId });
|
||||||
const { data: deployments } = api.deployment.all.useQuery(
|
const { data: deployments } = api.deployment.all.useQuery(
|
||||||
{ applicationId },
|
{ applicationId },
|
||||||
@@ -100,7 +103,7 @@ export const ShowDeployments = ({ applicationId }: Props) => {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActiveLog(deployment.logPath);
|
setActiveLog(deployment);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
@@ -112,9 +115,10 @@ export const ShowDeployments = ({ applicationId }: Props) => {
|
|||||||
)}
|
)}
|
||||||
<ShowDeployment
|
<ShowDeployment
|
||||||
serverId={data?.serverId || ""}
|
serverId={data?.serverId || ""}
|
||||||
open={activeLog !== null}
|
open={Boolean(activeLog && activeLog.logPath !== null)}
|
||||||
onClose={() => setActiveLog(null)}
|
onClose={() => setActiveLog(null)}
|
||||||
logPath={activeLog}
|
logPath={activeLog?.logPath || ""}
|
||||||
|
errorMessage={activeLog?.errorMessage || ""}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ export const ShowPreviewBuilds = ({
|
|||||||
serverId,
|
serverId,
|
||||||
trigger,
|
trigger,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [activeLog, setActiveLog] = useState<string | null>(null);
|
const [activeLog, setActiveLog] = useState<
|
||||||
|
RouterOutputs["deployment"]["all"][number] | null
|
||||||
|
>(null);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
@@ -77,7 +79,7 @@ export const ShowPreviewBuilds = ({
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActiveLog(deployment.logPath);
|
setActiveLog(deployment);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
@@ -89,9 +91,10 @@ export const ShowPreviewBuilds = ({
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<ShowDeployment
|
<ShowDeployment
|
||||||
serverId={serverId || ""}
|
serverId={serverId || ""}
|
||||||
open={activeLog !== null}
|
open={Boolean(activeLog && activeLog.logPath !== null)}
|
||||||
onClose={() => setActiveLog(null)}
|
onClose={() => setActiveLog(null)}
|
||||||
logPath={activeLog}
|
logPath={activeLog?.logPath || ""}
|
||||||
|
errorMessage={activeLog?.errorMessage || ""}
|
||||||
/>
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,12 +17,14 @@ interface Props {
|
|||||||
serverId?: string;
|
serverId?: string;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
errorMessage?: string;
|
||||||
}
|
}
|
||||||
export const ShowDeploymentCompose = ({
|
export const ShowDeploymentCompose = ({
|
||||||
logPath,
|
logPath,
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
serverId,
|
serverId,
|
||||||
|
errorMessage,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [data, setData] = useState("");
|
const [data, setData] = useState("");
|
||||||
const [filteredLogs, setFilteredLogs] = useState<LogLine[]>([]);
|
const [filteredLogs, setFilteredLogs] = useState<LogLine[]>([]);
|
||||||
@@ -105,6 +107,8 @@ export const ShowDeploymentCompose = ({
|
|||||||
}
|
}
|
||||||
}, [filteredLogs, autoScroll]);
|
}, [filteredLogs, autoScroll]);
|
||||||
|
|
||||||
|
const optionalErrors = parseLogs(errorMessage || "");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={open}
|
open={open}
|
||||||
@@ -161,9 +165,17 @@ export const ShowDeploymentCompose = ({
|
|||||||
<TerminalLine key={index} log={log} noTimestamp />
|
<TerminalLine key={index} log={log} noTimestamp />
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<div className="flex justify-center items-center h-full text-muted-foreground">
|
<>
|
||||||
<Loader2 className="h-6 w-6 animate-spin" />
|
{optionalErrors.length > 0 ? (
|
||||||
</div>
|
optionalErrors.map((log: LogLine, index: number) => (
|
||||||
|
<TerminalLine key={`extra-${index}`} log={log} noTimestamp />
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="flex justify-center items-center h-full text-muted-foreground">
|
||||||
|
<Loader2 className="h-6 w-6 animate-spin" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { api } from "@/utils/api";
|
import { api, type RouterOutputs } from "@/utils/api";
|
||||||
import { RocketIcon } from "lucide-react";
|
import { RocketIcon } from "lucide-react";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { CancelQueuesCompose } from "./cancel-queues-compose";
|
import { CancelQueuesCompose } from "./cancel-queues-compose";
|
||||||
@@ -19,7 +19,9 @@ interface Props {
|
|||||||
composeId: string;
|
composeId: string;
|
||||||
}
|
}
|
||||||
export const ShowDeploymentsCompose = ({ composeId }: Props) => {
|
export const ShowDeploymentsCompose = ({ composeId }: Props) => {
|
||||||
const [activeLog, setActiveLog] = useState<string | null>(null);
|
const [activeLog, setActiveLog] = useState<
|
||||||
|
RouterOutputs["deployment"]["all"][number] | null
|
||||||
|
>(null);
|
||||||
const { data } = api.compose.one.useQuery({ composeId });
|
const { data } = api.compose.one.useQuery({ composeId });
|
||||||
const { data: deployments } = api.deployment.allByCompose.useQuery(
|
const { data: deployments } = api.deployment.allByCompose.useQuery(
|
||||||
{ composeId },
|
{ composeId },
|
||||||
@@ -100,7 +102,7 @@ export const ShowDeploymentsCompose = ({ composeId }: Props) => {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActiveLog(deployment.logPath);
|
setActiveLog(deployment);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
@@ -112,9 +114,10 @@ export const ShowDeploymentsCompose = ({ composeId }: Props) => {
|
|||||||
)}
|
)}
|
||||||
<ShowDeploymentCompose
|
<ShowDeploymentCompose
|
||||||
serverId={data?.serverId || ""}
|
serverId={data?.serverId || ""}
|
||||||
open={activeLog !== null}
|
open={Boolean(activeLog && activeLog.logPath !== null)}
|
||||||
onClose={() => setActiveLog(null)}
|
onClose={() => setActiveLog(null)}
|
||||||
logPath={activeLog}
|
logPath={activeLog?.logPath || ""}
|
||||||
|
errorMessage={activeLog?.errorMessage || ""}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -226,7 +226,11 @@ export const AddTemplate = ({ projectId }: Props) => {
|
|||||||
|
|
||||||
<ScrollArea className="h-[calc(98vh-8rem)]">
|
<ScrollArea className="h-[calc(98vh-8rem)]">
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
{isError && (
|
||||||
|
<AlertBlock type="error" className="mb-4">
|
||||||
|
{error?.message}
|
||||||
|
</AlertBlock>
|
||||||
|
)}
|
||||||
|
|
||||||
{templates.length === 0 ? (
|
{templates.length === 0 ? (
|
||||||
<div className="flex justify-center items-center w-full gap-2 min-h-[50vh]">
|
<div className="flex justify-center items-center w-full gap-2 min-h-[50vh]">
|
||||||
|
|||||||
1
apps/dokploy/drizzle/0058_brown_sharon_carter.sql
Normal file
1
apps/dokploy/drizzle/0058_brown_sharon_carter.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "deployment" ADD COLUMN "errorMessage" text;
|
||||||
4341
apps/dokploy/drizzle/meta/0058_snapshot.json
Normal file
4341
apps/dokploy/drizzle/meta/0058_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -407,6 +407,13 @@
|
|||||||
"when": 1737306063563,
|
"when": 1737306063563,
|
||||||
"tag": "0057_tricky_living_tribunal",
|
"tag": "0057_tricky_living_tribunal",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 58,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1737612903012,
|
||||||
|
"tag": "0058_brown_sharon_carter",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -47,6 +47,7 @@ export const deployments = pgTable("deployment", {
|
|||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
.$defaultFn(() => new Date().toISOString()),
|
.$defaultFn(() => new Date().toISOString()),
|
||||||
|
errorMessage: text("errorMessage"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const deploymentsRelations = relations(deployments, ({ one }) => ({
|
export const deploymentsRelations = relations(deployments, ({ one }) => ({
|
||||||
|
|||||||
@@ -98,6 +98,17 @@ export const createDeployment = async (
|
|||||||
}
|
}
|
||||||
return deploymentCreate[0];
|
return deploymentCreate[0];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
await db
|
||||||
|
.insert(deployments)
|
||||||
|
.values({
|
||||||
|
applicationId: deployment.applicationId,
|
||||||
|
title: deployment.title || "Deployment",
|
||||||
|
status: "error",
|
||||||
|
logPath: "",
|
||||||
|
description: deployment.description || "",
|
||||||
|
errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`,
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
await updateApplicationStatus(application.applicationId, "error");
|
await updateApplicationStatus(application.applicationId, "error");
|
||||||
console.log(error);
|
console.log(error);
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
@@ -164,6 +175,17 @@ export const createDeploymentPreview = async (
|
|||||||
}
|
}
|
||||||
return deploymentCreate[0];
|
return deploymentCreate[0];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
await db
|
||||||
|
.insert(deployments)
|
||||||
|
.values({
|
||||||
|
previewDeploymentId: deployment.previewDeploymentId,
|
||||||
|
title: deployment.title || "Deployment",
|
||||||
|
status: "error",
|
||||||
|
logPath: "",
|
||||||
|
description: deployment.description || "",
|
||||||
|
errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`,
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
await updatePreviewDeployment(deployment.previewDeploymentId, {
|
await updatePreviewDeployment(deployment.previewDeploymentId, {
|
||||||
previewStatus: "error",
|
previewStatus: "error",
|
||||||
});
|
});
|
||||||
@@ -226,6 +248,17 @@ echo "Initializing deployment" >> ${logFilePath};
|
|||||||
}
|
}
|
||||||
return deploymentCreate[0];
|
return deploymentCreate[0];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
await db
|
||||||
|
.insert(deployments)
|
||||||
|
.values({
|
||||||
|
composeId: deployment.composeId,
|
||||||
|
title: deployment.title || "Deployment",
|
||||||
|
status: "error",
|
||||||
|
logPath: "",
|
||||||
|
description: deployment.description || "",
|
||||||
|
errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`,
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
await updateCompose(compose.composeId, {
|
await updateCompose(compose.composeId, {
|
||||||
composeStatus: "error",
|
composeStatus: "error",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export const createMount = async (input: typeof apiCreateMount._type) => {
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "BAD_REQUEST",
|
code: "BAD_REQUEST",
|
||||||
message: "Error creating the mount",
|
message: `Error ${error instanceof Error ? error.message : error}`,
|
||||||
cause: error,
|
cause: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ export const createFileMount = async (mountId: string) => {
|
|||||||
console.log(`Error creating the file mount: ${error}`);
|
console.log(`Error creating the file mount: ${error}`);
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "BAD_REQUEST",
|
code: "BAD_REQUEST",
|
||||||
message: "Error creating the mount",
|
message: `Error creating the mount ${error instanceof Error ? error.message : error}`,
|
||||||
cause: error,
|
cause: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user