[autofix.ci] apply automated fixes

This commit is contained in:
autofix-ci[bot]
2025-08-31 00:30:08 +00:00
committed by GitHub
parent a2841fdd30
commit 22e40134ea
2 changed files with 442 additions and 442 deletions
@@ -7,11 +7,11 @@ import { StatusTooltip } from "@/components/shared/status-tooltip";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Card, Card,
CardContent, CardContent,
CardDescription, CardDescription,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { api, type RouterOutputs } from "@/utils/api"; import { api, type RouterOutputs } from "@/utils/api";
import { ShowRollbackSettings } from "../rollbacks/show-rollback-settings"; import { ShowRollbackSettings } from "../rollbacks/show-rollback-settings";
@@ -20,240 +20,240 @@ import { RefreshToken } from "./refresh-token";
import { ShowDeployment } from "./show-deployment"; import { ShowDeployment } from "./show-deployment";
interface Props { interface Props {
id: string; id: string;
type: type:
| "application" | "application"
| "compose" | "compose"
| "schedule" | "schedule"
| "server" | "server"
| "backup" | "backup"
| "previewDeployment" | "previewDeployment"
| "volumeBackup"; | "volumeBackup";
refreshToken?: string; refreshToken?: string;
serverId?: string; serverId?: string;
} }
export const formatDuration = (seconds: number) => { export const formatDuration = (seconds: number) => {
if (seconds < 60) return `${seconds}s`; if (seconds < 60) return `${seconds}s`;
const minutes = Math.floor(seconds / 60); const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60; const remainingSeconds = seconds % 60;
return `${minutes}m ${remainingSeconds}s`; return `${minutes}m ${remainingSeconds}s`;
}; };
export const ShowDeployments = ({ export const ShowDeployments = ({
id, id,
type, type,
refreshToken, refreshToken,
serverId, serverId,
}: Props) => { }: Props) => {
const [activeLog, setActiveLog] = useState< const [activeLog, setActiveLog] = useState<
RouterOutputs["deployment"]["all"][number] | null RouterOutputs["deployment"]["all"][number] | null
>(null); >(null);
const { data: deployments, isLoading: isLoadingDeployments } = const { data: deployments, isLoading: isLoadingDeployments } =
api.deployment.allByType.useQuery( api.deployment.allByType.useQuery(
{ {
id, id,
type, type,
}, },
{ {
enabled: !!id, enabled: !!id,
refetchInterval: 1000, refetchInterval: 1000,
} },
); );
const { mutateAsync: rollback, isLoading: isRollingBack } = const { mutateAsync: rollback, isLoading: isRollingBack } =
api.rollback.rollback.useMutation(); api.rollback.rollback.useMutation();
const { mutateAsync: killProcess, isLoading: isKillingProcess } = const { mutateAsync: killProcess, isLoading: isKillingProcess } =
api.deployment.killProcess.useMutation(); api.deployment.killProcess.useMutation();
const [url, setUrl] = React.useState(""); const [url, setUrl] = React.useState("");
useEffect(() => { useEffect(() => {
setUrl(document.location.origin); setUrl(document.location.origin);
}, []); }, []);
return ( return (
<Card className="bg-background border-none"> <Card className="bg-background border-none">
<CardHeader className="flex flex-row items-center justify-between flex-wrap gap-2"> <CardHeader className="flex flex-row items-center justify-between flex-wrap gap-2">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<CardTitle className="text-xl">Deployments</CardTitle> <CardTitle className="text-xl">Deployments</CardTitle>
<CardDescription> <CardDescription>
See the last 10 deployments for this {type} See the last 10 deployments for this {type}
</CardDescription> </CardDescription>
</div> </div>
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
{(type === "application" || type === "compose") && ( {(type === "application" || type === "compose") && (
<CancelQueues id={id} type={type} /> <CancelQueues id={id} type={type} />
)} )}
{type === "application" && ( {type === "application" && (
<ShowRollbackSettings applicationId={id}> <ShowRollbackSettings applicationId={id}>
<Button variant="outline"> <Button variant="outline">
Configure Rollbacks <Settings className="size-4" /> Configure Rollbacks <Settings className="size-4" />
</Button> </Button>
</ShowRollbackSettings> </ShowRollbackSettings>
)} )}
</div> </div>
</CardHeader> </CardHeader>
<CardContent className="flex flex-col gap-4"> <CardContent className="flex flex-col gap-4">
{refreshToken && ( {refreshToken && (
<div className="flex flex-col gap-2 text-sm"> <div className="flex flex-col gap-2 text-sm">
<span> <span>
If you want to re-deploy this application use this URL in the If you want to re-deploy this application use this URL in the
config of your git provider or docker config of your git provider or docker
</span> </span>
<div className="flex flex-row items-center gap-2 flex-wrap"> <div className="flex flex-row items-center gap-2 flex-wrap">
<span>Webhook URL: </span> <span>Webhook URL: </span>
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
<span className="break-all text-muted-foreground"> <span className="break-all text-muted-foreground">
{`${url}/api/deploy${ {`${url}/api/deploy${
type === "compose" ? "/compose" : "" type === "compose" ? "/compose" : ""
}/${refreshToken}`} }/${refreshToken}`}
</span> </span>
{(type === "application" || type === "compose") && ( {(type === "application" || type === "compose") && (
<RefreshToken id={id} type={type} /> <RefreshToken id={id} type={type} />
)} )}
</div> </div>
</div> </div>
</div> </div>
)} )}
{isLoadingDeployments ? ( {isLoadingDeployments ? (
<div className="flex w-full flex-row items-center justify-center gap-3 pt-10 min-h-[25vh]"> <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" /> <Loader2 className="size-6 text-muted-foreground animate-spin" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
Loading deployments... Loading deployments...
</span> </span>
</div> </div>
) : deployments?.length === 0 ? ( ) : deployments?.length === 0 ? (
<div className="flex w-full flex-col items-center justify-center gap-3 pt-10 min-h-[25vh]"> <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" /> <RocketIcon className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground"> <span className="text-base text-muted-foreground">
No deployments found No deployments found
</span> </span>
</div> </div>
) : ( ) : (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
{deployments?.map((deployment, index) => ( {deployments?.map((deployment, index) => (
<div <div
key={deployment.deploymentId} key={deployment.deploymentId}
className="flex items-center justify-between rounded-lg border p-4 gap-2" className="flex items-center justify-between rounded-lg border p-4 gap-2"
> >
<div className="flex flex-col"> <div className="flex flex-col">
<span className="flex items-center gap-4 font-medium capitalize text-foreground"> <span className="flex items-center gap-4 font-medium capitalize text-foreground">
{index + 1}. {deployment.status} {index + 1}. {deployment.status}
<StatusTooltip <StatusTooltip
status={deployment?.status} status={deployment?.status}
className="size-2.5" className="size-2.5"
/> />
</span> </span>
<span className="text-sm text-muted-foreground"> <span className="text-sm text-muted-foreground">
{deployment.title} {deployment.title}
</span> </span>
{deployment.description && ( {deployment.description && (
<span className="break-all text-sm text-muted-foreground"> <span className="break-all text-sm text-muted-foreground">
{deployment.description} {deployment.description}
</span> </span>
)} )}
</div> </div>
<div className="flex flex-col items-end gap-2"> <div className="flex flex-col items-end gap-2">
<div className="text-sm capitalize text-muted-foreground flex items-center gap-2"> <div className="text-sm capitalize text-muted-foreground flex items-center gap-2">
<DateTooltip date={deployment.createdAt} /> <DateTooltip date={deployment.createdAt} />
{deployment.startedAt && deployment.finishedAt && ( {deployment.startedAt && deployment.finishedAt && (
<Badge <Badge
variant="outline" variant="outline"
className="text-[10px] gap-1 flex items-center" className="text-[10px] gap-1 flex items-center"
> >
<Clock className="size-3" /> <Clock className="size-3" />
{formatDuration( {formatDuration(
Math.floor( Math.floor(
(new Date(deployment.finishedAt).getTime() - (new Date(deployment.finishedAt).getTime() -
new Date(deployment.startedAt).getTime()) / new Date(deployment.startedAt).getTime()) /
1000 1000,
) ),
)} )}
</Badge> </Badge>
)} )}
</div> </div>
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
{deployment.pid && deployment.status === "running" && ( {deployment.pid && deployment.status === "running" && (
<DialogAction <DialogAction
title="Kill Process" title="Kill Process"
description="Are you sure you want to kill the process?" description="Are you sure you want to kill the process?"
type="default" type="default"
onClick={async () => { onClick={async () => {
await killProcess({ await killProcess({
deploymentId: deployment.deploymentId, deploymentId: deployment.deploymentId,
}) })
.then(() => { .then(() => {
toast.success("Process killed successfully"); toast.success("Process killed successfully");
}) })
.catch(() => { .catch(() => {
toast.error("Error killing process"); toast.error("Error killing process");
}); });
}} }}
> >
<Button <Button
variant="destructive" variant="destructive"
size="sm" size="sm"
isLoading={isKillingProcess} isLoading={isKillingProcess}
> >
Kill Process Kill Process
</Button> </Button>
</DialogAction> </DialogAction>
)} )}
<Button <Button
onClick={() => { onClick={() => {
setActiveLog(deployment); setActiveLog(deployment);
}} }}
> >
View View
</Button> </Button>
{deployment?.rollback && {deployment?.rollback &&
deployment.status === "done" && deployment.status === "done" &&
type === "application" && ( type === "application" && (
<DialogAction <DialogAction
title="Rollback to this deployment" title="Rollback to this deployment"
description="Are you sure you want to rollback to this deployment?" description="Are you sure you want to rollback to this deployment?"
type="default" type="default"
onClick={async () => { onClick={async () => {
await rollback({ await rollback({
rollbackId: deployment.rollback.rollbackId, rollbackId: deployment.rollback.rollbackId,
}) })
.then(() => { .then(() => {
toast.success( toast.success(
"Rollback initiated successfully" "Rollback initiated successfully",
); );
}) })
.catch(() => { .catch(() => {
toast.error("Error initiating rollback"); toast.error("Error initiating rollback");
}); });
}} }}
> >
<Button <Button
variant="secondary" variant="secondary"
size="sm" size="sm"
isLoading={isRollingBack} isLoading={isRollingBack}
> >
<RefreshCcw className="size-4 text-primary group-hover:text-red-500" /> <RefreshCcw className="size-4 text-primary group-hover:text-red-500" />
Rollback Rollback
</Button> </Button>
</DialogAction> </DialogAction>
)} )}
</div> </div>
</div> </div>
</div> </div>
))} ))}
</div> </div>
)} )}
<ShowDeployment <ShowDeployment
serverId={serverId} serverId={serverId}
open={Boolean(activeLog && activeLog.logPath !== null)} open={Boolean(activeLog && activeLog.logPath !== null)}
onClose={() => setActiveLog(null)} onClose={() => setActiveLog(null)}
logPath={activeLog?.logPath || ""} logPath={activeLog?.logPath || ""}
errorMessage={activeLog?.errorMessage || ""} errorMessage={activeLog?.errorMessage || ""}
/> />
</CardContent> </CardContent>
</Card> </Card>
); );
}; };
@@ -1,243 +1,243 @@
import { import {
ClipboardList, ClipboardList,
Clock, Clock,
Loader2, Loader2,
Play, Play,
Terminal, Terminal,
Trash2, Trash2,
} from "lucide-react"; } from "lucide-react";
import { toast } from "sonner"; import { toast } from "sonner";
import { DialogAction } from "@/components/shared/dialog-action"; import { DialogAction } from "@/components/shared/dialog-action";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Card, Card,
CardContent, CardContent,
CardDescription, CardDescription,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { import {
Tooltip, Tooltip,
TooltipContent, TooltipContent,
TooltipProvider, TooltipProvider,
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip"; } from "@/components/ui/tooltip";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import { ShowDeploymentsModal } from "../deployments/show-deployments-modal"; import { ShowDeploymentsModal } from "../deployments/show-deployments-modal";
import { HandleSchedules } from "./handle-schedules"; import { HandleSchedules } from "./handle-schedules";
interface Props { interface Props {
id: string; id: string;
scheduleType?: "application" | "compose" | "server" | "dokploy-server"; scheduleType?: "application" | "compose" | "server" | "dokploy-server";
} }
export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => { export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => {
const { const {
data: schedules, data: schedules,
isLoading: isLoadingSchedules, isLoading: isLoadingSchedules,
refetch: refetchSchedules, refetch: refetchSchedules,
} = api.schedule.list.useQuery( } = api.schedule.list.useQuery(
{ {
id: id || "", id: id || "",
scheduleType, scheduleType,
}, },
{ {
enabled: !!id, enabled: !!id,
} },
); );
const utils = api.useUtils(); const utils = api.useUtils();
const { mutateAsync: deleteSchedule, isLoading: isDeleting } = const { mutateAsync: deleteSchedule, isLoading: isDeleting } =
api.schedule.delete.useMutation(); api.schedule.delete.useMutation();
const { mutateAsync: runManually, isLoading } = const { mutateAsync: runManually, isLoading } =
api.schedule.runManually.useMutation(); api.schedule.runManually.useMutation();
return ( return (
<Card className="border px-6 shadow-none bg-transparent h-full min-h-[50vh]"> <Card className="border px-6 shadow-none bg-transparent h-full min-h-[50vh]">
<CardHeader className="px-0"> <CardHeader className="px-0">
<div className="flex justify-between items-center gap-y-2 flex-wrap"> <div className="flex justify-between items-center gap-y-2 flex-wrap">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<CardTitle className="text-xl font-bold flex items-center gap-2"> <CardTitle className="text-xl font-bold flex items-center gap-2">
Scheduled Tasks Scheduled Tasks
</CardTitle> </CardTitle>
<CardDescription> <CardDescription>
Schedule tasks to run automatically at specified intervals. Schedule tasks to run automatically at specified intervals.
</CardDescription> </CardDescription>
</div> </div>
{schedules && schedules.length > 0 && ( {schedules && schedules.length > 0 && (
<HandleSchedules id={id} scheduleType={scheduleType} /> <HandleSchedules id={id} scheduleType={scheduleType} />
)} )}
</div> </div>
</CardHeader> </CardHeader>
<CardContent className="px-0"> <CardContent className="px-0">
{isLoadingSchedules ? ( {isLoadingSchedules ? (
<div className="flex gap-4 w-full items-center justify-center text-center mx-auto min-h-[45vh]"> <div className="flex gap-4 w-full items-center justify-center text-center mx-auto min-h-[45vh]">
<Loader2 className="size-4 text-muted-foreground/70 transition-colors animate-spin self-center" /> <Loader2 className="size-4 text-muted-foreground/70 transition-colors animate-spin self-center" />
<span className="text-sm text-muted-foreground/70"> <span className="text-sm text-muted-foreground/70">
Loading scheduled tasks... Loading scheduled tasks...
</span> </span>
</div> </div>
) : schedules && schedules.length > 0 ? ( ) : schedules && schedules.length > 0 ? (
<div className="grid xl:grid-cols-2 gap-4 grid-cols-1 h-full"> <div className="grid xl:grid-cols-2 gap-4 grid-cols-1 h-full">
{schedules.map((schedule) => { {schedules.map((schedule) => {
const serverId = const serverId =
schedule.serverId || schedule.serverId ||
schedule.application?.serverId || schedule.application?.serverId ||
schedule.compose?.serverId; schedule.compose?.serverId;
return ( return (
<div <div
key={schedule.scheduleId} key={schedule.scheduleId}
className="flex items-center flex-wrap sm:flex-nowrap gap-y-2 justify-between rounded-lg border p-3 transition-colors bg-muted/50" className="flex items-center flex-wrap sm:flex-nowrap gap-y-2 justify-between rounded-lg border p-3 transition-colors bg-muted/50"
> >
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<div className="flex flex-shrink-0 h-9 w-9 items-center justify-center rounded-full bg-primary/5"> <div className="flex flex-shrink-0 h-9 w-9 items-center justify-center rounded-full bg-primary/5">
<Clock className="size-4 text-primary/70" /> <Clock className="size-4 text-primary/70" />
</div> </div>
<div className="space-y-1.5"> <div className="space-y-1.5">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<h3 className="text-sm font-medium leading-none [overflow-wrap:anywhere] line-clamp-3"> <h3 className="text-sm font-medium leading-none [overflow-wrap:anywhere] line-clamp-3">
{schedule.name} {schedule.name}
</h3> </h3>
<Badge <Badge
variant={schedule.enabled ? "default" : "secondary"} variant={schedule.enabled ? "default" : "secondary"}
className="text-[10px] px-1 py-0" className="text-[10px] px-1 py-0"
> >
{schedule.enabled ? "Enabled" : "Disabled"} {schedule.enabled ? "Enabled" : "Disabled"}
</Badge> </Badge>
</div> </div>
<div className="flex items-center gap-2 text-sm text-muted-foreground flex-wrap"> <div className="flex items-center gap-2 text-sm text-muted-foreground flex-wrap">
<Badge <Badge
variant="outline" variant="outline"
className="font-mono text-[10px] bg-transparent" className="font-mono text-[10px] bg-transparent"
> >
Cron: {schedule.cronExpression} Cron: {schedule.cronExpression}
</Badge> </Badge>
{schedule.scheduleType !== "server" && {schedule.scheduleType !== "server" &&
schedule.scheduleType !== "dokploy-server" && ( schedule.scheduleType !== "dokploy-server" && (
<> <>
<span className="text-xs text-muted-foreground/50"> <span className="text-xs text-muted-foreground/50">
• •
</span> </span>
<Badge <Badge
variant="outline" variant="outline"
className="font-mono text-[10px] bg-transparent" className="font-mono text-[10px] bg-transparent"
> >
{schedule.shellType} {schedule.shellType}
</Badge> </Badge>
</> </>
)} )}
</div> </div>
{schedule.command && ( {schedule.command && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Terminal className="size-3.5 text-muted-foreground/70" /> <Terminal className="size-3.5 text-muted-foreground/70" />
<code className="font-mono text-[10px] text-muted-foreground/70"> <code className="font-mono text-[10px] text-muted-foreground/70">
{schedule.command} {schedule.command}
</code> </code>
</div> </div>
)} )}
</div> </div>
</div> </div>
<div className="flex items-center gap-0.5 md:gap-1.5"> <div className="flex items-center gap-0.5 md:gap-1.5">
<ShowDeploymentsModal <ShowDeploymentsModal
id={schedule.scheduleId} id={schedule.scheduleId}
type="schedule" type="schedule"
serverId={serverId || undefined} serverId={serverId || undefined}
> >
<Button variant="ghost" size="icon"> <Button variant="ghost" size="icon">
<ClipboardList className="size-4 transition-colors " /> <ClipboardList className="size-4 transition-colors " />
</Button> </Button>
</ShowDeploymentsModal> </ShowDeploymentsModal>
<TooltipProvider delayDuration={0}> <TooltipProvider delayDuration={0}>
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<Button <Button
type="button" type="button"
variant="ghost" variant="ghost"
size="icon" size="icon"
isLoading={isLoading} isLoading={isLoading}
onClick={async () => { onClick={async () => {
toast.success("Schedule run successfully"); toast.success("Schedule run successfully");
await runManually({ await runManually({
scheduleId: schedule.scheduleId, scheduleId: schedule.scheduleId,
}) })
.then(async () => { .then(async () => {
await new Promise((resolve) => await new Promise((resolve) =>
setTimeout(resolve, 1500) setTimeout(resolve, 1500),
); );
refetchSchedules(); refetchSchedules();
}) })
.catch(() => { .catch(() => {
toast.error("Error running schedule"); toast.error("Error running schedule");
}); });
}} }}
> >
<Play className="size-4 transition-colors" /> <Play className="size-4 transition-colors" />
</Button> </Button>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent>Run Manual Schedule</TooltipContent> <TooltipContent>Run Manual Schedule</TooltipContent>
</Tooltip> </Tooltip>
</TooltipProvider> </TooltipProvider>
<HandleSchedules <HandleSchedules
scheduleId={schedule.scheduleId} scheduleId={schedule.scheduleId}
id={id} id={id}
scheduleType={scheduleType} scheduleType={scheduleType}
/> />
<DialogAction <DialogAction
title="Delete Schedule" title="Delete Schedule"
description="Are you sure you want to delete this schedule?" description="Are you sure you want to delete this schedule?"
type="destructive" type="destructive"
onClick={async () => { onClick={async () => {
await deleteSchedule({ await deleteSchedule({
scheduleId: schedule.scheduleId, scheduleId: schedule.scheduleId,
}) })
.then(() => { .then(() => {
utils.schedule.list.invalidate({ utils.schedule.list.invalidate({
id, id,
scheduleType, scheduleType,
}); });
toast.success("Schedule deleted successfully"); toast.success("Schedule deleted successfully");
}) })
.catch(() => { .catch(() => {
toast.error("Error deleting schedule"); toast.error("Error deleting schedule");
}); });
}} }}
> >
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="group hover:bg-red-500/10 " className="group hover:bg-red-500/10 "
isLoading={isDeleting} isLoading={isDeleting}
> >
<Trash2 className="size-4 text-primary group-hover:text-red-500" /> <Trash2 className="size-4 text-primary group-hover:text-red-500" />
</Button> </Button>
</DialogAction> </DialogAction>
</div> </div>
</div> </div>
); );
})} })}
</div> </div>
) : ( ) : (
<div className="flex flex-col gap-2 items-center justify-center py-12 rounded-lg"> <div className="flex flex-col gap-2 items-center justify-center py-12 rounded-lg">
<Clock className="size-8 mb-4 text-muted-foreground" /> <Clock className="size-8 mb-4 text-muted-foreground" />
<p className="text-lg font-medium text-muted-foreground"> <p className="text-lg font-medium text-muted-foreground">
No scheduled tasks No scheduled tasks
</p> </p>
<p className="text-sm text-muted-foreground mt-1"> <p className="text-sm text-muted-foreground mt-1">
Create your first scheduled task to automate your workflows Create your first scheduled task to automate your workflows
</p> </p>
<HandleSchedules id={id} scheduleType={scheduleType} /> <HandleSchedules id={id} scheduleType={scheduleType} />
</div> </div>
)} )}
</CardContent> </CardContent>
</Card> </Card>
); );
}; };