From 468feaa092b373011ecbd101cc37b17b17064877 Mon Sep 17 00:00:00 2001 From: Tam Nguyen Date: Sun, 31 Aug 2025 10:25:09 +1000 Subject: [PATCH 1/4] fix(ui): improve server schedule responsiveness for mobile --- .../deployments/show-deployments.tsx | 454 +++++++++--------- .../application/schedules/show-schedules.tsx | 428 ++++++++--------- 2 files changed, 442 insertions(+), 440 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx index 5efa9e5f..1dad1cf9 100644 --- a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx +++ b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx @@ -7,11 +7,11 @@ import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, } from "@/components/ui/card"; import { api, type RouterOutputs } from "@/utils/api"; import { ShowRollbackSettings } from "../rollbacks/show-rollback-settings"; @@ -20,238 +20,240 @@ import { RefreshToken } from "./refresh-token"; import { ShowDeployment } from "./show-deployment"; interface Props { - id: string; - type: - | "application" - | "compose" - | "schedule" - | "server" - | "backup" - | "previewDeployment" - | "volumeBackup"; - refreshToken?: string; - serverId?: string; + id: string; + type: + | "application" + | "compose" + | "schedule" + | "server" + | "backup" + | "previewDeployment" + | "volumeBackup"; + refreshToken?: string; + serverId?: string; } 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`; + if (seconds < 60) return `${seconds}s`; + const minutes = Math.floor(seconds / 60); + const remainingSeconds = seconds % 60; + return `${minutes}m ${remainingSeconds}s`; }; export const ShowDeployments = ({ - id, - type, - refreshToken, - serverId, + id, + type, + refreshToken, + serverId, }: Props) => { - const [activeLog, setActiveLog] = useState< - RouterOutputs["deployment"]["all"][number] | null - >(null); - const { data: deployments, isLoading: isLoadingDeployments } = - api.deployment.allByType.useQuery( - { - id, - type, - }, - { - enabled: !!id, - refetchInterval: 1000, - }, - ); + const [activeLog, setActiveLog] = useState< + RouterOutputs["deployment"]["all"][number] | null + >(null); + const { data: deployments, isLoading: isLoadingDeployments } = + api.deployment.allByType.useQuery( + { + id, + type, + }, + { + enabled: !!id, + refetchInterval: 1000, + } + ); - const { mutateAsync: rollback, isLoading: isRollingBack } = - api.rollback.rollback.useMutation(); - const { mutateAsync: killProcess, isLoading: isKillingProcess } = - api.deployment.killProcess.useMutation(); + const { mutateAsync: rollback, isLoading: isRollingBack } = + api.rollback.rollback.useMutation(); + const { mutateAsync: killProcess, isLoading: isKillingProcess } = + api.deployment.killProcess.useMutation(); - const [url, setUrl] = React.useState(""); - useEffect(() => { - setUrl(document.location.origin); - }, []); + const [url, setUrl] = React.useState(""); + useEffect(() => { + setUrl(document.location.origin); + }, []); - return ( - - -
- Deployments - - See all the 10 last deployments for this {type} - -
-
- {(type === "application" || type === "compose") && ( - - )} - {type === "application" && ( - - - - )} -
-
- - {refreshToken && ( -
- - If you want to re-deploy this application use this URL in the - config of your git provider or docker - -
- Webhook URL: -
- - {`${url}/api/deploy${type === "compose" ? "/compose" : ""}/${refreshToken}`} - - {(type === "application" || type === "compose") && ( - - )} -
-
-
- )} + return ( + + +
+ Deployments + + See the last 10 deployments for this {type} + +
+
+ {(type === "application" || type === "compose") && ( + + )} + {type === "application" && ( + + + + )} +
+
+ + {refreshToken && ( +
+ + If you want to re-deploy this application use this URL in the + config of your git provider or docker + +
+ Webhook URL: +
+ + {`${url}/api/deploy${ + type === "compose" ? "/compose" : "" + }/${refreshToken}`} + + {(type === "application" || type === "compose") && ( + + )} +
+
+
+ )} - {isLoadingDeployments ? ( -
- - - Loading deployments... - -
- ) : deployments?.length === 0 ? ( -
- - - No deployments found - -
- ) : ( -
- {deployments?.map((deployment, index) => ( -
-
- - {index + 1}. {deployment.status} - - - - {deployment.title} - - {deployment.description && ( - - {deployment.description} - - )} -
-
-
- - {deployment.startedAt && deployment.finishedAt && ( - - - {formatDuration( - Math.floor( - (new Date(deployment.finishedAt).getTime() - - new Date(deployment.startedAt).getTime()) / - 1000, - ), - )} - - )} -
+ {isLoadingDeployments ? ( +
+ + + Loading deployments... + +
+ ) : deployments?.length === 0 ? ( +
+ + + No deployments found + +
+ ) : ( +
+ {deployments?.map((deployment, index) => ( +
+
+ + {index + 1}. {deployment.status} + + + + {deployment.title} + + {deployment.description && ( + + {deployment.description} + + )} +
+
+
+ + {deployment.startedAt && deployment.finishedAt && ( + + + {formatDuration( + Math.floor( + (new Date(deployment.finishedAt).getTime() - + new Date(deployment.startedAt).getTime()) / + 1000 + ) + )} + + )} +
-
- {deployment.pid && deployment.status === "running" && ( - { - await killProcess({ - deploymentId: deployment.deploymentId, - }) - .then(() => { - toast.success("Process killed successfully"); - }) - .catch(() => { - toast.error("Error killing process"); - }); - }} - > - - - )} - +
+ {deployment.pid && deployment.status === "running" && ( + { + await killProcess({ + deploymentId: deployment.deploymentId, + }) + .then(() => { + toast.success("Process killed successfully"); + }) + .catch(() => { + toast.error("Error killing process"); + }); + }} + > + + + )} + - {deployment?.rollback && - deployment.status === "done" && - type === "application" && ( - { - await rollback({ - rollbackId: deployment.rollback.rollbackId, - }) - .then(() => { - toast.success( - "Rollback initiated successfully", - ); - }) - .catch(() => { - toast.error("Error initiating rollback"); - }); - }} - > - - - )} -
-
-
- ))} -
- )} - setActiveLog(null)} - logPath={activeLog?.logPath || ""} - errorMessage={activeLog?.errorMessage || ""} - /> - - - ); + {deployment?.rollback && + deployment.status === "done" && + type === "application" && ( + { + await rollback({ + rollbackId: deployment.rollback.rollbackId, + }) + .then(() => { + toast.success( + "Rollback initiated successfully" + ); + }) + .catch(() => { + toast.error("Error initiating rollback"); + }); + }} + > + + + )} +
+
+
+ ))} +
+ )} + setActiveLog(null)} + logPath={activeLog?.logPath || ""} + errorMessage={activeLog?.errorMessage || ""} + /> +
+
+ ); }; diff --git a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx index 3ebc76de..33981534 100644 --- a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx +++ b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx @@ -1,243 +1,243 @@ import { - ClipboardList, - Clock, - Loader2, - Play, - Terminal, - Trash2, + ClipboardList, + Clock, + Loader2, + Play, + Terminal, + Trash2, } from "lucide-react"; import { toast } from "sonner"; import { DialogAction } from "@/components/shared/dialog-action"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, } from "@/components/ui/card"; import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, } from "@/components/ui/tooltip"; import { api } from "@/utils/api"; import { ShowDeploymentsModal } from "../deployments/show-deployments-modal"; import { HandleSchedules } from "./handle-schedules"; interface Props { - id: string; - scheduleType?: "application" | "compose" | "server" | "dokploy-server"; + id: string; + scheduleType?: "application" | "compose" | "server" | "dokploy-server"; } export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => { - const { - data: schedules, - isLoading: isLoadingSchedules, - refetch: refetchSchedules, - } = api.schedule.list.useQuery( - { - id: id || "", - scheduleType, - }, - { - enabled: !!id, - }, - ); + const { + data: schedules, + isLoading: isLoadingSchedules, + refetch: refetchSchedules, + } = api.schedule.list.useQuery( + { + id: id || "", + scheduleType, + }, + { + enabled: !!id, + } + ); - const utils = api.useUtils(); + const utils = api.useUtils(); - const { mutateAsync: deleteSchedule, isLoading: isDeleting } = - api.schedule.delete.useMutation(); + const { mutateAsync: deleteSchedule, isLoading: isDeleting } = + api.schedule.delete.useMutation(); - const { mutateAsync: runManually, isLoading } = - api.schedule.runManually.useMutation(); + const { mutateAsync: runManually, isLoading } = + api.schedule.runManually.useMutation(); - return ( - - -
-
- - Scheduled Tasks - - - Schedule tasks to run automatically at specified intervals. - -
+ return ( + + +
+
+ + Scheduled Tasks + + + Schedule tasks to run automatically at specified intervals. + +
- {schedules && schedules.length > 0 && ( - - )} -
-
- - {isLoadingSchedules ? ( -
- - - Loading scheduled tasks... - -
- ) : schedules && schedules.length > 0 ? ( -
- {schedules.map((schedule) => { - const serverId = - schedule.serverId || - schedule.application?.serverId || - schedule.compose?.serverId; - return ( -
-
-
- -
-
-
-

- {schedule.name} -

- - {schedule.enabled ? "Enabled" : "Disabled"} - -
-
- - Cron: {schedule.cronExpression} - - {schedule.scheduleType !== "server" && - schedule.scheduleType !== "dokploy-server" && ( - <> - - • - - - {schedule.shellType} - - - )} -
- {schedule.command && ( -
- - - {schedule.command} - -
- )} -
-
+ {schedules && schedules.length > 0 && ( + + )} +
+ + + {isLoadingSchedules ? ( +
+ + + Loading scheduled tasks... + +
+ ) : schedules && schedules.length > 0 ? ( +
+ {schedules.map((schedule) => { + const serverId = + schedule.serverId || + schedule.application?.serverId || + schedule.compose?.serverId; + return ( +
+
+
+ +
+
+
+

+ {schedule.name} +

+ + {schedule.enabled ? "Enabled" : "Disabled"} + +
+
+ + Cron: {schedule.cronExpression} + + {schedule.scheduleType !== "server" && + schedule.scheduleType !== "dokploy-server" && ( + <> + + • + + + {schedule.shellType} + + + )} +
+ {schedule.command && ( +
+ + + {schedule.command} + +
+ )} +
+
-
- - - +
+ + + - - - - - - Run Manual Schedule - - + await runManually({ + scheduleId: schedule.scheduleId, + }) + .then(async () => { + await new Promise((resolve) => + setTimeout(resolve, 1500) + ); + refetchSchedules(); + }) + .catch(() => { + toast.error("Error running schedule"); + }); + }} + > + + + + Run Manual Schedule + + - + - { - await deleteSchedule({ - scheduleId: schedule.scheduleId, - }) - .then(() => { - utils.schedule.list.invalidate({ - id, - scheduleType, - }); - toast.success("Schedule deleted successfully"); - }) - .catch(() => { - toast.error("Error deleting schedule"); - }); - }} - > - - -
-
- ); - })} -
- ) : ( -
- -

- No scheduled tasks -

-

- Create your first scheduled task to automate your workflows -

- -
- )} - - - ); + { + await deleteSchedule({ + scheduleId: schedule.scheduleId, + }) + .then(() => { + utils.schedule.list.invalidate({ + id, + scheduleType, + }); + toast.success("Schedule deleted successfully"); + }) + .catch(() => { + toast.error("Error deleting schedule"); + }); + }} + > + + +
+
+ ); + })} +
+ ) : ( +
+ +

+ No scheduled tasks +

+

+ Create your first scheduled task to automate your workflows +

+ +
+ )} +
+
+ ); }; From a2841fdd30dce6f61c85513c3cad07e660a3a978 Mon Sep 17 00:00:00 2001 From: Tam Nguyen Date: Sun, 31 Aug 2025 10:27:12 +1000 Subject: [PATCH 2/4] fix(ui): flex-wrap for cron and shell type --- .../dashboard/application/schedules/show-schedules.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx index 33981534..d235f6bc 100644 --- a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx +++ b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx @@ -109,7 +109,7 @@ export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => { {schedule.enabled ? "Enabled" : "Disabled"} -
+
Date: Sun, 31 Aug 2025 00:30:08 +0000 Subject: [PATCH 3/4] [autofix.ci] apply automated fixes --- .../deployments/show-deployments.tsx | 456 +++++++++--------- .../application/schedules/show-schedules.tsx | 428 ++++++++-------- 2 files changed, 442 insertions(+), 442 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx index 1dad1cf9..13694a28 100644 --- a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx +++ b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx @@ -7,11 +7,11 @@ import { StatusTooltip } from "@/components/shared/status-tooltip"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, } from "@/components/ui/card"; import { api, type RouterOutputs } from "@/utils/api"; import { ShowRollbackSettings } from "../rollbacks/show-rollback-settings"; @@ -20,240 +20,240 @@ import { RefreshToken } from "./refresh-token"; import { ShowDeployment } from "./show-deployment"; interface Props { - id: string; - type: - | "application" - | "compose" - | "schedule" - | "server" - | "backup" - | "previewDeployment" - | "volumeBackup"; - refreshToken?: string; - serverId?: string; + id: string; + type: + | "application" + | "compose" + | "schedule" + | "server" + | "backup" + | "previewDeployment" + | "volumeBackup"; + refreshToken?: string; + serverId?: string; } 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`; + if (seconds < 60) return `${seconds}s`; + const minutes = Math.floor(seconds / 60); + const remainingSeconds = seconds % 60; + return `${minutes}m ${remainingSeconds}s`; }; export const ShowDeployments = ({ - id, - type, - refreshToken, - serverId, + id, + type, + refreshToken, + serverId, }: Props) => { - const [activeLog, setActiveLog] = useState< - RouterOutputs["deployment"]["all"][number] | null - >(null); - const { data: deployments, isLoading: isLoadingDeployments } = - api.deployment.allByType.useQuery( - { - id, - type, - }, - { - enabled: !!id, - refetchInterval: 1000, - } - ); + const [activeLog, setActiveLog] = useState< + RouterOutputs["deployment"]["all"][number] | null + >(null); + const { data: deployments, isLoading: isLoadingDeployments } = + api.deployment.allByType.useQuery( + { + id, + type, + }, + { + enabled: !!id, + refetchInterval: 1000, + }, + ); - const { mutateAsync: rollback, isLoading: isRollingBack } = - api.rollback.rollback.useMutation(); - const { mutateAsync: killProcess, isLoading: isKillingProcess } = - api.deployment.killProcess.useMutation(); + const { mutateAsync: rollback, isLoading: isRollingBack } = + api.rollback.rollback.useMutation(); + const { mutateAsync: killProcess, isLoading: isKillingProcess } = + api.deployment.killProcess.useMutation(); - const [url, setUrl] = React.useState(""); - useEffect(() => { - setUrl(document.location.origin); - }, []); + const [url, setUrl] = React.useState(""); + useEffect(() => { + setUrl(document.location.origin); + }, []); - return ( - - -
- Deployments - - See the last 10 deployments for this {type} - -
-
- {(type === "application" || type === "compose") && ( - - )} - {type === "application" && ( - - - - )} -
-
- - {refreshToken && ( -
- - If you want to re-deploy this application use this URL in the - config of your git provider or docker - -
- Webhook URL: -
- - {`${url}/api/deploy${ - type === "compose" ? "/compose" : "" - }/${refreshToken}`} - - {(type === "application" || type === "compose") && ( - - )} -
-
-
- )} + return ( + + +
+ Deployments + + See the last 10 deployments for this {type} + +
+
+ {(type === "application" || type === "compose") && ( + + )} + {type === "application" && ( + + + + )} +
+
+ + {refreshToken && ( +
+ + If you want to re-deploy this application use this URL in the + config of your git provider or docker + +
+ Webhook URL: +
+ + {`${url}/api/deploy${ + type === "compose" ? "/compose" : "" + }/${refreshToken}`} + + {(type === "application" || type === "compose") && ( + + )} +
+
+
+ )} - {isLoadingDeployments ? ( -
- - - Loading deployments... - -
- ) : deployments?.length === 0 ? ( -
- - - No deployments found - -
- ) : ( -
- {deployments?.map((deployment, index) => ( -
-
- - {index + 1}. {deployment.status} - - - - {deployment.title} - - {deployment.description && ( - - {deployment.description} - - )} -
-
-
- - {deployment.startedAt && deployment.finishedAt && ( - - - {formatDuration( - Math.floor( - (new Date(deployment.finishedAt).getTime() - - new Date(deployment.startedAt).getTime()) / - 1000 - ) - )} - - )} -
+ {isLoadingDeployments ? ( +
+ + + Loading deployments... + +
+ ) : deployments?.length === 0 ? ( +
+ + + No deployments found + +
+ ) : ( +
+ {deployments?.map((deployment, index) => ( +
+
+ + {index + 1}. {deployment.status} + + + + {deployment.title} + + {deployment.description && ( + + {deployment.description} + + )} +
+
+
+ + {deployment.startedAt && deployment.finishedAt && ( + + + {formatDuration( + Math.floor( + (new Date(deployment.finishedAt).getTime() - + new Date(deployment.startedAt).getTime()) / + 1000, + ), + )} + + )} +
-
- {deployment.pid && deployment.status === "running" && ( - { - await killProcess({ - deploymentId: deployment.deploymentId, - }) - .then(() => { - toast.success("Process killed successfully"); - }) - .catch(() => { - toast.error("Error killing process"); - }); - }} - > - - - )} - +
+ {deployment.pid && deployment.status === "running" && ( + { + await killProcess({ + deploymentId: deployment.deploymentId, + }) + .then(() => { + toast.success("Process killed successfully"); + }) + .catch(() => { + toast.error("Error killing process"); + }); + }} + > + + + )} + - {deployment?.rollback && - deployment.status === "done" && - type === "application" && ( - { - await rollback({ - rollbackId: deployment.rollback.rollbackId, - }) - .then(() => { - toast.success( - "Rollback initiated successfully" - ); - }) - .catch(() => { - toast.error("Error initiating rollback"); - }); - }} - > - - - )} -
-
-
- ))} -
- )} - setActiveLog(null)} - logPath={activeLog?.logPath || ""} - errorMessage={activeLog?.errorMessage || ""} - /> - - - ); + {deployment?.rollback && + deployment.status === "done" && + type === "application" && ( + { + await rollback({ + rollbackId: deployment.rollback.rollbackId, + }) + .then(() => { + toast.success( + "Rollback initiated successfully", + ); + }) + .catch(() => { + toast.error("Error initiating rollback"); + }); + }} + > + + + )} +
+
+
+ ))} +
+ )} + setActiveLog(null)} + logPath={activeLog?.logPath || ""} + errorMessage={activeLog?.errorMessage || ""} + /> +
+
+ ); }; diff --git a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx index d235f6bc..6369b7fd 100644 --- a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx +++ b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx @@ -1,243 +1,243 @@ import { - ClipboardList, - Clock, - Loader2, - Play, - Terminal, - Trash2, + ClipboardList, + Clock, + Loader2, + Play, + Terminal, + Trash2, } from "lucide-react"; import { toast } from "sonner"; import { DialogAction } from "@/components/shared/dialog-action"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, } from "@/components/ui/card"; import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, } from "@/components/ui/tooltip"; import { api } from "@/utils/api"; import { ShowDeploymentsModal } from "../deployments/show-deployments-modal"; import { HandleSchedules } from "./handle-schedules"; interface Props { - id: string; - scheduleType?: "application" | "compose" | "server" | "dokploy-server"; + id: string; + scheduleType?: "application" | "compose" | "server" | "dokploy-server"; } export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => { - const { - data: schedules, - isLoading: isLoadingSchedules, - refetch: refetchSchedules, - } = api.schedule.list.useQuery( - { - id: id || "", - scheduleType, - }, - { - enabled: !!id, - } - ); + const { + data: schedules, + isLoading: isLoadingSchedules, + refetch: refetchSchedules, + } = api.schedule.list.useQuery( + { + id: id || "", + scheduleType, + }, + { + enabled: !!id, + }, + ); - const utils = api.useUtils(); + const utils = api.useUtils(); - const { mutateAsync: deleteSchedule, isLoading: isDeleting } = - api.schedule.delete.useMutation(); + const { mutateAsync: deleteSchedule, isLoading: isDeleting } = + api.schedule.delete.useMutation(); - const { mutateAsync: runManually, isLoading } = - api.schedule.runManually.useMutation(); + const { mutateAsync: runManually, isLoading } = + api.schedule.runManually.useMutation(); - return ( - - -
-
- - Scheduled Tasks - - - Schedule tasks to run automatically at specified intervals. - -
+ return ( + + +
+
+ + Scheduled Tasks + + + Schedule tasks to run automatically at specified intervals. + +
- {schedules && schedules.length > 0 && ( - - )} -
-
- - {isLoadingSchedules ? ( -
- - - Loading scheduled tasks... - -
- ) : schedules && schedules.length > 0 ? ( -
- {schedules.map((schedule) => { - const serverId = - schedule.serverId || - schedule.application?.serverId || - schedule.compose?.serverId; - return ( -
-
-
- -
-
-
-

- {schedule.name} -

- - {schedule.enabled ? "Enabled" : "Disabled"} - -
-
- - Cron: {schedule.cronExpression} - - {schedule.scheduleType !== "server" && - schedule.scheduleType !== "dokploy-server" && ( - <> - - • - - - {schedule.shellType} - - - )} -
- {schedule.command && ( -
- - - {schedule.command} - -
- )} -
-
+ {schedules && schedules.length > 0 && ( + + )} +
+ + + {isLoadingSchedules ? ( +
+ + + Loading scheduled tasks... + +
+ ) : schedules && schedules.length > 0 ? ( +
+ {schedules.map((schedule) => { + const serverId = + schedule.serverId || + schedule.application?.serverId || + schedule.compose?.serverId; + return ( +
+
+
+ +
+
+
+

+ {schedule.name} +

+ + {schedule.enabled ? "Enabled" : "Disabled"} + +
+
+ + Cron: {schedule.cronExpression} + + {schedule.scheduleType !== "server" && + schedule.scheduleType !== "dokploy-server" && ( + <> + + • + + + {schedule.shellType} + + + )} +
+ {schedule.command && ( +
+ + + {schedule.command} + +
+ )} +
+
-
- - - +
+ + + - - - - - - Run Manual Schedule - - + await runManually({ + scheduleId: schedule.scheduleId, + }) + .then(async () => { + await new Promise((resolve) => + setTimeout(resolve, 1500), + ); + refetchSchedules(); + }) + .catch(() => { + toast.error("Error running schedule"); + }); + }} + > + + + + Run Manual Schedule + + - + - { - await deleteSchedule({ - scheduleId: schedule.scheduleId, - }) - .then(() => { - utils.schedule.list.invalidate({ - id, - scheduleType, - }); - toast.success("Schedule deleted successfully"); - }) - .catch(() => { - toast.error("Error deleting schedule"); - }); - }} - > - - -
-
- ); - })} -
- ) : ( -
- -

- No scheduled tasks -

-

- Create your first scheduled task to automate your workflows -

- -
- )} - - - ); + { + await deleteSchedule({ + scheduleId: schedule.scheduleId, + }) + .then(() => { + utils.schedule.list.invalidate({ + id, + scheduleType, + }); + toast.success("Schedule deleted successfully"); + }) + .catch(() => { + toast.error("Error deleting schedule"); + }); + }} + > + + +
+
+ ); + })} +
+ ) : ( +
+ +

+ No scheduled tasks +

+

+ Create your first scheduled task to automate your workflows +

+ +
+ )} +
+
+ ); }; From 38abe032574c1e5468d588c9e0fa35283b96e045 Mon Sep 17 00:00:00 2001 From: Tam Nguyen Date: Sun, 31 Aug 2025 10:36:07 +1000 Subject: [PATCH 4/4] fix(ui): flex-wrap on schedule name and enabled --- .../dashboard/application/schedules/show-schedules.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx index 6369b7fd..3209b6e0 100644 --- a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx +++ b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx @@ -98,7 +98,7 @@ export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => {
-
+

{schedule.name}

@@ -226,7 +226,7 @@ export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => { })}
) : ( -
+

No scheduled tasks