Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
94c947e
fix(backups): web-server backups auto-deletion
vicke4 Apr 3, 2025
e176def
[autofix.ci] apply automated fixes
autofix-ci[bot] Apr 3, 2025
6cb4159
Merge branch 'Dokploy:canary' into webserver-backup-auto-delete
vicke4 Apr 3, 2025
8479f20
feat(handle-project): enhance project name validation to disallow sta…
Siumauricio Apr 4, 2025
d43b098
Merge pull request #1623 from Dokploy/1606-project-name-starting-with…
Siumauricio Apr 4, 2025
3617249
refactor(websocket): streamline WebSocket server setup and client ins…
Siumauricio Apr 4, 2025
eff2657
fix: resolve incorrect endpoints for database bulk actions (#1626)
krokodaws Apr 4, 2025
2c09b63
feat: improve projects show grid
lorenzomigliorero Apr 4, 2025
5863e45
remove sensitive files on static build
lorenzomigliorero Apr 4, 2025
e83efa3
Merge pull request #1630 from lorenzomigliorero/feat/improve-projects…
Siumauricio Apr 5, 2025
cb20950
feat(registry): refactor Docker login command execution to use execFi…
Siumauricio Apr 6, 2025
6c8eb3b
Merge pull request #1635 from Dokploy/fix/use-exec-file
Siumauricio Apr 6, 2025
14bc26e
feat(websocket): enhance WebSocket server with request validation and…
Siumauricio Apr 6, 2025
1605aed
feat(settings): add HTTPS support and update user schema
Siumauricio Apr 6, 2025
42fa400
feat(backups): implement normalizeS3Path utility and integrate into b…
Siumauricio Apr 6, 2025
e5a3e56
fix(tests): initialize HTTPS field in user schema for server config t…
Siumauricio Apr 6, 2025
4b51744
Merge pull request #1638 from Dokploy/1588-invalid-behavior-when-usin…
Siumauricio Apr 6, 2025
5a9c763
Merge pull request #1631 from lorenzomigliorero/fix/remove-sensitive-…
Siumauricio Apr 6, 2025
b3bd9ba
Merge pull request #1616 from vicke4/webserver-backup-auto-delete
Siumauricio Apr 6, 2025
bca6af7
fix(traefik): update server configuration to use new host parameter a…
Siumauricio Apr 6, 2025
48ec0a7
Merge pull request #1637 from Dokploy/1601-duplicate-domain-bug
Siumauricio Apr 6, 2025
2352939
fix(application): enhance application reload process with error handl…
Siumauricio Apr 6, 2025
b2a8572
Merge pull request #1640 from Dokploy/1633-bug-using-reload-for-an-ap…
Siumauricio Apr 6, 2025
bea0316
fix(backups): suppress output during backup and restore processes
Siumauricio Apr 6, 2025
1beceb7
Merge pull request #1641 from Dokploy/1590-backup-maxing-buffer-size
Siumauricio Apr 6, 2025
148b1ff
refactor(user-nav): remove settings option for owner role and delete …
Siumauricio Apr 6, 2025
61a20f1
Merge pull request #1629 from krokodaws/fix/bulk-actions
Siumauricio Apr 6, 2025
8f0697b
Update package.json
Siumauricio Apr 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { beforeEach, expect, test, vi } from "vitest";

const baseAdmin: User = {
https: false,
enablePaidFeatures: false,
metricsConfig: {
containers: {
Expand Down Expand Up @@ -73,7 +74,6 @@ beforeEach(() => {

test("Should read the configuration file", () => {
const config: FileConfig = loadOrCreateConfig("dokploy");

expect(config.http?.routers?.["dokploy-router-app"]?.service).toBe(
"dokploy-service-app",
);
Expand All @@ -83,6 +83,7 @@ test("Should apply redirect-to-https", () => {
updateServerTraefik(
{
...baseAdmin,
https: true,
certificateType: "letsencrypt",
},
"example.com",
Expand Down
61 changes: 61 additions & 0 deletions apps/dokploy/__test__/utils/backups.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { describe, expect, test } from "vitest";
import { normalizeS3Path } from "@dokploy/server/utils/backups/utils";

describe("normalizeS3Path", () => {
test("should handle empty and whitespace-only prefix", () => {
expect(normalizeS3Path("")).toBe("");
expect(normalizeS3Path("/")).toBe("");
expect(normalizeS3Path(" ")).toBe("");
expect(normalizeS3Path("\t")).toBe("");
expect(normalizeS3Path("\n")).toBe("");
expect(normalizeS3Path(" \n \t ")).toBe("");
});

test("should trim whitespace from prefix", () => {
expect(normalizeS3Path(" prefix")).toBe("prefix/");
expect(normalizeS3Path("prefix ")).toBe("prefix/");
expect(normalizeS3Path(" prefix ")).toBe("prefix/");
expect(normalizeS3Path("\tprefix\t")).toBe("prefix/");
expect(normalizeS3Path(" prefix/nested ")).toBe("prefix/nested/");
});

test("should remove leading slashes", () => {
expect(normalizeS3Path("/prefix")).toBe("prefix/");
expect(normalizeS3Path("///prefix")).toBe("prefix/");
});

test("should remove trailing slashes", () => {
expect(normalizeS3Path("prefix/")).toBe("prefix/");
expect(normalizeS3Path("prefix///")).toBe("prefix/");
});

test("should remove both leading and trailing slashes", () => {
expect(normalizeS3Path("/prefix/")).toBe("prefix/");
expect(normalizeS3Path("///prefix///")).toBe("prefix/");
});

test("should handle nested paths", () => {
expect(normalizeS3Path("prefix/nested")).toBe("prefix/nested/");
expect(normalizeS3Path("/prefix/nested/")).toBe("prefix/nested/");
expect(normalizeS3Path("///prefix/nested///")).toBe("prefix/nested/");
});

test("should preserve middle slashes", () => {
expect(normalizeS3Path("prefix/nested/deep")).toBe("prefix/nested/deep/");
expect(normalizeS3Path("/prefix/nested/deep/")).toBe("prefix/nested/deep/");
});

test("should handle special characters", () => {
expect(normalizeS3Path("prefix-with-dashes")).toBe("prefix-with-dashes/");
expect(normalizeS3Path("prefix_with_underscores")).toBe(
"prefix_with_underscores/",
);
expect(normalizeS3Path("prefix.with.dots")).toBe("prefix.with.dots/");
});

test("should handle the cases from the bug report", () => {
expect(normalizeS3Path("instance-backups/")).toBe("instance-backups/");
expect(normalizeS3Path("/instance-backups/")).toBe("instance-backups/");
expect(normalizeS3Path("instance-backups")).toBe("instance-backups/");
});
});
23 changes: 8 additions & 15 deletions apps/dokploy/components/dashboard/projects/handle-project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,14 @@ import { toast } from "sonner";
import { z } from "zod";

const AddProjectSchema = z.object({
name: z.string().min(1, {
message: "Name is required",
}),
name: z
.string()
.min(1, {
message: "Name is required",
})
.regex(/^[a-zA-Z]/, {
message: "Project name cannot start with a number",
}),
description: z.string().optional(),
});

Expand Down Expand Up @@ -97,18 +102,6 @@ export const HandleProject = ({ projectId }: Props) => {
);
});
};
// useEffect(() => {
// const getUsers = async () => {
// const users = await authClient.admin.listUsers({
// query: {
// limit: 100,
// },
// });
// console.log(users);
// };

// getUsers();
// });

return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
Expand Down
2 changes: 1 addition & 1 deletion apps/dokploy/components/dashboard/projects/show.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export const ShowProjects = () => {
</span>
</div>
)}
<div className="w-full grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-4 3xl:grid-cols-5 flex-wrap gap-5">
<div className="w-full grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 3xl:grid-cols-5 flex-wrap gap-5">
{filteredProjects?.map((project) => {
const emptyServices =
project?.mariadb.length === 0 &&
Expand Down
111 changes: 74 additions & 37 deletions apps/dokploy/components/dashboard/settings/web-domain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
Expand All @@ -22,6 +23,7 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { GlobeIcon } from "lucide-react";
Expand All @@ -33,11 +35,19 @@ import { z } from "zod";

const addServerDomain = z
.object({
domain: z.string().min(1, { message: "URL is required" }),
domain: z.string(),
letsEncryptEmail: z.string(),
https: z.boolean().optional(),
certificateType: z.enum(["letsencrypt", "none", "custom"]),
})
.superRefine((data, ctx) => {
if (data.https && !data.certificateType) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["certificateType"],
message: "Required",
});
}
if (data.certificateType === "letsencrypt" && !data.letsEncryptEmail) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
Expand All @@ -61,15 +71,18 @@ export const WebDomain = () => {
domain: "",
certificateType: "none",
letsEncryptEmail: "",
https: false,
},
resolver: zodResolver(addServerDomain),
});
const https = form.watch("https");
useEffect(() => {
if (data) {
form.reset({
domain: data?.user?.host || "",
certificateType: data?.user?.certificateType,
letsEncryptEmail: data?.user?.letsEncryptEmail || "",
https: data?.user?.https || false,
});
}
}, [form, form.reset, data]);
Expand All @@ -79,6 +92,7 @@ export const WebDomain = () => {
host: data.domain,
letsEncryptEmail: data.letsEncryptEmail,
certificateType: data.certificateType,
https: data.https,
})
.then(async () => {
await refetch();
Expand Down Expand Up @@ -155,44 +169,67 @@ export const WebDomain = () => {
/>
<FormField
control={form.control}
name="certificateType"
render={({ field }) => {
return (
<FormItem className="md:col-span-2">
<FormLabel>
{t("settings.server.domain.form.certificate.label")}
</FormLabel>
<Select
onValueChange={field.onChange}
value={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue
placeholder={t(
"settings.server.domain.form.certificate.placeholder",
)}
/>
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value={"none"}>
{t(
"settings.server.domain.form.certificateOptions.none",
)}
</SelectItem>
<SelectItem value={"letsencrypt"}>
{t(
"settings.server.domain.form.certificateOptions.letsencrypt",
)}
</SelectItem>
</SelectContent>
</Select>
name="https"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between p-3 mt-4 border rounded-lg shadow-sm w-full col-span-2">
<div className="space-y-0.5">
<FormLabel>HTTPS</FormLabel>
<FormDescription>
Automatically provision SSL Certificate.
</FormDescription>
<FormMessage />
</FormItem>
);
}}
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
{https && (
<FormField
control={form.control}
name="certificateType"
render={({ field }) => {
return (
<FormItem className="md:col-span-2">
<FormLabel>
{t("settings.server.domain.form.certificate.label")}
</FormLabel>
<Select
onValueChange={field.onChange}
value={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue
placeholder={t(
"settings.server.domain.form.certificate.placeholder",
)}
/>
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value={"none"}>
{t(
"settings.server.domain.form.certificateOptions.none",
)}
</SelectItem>
<SelectItem value={"letsencrypt"}>
{t(
"settings.server.domain.form.certificateOptions.letsencrypt",
)}
</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
);
}}
/>
)}

<div className="flex w-full justify-end col-span-2">
<Button isLoading={isLoading} type="submit">
Expand Down
11 changes: 0 additions & 11 deletions apps/dokploy/components/layouts/user-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,6 @@ export const UserNav = () => {
Docker
</DropdownMenuItem>
)}

{data?.role === "owner" && (
<DropdownMenuItem
className="cursor-pointer"
onClick={() => {
router.push("/dashboard/settings");
}}
>
Settings
</DropdownMenuItem>
)}
</>
) : (
<>
Expand Down
1 change: 1 addition & 0 deletions apps/dokploy/drizzle/0084_thin_iron_lad.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE "user_temp" ADD COLUMN "https" boolean DEFAULT false NOT NULL;
Loading
Loading