mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-28 18:45:22 +02:00
Compare commits
14 Commits
fix/webhoo
...
feat/docke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebbc008dbe | ||
|
|
645a81b2ce | ||
|
|
a6db83c758 | ||
|
|
ac65cc97f4 | ||
|
|
30d5493281 | ||
|
|
91b44720ef | ||
|
|
f700017ccf | ||
|
|
9287721dbf | ||
|
|
6cde04ea39 | ||
|
|
283eeeb3e6 | ||
|
|
19ae575fa8 | ||
|
|
c42a16d658 | ||
|
|
b222409129 | ||
|
|
a322ac374c |
@@ -56,17 +56,17 @@ export const ShowEnvironment = ({ id, type }: Props) => {
|
|||||||
const [isEnvVisible, setIsEnvVisible] = useState(true);
|
const [isEnvVisible, setIsEnvVisible] = useState(true);
|
||||||
|
|
||||||
const mutationMap = {
|
const mutationMap = {
|
||||||
compose: () => api.compose.update.useMutation(),
|
compose: () => api.compose.saveEnvironment.useMutation(),
|
||||||
libsql: () => api.libsql.update.useMutation(),
|
libsql: () => api.libsql.saveEnvironment.useMutation(),
|
||||||
mariadb: () => api.mariadb.update.useMutation(),
|
mariadb: () => api.mariadb.saveEnvironment.useMutation(),
|
||||||
mongo: () => api.mongo.update.useMutation(),
|
mongo: () => api.mongo.saveEnvironment.useMutation(),
|
||||||
mysql: () => api.mysql.update.useMutation(),
|
mysql: () => api.mysql.saveEnvironment.useMutation(),
|
||||||
postgres: () => api.postgres.update.useMutation(),
|
postgres: () => api.postgres.saveEnvironment.useMutation(),
|
||||||
redis: () => api.redis.update.useMutation(),
|
redis: () => api.redis.saveEnvironment.useMutation(),
|
||||||
};
|
};
|
||||||
const { mutateAsync, isPending } = mutationMap[type]
|
const { mutateAsync, isPending } = mutationMap[type]
|
||||||
? mutationMap[type]()
|
? mutationMap[type]()
|
||||||
: api.mongo.update.useMutation();
|
: api.mongo.saveEnvironment.useMutation();
|
||||||
|
|
||||||
const form = useForm<EnvironmentSchema>({
|
const form = useForm<EnvironmentSchema>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { toast } from "sonner";
|
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
import { HelpCircle } from "lucide-react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
serverId?: string;
|
serverId?: string;
|
||||||
@@ -52,7 +59,36 @@ export const ToggleDockerCleanup = ({ serverId }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<Switch checked={!!enabled} onCheckedChange={handleToggle} />
|
<Switch checked={!!enabled} onCheckedChange={handleToggle} />
|
||||||
<Label className="text-primary">Daily Docker Cleanup</Label>
|
<TooltipProvider delayDuration={0}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Label className="text-primary flex items-center gap-1.5 cursor-pointer">
|
||||||
|
Daily Docker Cleanup
|
||||||
|
<HelpCircle className="size-4 text-muted-foreground" />
|
||||||
|
</Label>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="top" className="max-w-sm">
|
||||||
|
<p>
|
||||||
|
Runs a full Docker cleanup daily, pruning stopped containers,
|
||||||
|
unused images, volumes, build cache, and system resources. This
|
||||||
|
may remove images built for Compose services that run on-demand
|
||||||
|
(backup runners, cron jobs, one-off tasks).
|
||||||
|
</p>
|
||||||
|
<p className="mt-1">
|
||||||
|
For custom cleanup strategies, use{" "}
|
||||||
|
<a
|
||||||
|
href="https://docs.dokploy.com/docs/core/schedule-jobs#example-1-automatic-docker-cleanup"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="underline text-primary"
|
||||||
|
>
|
||||||
|
Schedule Jobs
|
||||||
|
</a>{" "}
|
||||||
|
on your web server or remote servers.
|
||||||
|
</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,14 +53,9 @@ export default async function handler(
|
|||||||
|
|
||||||
if (sourceType === "github") {
|
if (sourceType === "github") {
|
||||||
const branchName = extractBranchName(req.headers, req.body);
|
const branchName = extractBranchName(req.headers, req.body);
|
||||||
const normalizedCommits =
|
const normalizedCommits = req.body?.commits?.flatMap(
|
||||||
req.body?.commits
|
(commit: any) => commit.modified,
|
||||||
?.flatMap((commit: any) => [
|
);
|
||||||
...(commit.modified || []),
|
|
||||||
...(commit.added || []),
|
|
||||||
...(commit.removed || []),
|
|
||||||
])
|
|
||||||
.filter(Boolean) || [];
|
|
||||||
|
|
||||||
const shouldDeployPaths = shouldDeploy(
|
const shouldDeployPaths = shouldDeploy(
|
||||||
composeResult.watchPaths,
|
composeResult.watchPaths,
|
||||||
@@ -78,14 +73,9 @@ export default async function handler(
|
|||||||
}
|
}
|
||||||
} else if (sourceType === "gitlab") {
|
} else if (sourceType === "gitlab") {
|
||||||
const branchName = extractBranchName(req.headers, req.body);
|
const branchName = extractBranchName(req.headers, req.body);
|
||||||
const normalizedCommits =
|
const normalizedCommits = req.body?.commits?.flatMap(
|
||||||
req.body?.commits
|
(commit: any) => commit.modified,
|
||||||
?.flatMap((commit: any) => [
|
);
|
||||||
...(commit.modified || []),
|
|
||||||
...(commit.added || []),
|
|
||||||
...(commit.removed || []),
|
|
||||||
])
|
|
||||||
.filter(Boolean) || [];
|
|
||||||
|
|
||||||
const shouldDeployPaths = shouldDeploy(
|
const shouldDeployPaths = shouldDeploy(
|
||||||
composeResult.watchPaths,
|
composeResult.watchPaths,
|
||||||
@@ -134,32 +124,17 @@ export default async function handler(
|
|||||||
let normalizedCommits: string[] = [];
|
let normalizedCommits: string[] = [];
|
||||||
|
|
||||||
if (provider === "github") {
|
if (provider === "github") {
|
||||||
normalizedCommits =
|
normalizedCommits = req.body?.commits?.flatMap(
|
||||||
req.body?.commits
|
(commit: any) => commit.modified,
|
||||||
?.flatMap((commit: any) => [
|
);
|
||||||
...(commit.modified || []),
|
|
||||||
...(commit.added || []),
|
|
||||||
...(commit.removed || []),
|
|
||||||
])
|
|
||||||
.filter(Boolean) || [];
|
|
||||||
} else if (provider === "gitlab") {
|
} else if (provider === "gitlab") {
|
||||||
normalizedCommits =
|
normalizedCommits = req.body?.commits?.flatMap(
|
||||||
req.body?.commits
|
(commit: any) => commit.modified,
|
||||||
?.flatMap((commit: any) => [
|
);
|
||||||
...(commit.modified || []),
|
|
||||||
...(commit.added || []),
|
|
||||||
...(commit.removed || []),
|
|
||||||
])
|
|
||||||
.filter(Boolean) || [];
|
|
||||||
} else if (provider === "gitea") {
|
} else if (provider === "gitea") {
|
||||||
normalizedCommits =
|
normalizedCommits = req.body?.commits?.flatMap(
|
||||||
req.body?.commits
|
(commit: any) => commit.modified,
|
||||||
?.flatMap((commit: any) => [
|
);
|
||||||
...(commit.modified || []),
|
|
||||||
...(commit.added || []),
|
|
||||||
...(commit.removed || []),
|
|
||||||
])
|
|
||||||
.filter(Boolean) || [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldDeployPaths = shouldDeploy(
|
const shouldDeployPaths = shouldDeploy(
|
||||||
@@ -174,14 +149,9 @@ export default async function handler(
|
|||||||
} else if (sourceType === "gitea") {
|
} else if (sourceType === "gitea") {
|
||||||
const branchName = extractBranchName(req.headers, req.body);
|
const branchName = extractBranchName(req.headers, req.body);
|
||||||
|
|
||||||
const normalizedCommits =
|
const normalizedCommits = req.body?.commits?.flatMap(
|
||||||
req.body?.commits
|
(commit: any) => commit.modified,
|
||||||
?.flatMap((commit: any) => [
|
);
|
||||||
...(commit.modified || []),
|
|
||||||
...(commit.added || []),
|
|
||||||
...(commit.removed || []),
|
|
||||||
])
|
|
||||||
.filter(Boolean) || [];
|
|
||||||
|
|
||||||
const shouldDeployPaths = shouldDeploy(
|
const shouldDeployPaths = shouldDeploy(
|
||||||
composeResult.watchPaths,
|
composeResult.watchPaths,
|
||||||
|
|||||||
@@ -213,14 +213,9 @@ export default async function handler(
|
|||||||
const deploymentTitle = extractCommitMessage(req.headers, req.body);
|
const deploymentTitle = extractCommitMessage(req.headers, req.body);
|
||||||
const deploymentHash = extractHash(req.headers, req.body);
|
const deploymentHash = extractHash(req.headers, req.body);
|
||||||
const owner = githubBody?.repository?.owner?.name;
|
const owner = githubBody?.repository?.owner?.name;
|
||||||
const normalizedCommits =
|
const normalizedCommits = githubBody?.commits?.flatMap(
|
||||||
githubBody?.commits
|
(commit: any) => commit.modified,
|
||||||
?.flatMap((commit: any) => [
|
);
|
||||||
...(commit.modified || []),
|
|
||||||
...(commit.added || []),
|
|
||||||
...(commit.removed || []),
|
|
||||||
])
|
|
||||||
.filter(Boolean) || [];
|
|
||||||
|
|
||||||
const apps = await db.query.applications.findMany({
|
const apps = await db.query.applications.findMany({
|
||||||
where: and(
|
where: and(
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import {
|
|||||||
apiFindCompose,
|
apiFindCompose,
|
||||||
apiRandomizeCompose,
|
apiRandomizeCompose,
|
||||||
apiRedeployCompose,
|
apiRedeployCompose,
|
||||||
|
apiSaveEnvironmentVariablesCompose,
|
||||||
apiUpdateCompose,
|
apiUpdateCompose,
|
||||||
compose as composeTable,
|
compose as composeTable,
|
||||||
environments,
|
environments,
|
||||||
@@ -201,6 +202,31 @@ export const composeRouter = createTRPCRouter({
|
|||||||
});
|
});
|
||||||
return updated;
|
return updated;
|
||||||
}),
|
}),
|
||||||
|
saveEnvironment: protectedProcedure
|
||||||
|
.input(apiSaveEnvironmentVariablesCompose)
|
||||||
|
.mutation(async ({ input, ctx }) => {
|
||||||
|
await checkServicePermissionAndAccess(ctx, input.composeId, {
|
||||||
|
envVars: ["write"],
|
||||||
|
});
|
||||||
|
const updated = await updateCompose(input.composeId, {
|
||||||
|
env: input.env,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!updated) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "BAD_REQUEST",
|
||||||
|
message: "Error adding environment variables",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await audit(ctx, {
|
||||||
|
action: "update",
|
||||||
|
resourceType: "compose",
|
||||||
|
resourceId: input.composeId,
|
||||||
|
resourceName: updated?.name,
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}),
|
||||||
delete: protectedProcedure
|
delete: protectedProcedure
|
||||||
.input(apiDeleteCompose)
|
.input(apiDeleteCompose)
|
||||||
.mutation(async ({ input, ctx }) => {
|
.mutation(async ({ input, ctx }) => {
|
||||||
@@ -290,7 +316,7 @@ export const composeRouter = createTRPCRouter({
|
|||||||
.input(apiFetchServices)
|
.input(apiFetchServices)
|
||||||
.query(async ({ input, ctx }) => {
|
.query(async ({ input, ctx }) => {
|
||||||
await checkServicePermissionAndAccess(ctx, input.composeId, {
|
await checkServicePermissionAndAccess(ctx, input.composeId, {
|
||||||
service: ["create"],
|
service: ["read"],
|
||||||
});
|
});
|
||||||
return await loadServices(input.composeId, input.type);
|
return await loadServices(input.composeId, input.type);
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -677,7 +677,10 @@ export const notificationRouter = createTRPCRouter({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "BAD_REQUEST",
|
code: "BAD_REQUEST",
|
||||||
message: "Error testing the notification",
|
message:
|
||||||
|
error instanceof Error
|
||||||
|
? `Error testing the notification: ${error.message}`
|
||||||
|
: "Error testing the notification",
|
||||||
cause: error,
|
cause: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,6 +225,13 @@ export const apiUpdateCompose = createSchema
|
|||||||
})
|
})
|
||||||
.omit({ serverId: true });
|
.omit({ serverId: true });
|
||||||
|
|
||||||
|
export const apiSaveEnvironmentVariablesCompose = createSchema
|
||||||
|
.pick({
|
||||||
|
composeId: true,
|
||||||
|
env: true,
|
||||||
|
})
|
||||||
|
.required();
|
||||||
|
|
||||||
export const apiRandomizeCompose = createSchema
|
export const apiRandomizeCompose = createSchema
|
||||||
.pick({
|
.pick({
|
||||||
composeId: true,
|
composeId: true,
|
||||||
|
|||||||
@@ -251,15 +251,22 @@ export const deployCompose = async ({
|
|||||||
} else {
|
} else {
|
||||||
await execAsync(commandWithLog);
|
await execAsync(commandWithLog);
|
||||||
}
|
}
|
||||||
command = "set -e;";
|
|
||||||
if (compose.sourceType !== "raw") {
|
if (compose.sourceType !== "raw") {
|
||||||
|
command = "set -e;";
|
||||||
command += await generateApplyPatchesCommand({
|
command += await generateApplyPatchesCommand({
|
||||||
id: compose.composeId,
|
id: compose.composeId,
|
||||||
type: "compose",
|
type: "compose",
|
||||||
serverId: compose.serverId,
|
serverId: compose.serverId,
|
||||||
});
|
});
|
||||||
|
commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`;
|
||||||
|
if (compose.serverId) {
|
||||||
|
await execAsyncRemote(compose.serverId, commandWithLog);
|
||||||
|
} else {
|
||||||
|
await execAsync(commandWithLog);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
command = "set -e;";
|
||||||
command += await getBuildComposeCommand(entity);
|
command += await getBuildComposeCommand(entity);
|
||||||
commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`;
|
commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`;
|
||||||
if (compose.serverId) {
|
if (compose.serverId) {
|
||||||
@@ -357,6 +364,23 @@ export const rebuildCompose = async ({
|
|||||||
} else {
|
} else {
|
||||||
await execAsync(commandWithLog);
|
await execAsync(commandWithLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (compose.sourceType !== "raw") {
|
||||||
|
command = "set -e;";
|
||||||
|
command += await generateApplyPatchesCommand({
|
||||||
|
id: compose.composeId,
|
||||||
|
type: "compose",
|
||||||
|
serverId: compose.serverId,
|
||||||
|
});
|
||||||
|
commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`;
|
||||||
|
if (compose.serverId) {
|
||||||
|
await execAsyncRemote(compose.serverId, commandWithLog);
|
||||||
|
} else {
|
||||||
|
await execAsync(commandWithLog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command = "set -e;";
|
||||||
command += await getBuildComposeCommand(compose);
|
command += await getBuildComposeCommand(compose);
|
||||||
commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`;
|
commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`;
|
||||||
if (compose.serverId) {
|
if (compose.serverId) {
|
||||||
|
|||||||
@@ -240,14 +240,13 @@ export const sendBuildErrorNotifications = async ({
|
|||||||
value: `\`\`\`${errorMessage}\`\`\``,
|
value: `\`\`\`${errorMessage}\`\`\``,
|
||||||
short: false,
|
short: false,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
{
|
||||||
type: "button",
|
title: "Details",
|
||||||
text: "View Build Details",
|
value: `<${buildLink}|View Build Details>`,
|
||||||
url: buildLink,
|
short: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
mrkdwn_in: ["fields"],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -256,14 +256,13 @@ export const sendBuildSuccessNotifications = async ({
|
|||||||
value: date.toLocaleString(),
|
value: date.toLocaleString(),
|
||||||
short: true,
|
short: true,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
{
|
||||||
type: "button",
|
title: "Details",
|
||||||
text: "View Build Details",
|
value: `<${buildLink}|View Build Details>`,
|
||||||
url: buildLink,
|
short: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
mrkdwn_in: ["fields"],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user