mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Add ShowDeploymentsModal component and refactor ShowDeployments for enhanced deployment handling
- Introduced `ShowDeploymentsModal` component to manage deployment logs and details in a modal interface. - Updated `ShowDeployments` to accept `serverId` and `refreshToken` props, allowing for more flexible deployment data handling. - Refactored API queries in `ShowDeployments` to utilize a unified query for fetching deployments by type, improving code efficiency. - Replaced instances of `ShowSchedulesLogs` with `ShowDeploymentsModal` in relevant components to streamline deployment log access.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
|
||||
|
||||
import type { RouterOutputs } from "@/utils/api";
|
||||
import { useState } from "react";
|
||||
import { ShowDeployment } from "../deployments/show-deployment";
|
||||
import { ShowDeployments } from "./show-deployments";
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
type: "application" | "compose" | "schedule" | "server" | "backup";
|
||||
serverId?: string;
|
||||
refreshToken?: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const formatDuration = (seconds: number) => {
|
||||
if (seconds < 60) return `${seconds}s`;
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = seconds % 60;
|
||||
return `${minutes}m ${remainingSeconds}s`;
|
||||
};
|
||||
|
||||
export const ShowDeploymentsModal = ({
|
||||
id,
|
||||
type,
|
||||
serverId,
|
||||
refreshToken,
|
||||
children,
|
||||
}: Props) => {
|
||||
const [activeLog, setActiveLog] = useState<
|
||||
RouterOutputs["deployment"]["all"][number] | null
|
||||
>(null);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
{children ? (
|
||||
children
|
||||
) : (
|
||||
<Button className="sm:w-auto w-full" size="sm" variant="outline">
|
||||
View Logs
|
||||
</Button>
|
||||
)}
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-5xl p-0">
|
||||
<ShowDeployments
|
||||
id={id}
|
||||
type={type}
|
||||
serverId={serverId}
|
||||
refreshToken={refreshToken}
|
||||
/>
|
||||
</DialogContent>
|
||||
<ShowDeployment
|
||||
serverId={serverId || ""}
|
||||
open={Boolean(activeLog && activeLog.logPath !== null)}
|
||||
onClose={() => setActiveLog(null)}
|
||||
logPath={activeLog?.logPath || ""}
|
||||
errorMessage={activeLog?.errorMessage || ""}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -16,35 +16,34 @@ import { RefreshToken } from "./refresh-token";
|
||||
import { ShowDeployment } from "./show-deployment";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { formatDuration } from "../schedules/show-schedules-logs";
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
type: "application" | "compose";
|
||||
type: "application" | "compose" | "schedule" | "server" | "backup";
|
||||
refreshToken?: string;
|
||||
serverId?: string;
|
||||
}
|
||||
|
||||
export const ShowDeployments = ({ id, type }: Props) => {
|
||||
export const ShowDeployments = ({
|
||||
id,
|
||||
type,
|
||||
refreshToken,
|
||||
serverId,
|
||||
}: Props) => {
|
||||
const [activeLog, setActiveLog] = useState<
|
||||
RouterOutputs["deployment"]["all"][number] | null
|
||||
>(null);
|
||||
const { data } =
|
||||
type === "application"
|
||||
? api.application.one.useQuery({ applicationId: id })
|
||||
: api.compose.one.useQuery({ composeId: id });
|
||||
const { data: deployments, isLoading: isLoadingDeployments } =
|
||||
type === "application"
|
||||
? api.deployment.all.useQuery(
|
||||
{ applicationId: id },
|
||||
{
|
||||
enabled: !!id,
|
||||
refetchInterval: 1000,
|
||||
},
|
||||
)
|
||||
: api.deployment.allByCompose.useQuery(
|
||||
{ composeId: id },
|
||||
{
|
||||
enabled: !!id,
|
||||
refetchInterval: 1000,
|
||||
},
|
||||
);
|
||||
api.deployment.allByType.useQuery(
|
||||
{
|
||||
id,
|
||||
type,
|
||||
},
|
||||
{
|
||||
enabled: !!id,
|
||||
refetchInterval: 1000,
|
||||
},
|
||||
);
|
||||
|
||||
const [url, setUrl] = React.useState("");
|
||||
useEffect(() => {
|
||||
@@ -52,7 +51,7 @@ export const ShowDeployments = ({ id, type }: Props) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Card className="bg-background">
|
||||
<Card className="bg-background border-none">
|
||||
<CardHeader className="flex flex-row items-center justify-between flex-wrap gap-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<CardTitle className="text-xl">Deployments</CardTitle>
|
||||
@@ -60,24 +59,27 @@ export const ShowDeployments = ({ id, type }: Props) => {
|
||||
See all the 10 last deployments for this {type}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<CancelQueues id={id} type={type} />
|
||||
{refreshToken && <CancelQueues id={id} type={type} />}
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-2 text-sm">
|
||||
<span>
|
||||
If you want to re-deploy this application use this URL in the config
|
||||
of your git provider or docker
|
||||
</span>
|
||||
<div className="flex flex-row items-center gap-2 flex-wrap">
|
||||
<span>Webhook URL: </span>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<span className="break-all text-muted-foreground">
|
||||
{`${url}/api/deploy/${data?.refreshToken}`}
|
||||
</span>
|
||||
<RefreshToken id={id} type={type} />
|
||||
{refreshToken && (
|
||||
<div className="flex flex-col gap-2 text-sm">
|
||||
<span>
|
||||
If you want to re-deploy this application use this URL in the
|
||||
config of your git provider or docker
|
||||
</span>
|
||||
<div className="flex flex-row items-center gap-2 flex-wrap">
|
||||
<span>Webhook URL: </span>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<span className="break-all text-muted-foreground">
|
||||
{`${url}/api/deploy/${refreshToken}`}
|
||||
</span>
|
||||
<RefreshToken id={id} type={type} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isLoadingDeployments ? (
|
||||
<div className="flex w-full flex-row items-center justify-center gap-3 pt-10 min-h-[25vh]">
|
||||
<Loader2 className="size-6 text-muted-foreground animate-spin" />
|
||||
@@ -85,7 +87,7 @@ export const ShowDeployments = ({ id, type }: Props) => {
|
||||
Loading deployments...
|
||||
</span>
|
||||
</div>
|
||||
) : data?.deployments?.length === 0 ? (
|
||||
) : deployments?.length === 0 ? (
|
||||
<div className="flex w-full flex-col items-center justify-center gap-3 pt-10 min-h-[25vh]">
|
||||
<RocketIcon className="size-8 text-muted-foreground" />
|
||||
<span className="text-base text-muted-foreground">
|
||||
@@ -149,7 +151,7 @@ export const ShowDeployments = ({ id, type }: Props) => {
|
||||
</div>
|
||||
)}
|
||||
<ShowDeployment
|
||||
serverId={data?.serverId || ""}
|
||||
serverId={serverId}
|
||||
open={Boolean(activeLog && activeLog.logPath !== null)}
|
||||
onClose={() => setActiveLog(null)}
|
||||
logPath={activeLog?.logPath || ""}
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
} from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { toast } from "sonner";
|
||||
import { ShowSchedulesLogs } from "./show-schedules-logs";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
@@ -26,6 +25,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { ShowDeploymentsModal } from "../deployments/show-deployments-modal";
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
@@ -88,7 +88,6 @@ export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => {
|
||||
schedule.serverId ||
|
||||
schedule.application?.serverId ||
|
||||
schedule.compose?.serverId;
|
||||
const deployments = schedule.deployments;
|
||||
return (
|
||||
<div
|
||||
key={schedule.scheduleId}
|
||||
@@ -144,14 +143,15 @@ export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1.5">
|
||||
<ShowSchedulesLogs
|
||||
deployments={deployments || []}
|
||||
<ShowDeploymentsModal
|
||||
id={schedule.scheduleId}
|
||||
type="schedule"
|
||||
serverId={serverId || undefined}
|
||||
>
|
||||
<Button variant="ghost" size="icon">
|
||||
<ClipboardList className="size-4 transition-colors " />
|
||||
</Button>
|
||||
</ShowSchedulesLogs>
|
||||
</ShowDeploymentsModal>
|
||||
|
||||
<TooltipProvider delayDuration={0}>
|
||||
<Tooltip>
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
PostgresqlIcon,
|
||||
} from "@/components/icons/data-tools-icons";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { ShowSchedulesLogs } from "../../application/schedules/show-schedules-logs";
|
||||
import { ShowDeploymentsModal } from "../../application/deployments/show-deployments-modal";
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
@@ -179,12 +179,6 @@ export const ShowBackups = ({
|
||||
)}
|
||||
<div className="flex flex-col gap-6">
|
||||
{postgres?.backups.map((backup) => {
|
||||
const orderedDeployments = backup.deployments.sort(
|
||||
(a, b) =>
|
||||
new Date(b.createdAt).getTime() -
|
||||
new Date(a.createdAt).getTime(),
|
||||
);
|
||||
|
||||
const serverId =
|
||||
"serverId" in postgres ? postgres.serverId : undefined;
|
||||
|
||||
@@ -285,8 +279,9 @@ export const ShowBackups = ({
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row md:flex-col gap-1.5">
|
||||
<ShowSchedulesLogs
|
||||
deployments={orderedDeployments}
|
||||
<ShowDeploymentsModal
|
||||
id={backup.backupId}
|
||||
type="backup"
|
||||
serverId={serverId || undefined}
|
||||
>
|
||||
<Button
|
||||
@@ -296,7 +291,7 @@ export const ShowBackups = ({
|
||||
>
|
||||
<ClipboardList className="size-4 transition-colors " />
|
||||
</Button>
|
||||
</ShowSchedulesLogs>
|
||||
</ShowDeploymentsModal>
|
||||
<TooltipProvider delayDuration={0}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
|
||||
Reference in New Issue
Block a user