Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d9c34c4
Update Simplified Chinese
f3liiix Apr 6, 2025
7ac7481
Update Simplified Chinese
f3liiix Apr 6, 2025
350bed2
Delete the extract script
f3liiix Apr 6, 2025
0e1f0b4
fix(gitlab): update group name label and enhance group name handling
lorenzomigliorero Apr 7, 2025
1279fac
[autofix.ci] apply automated fixes
autofix-ci[bot] Apr 7, 2025
8e97c63
[autofix.ci] apply automated fixes
autofix-ci[bot] Apr 13, 2025
3d42bfc
feat: implement debounced search functionality in RestoreBackup compo…
Siumauricio Apr 14, 2025
dfd3dc1
Merge pull request #1706 from Dokploy/1649-webserver-restore-backups-bug
Siumauricio Apr 14, 2025
850d06a
chore: bump version to v0.21.7 in package.json
Siumauricio Apr 14, 2025
dbd36fc
Fix for #1708, missing dutch translation and sorted list by population
Axodouble Apr 14, 2025
f405445
[autofix.ci] apply automated fixes
autofix-ci[bot] Apr 14, 2025
0f36bcb
Merge branch 'Dokploy:canary' into canary
f3liiix Apr 14, 2025
8fbad8a
Merge pull request #1709 from Axodouble/fix-missing-nl
Siumauricio Apr 15, 2025
bdc10ca
docs(contributing): recommendations to use biome IDE addons and nvm f…
unleashit Apr 15, 2025
48cfe66
Refactor 2FA enablement flow in Enable2FA component
Siumauricio Apr 17, 2025
f4cd617
Merge pull request #1722 from Dokploy/1715-pin-field-auto-populated-w…
Siumauricio Apr 17, 2025
8e8bc3e
Enhance PostgreSQL backup command in web server utility
Siumauricio Apr 17, 2025
8eaa006
Merge pull request #1723 from Dokploy/1682-dokploy-backup-fails
Siumauricio Apr 17, 2025
a630909
Merge pull request #1634 from f3liiix/canary
Siumauricio Apr 17, 2025
571d73a
Merge pull request #1720 from unleashit/docs/contributing-edits
Siumauricio Apr 17, 2025
33ab87f
fix(gitlab): enhance group name matching logic to support multiple names
Siumauricio Apr 17, 2025
e14f278
Merge pull request #1656 from lorenzomigliorero/support-multiple-gitl…
Siumauricio Apr 17, 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
4 changes: 3 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ feat: add new feature

Before you start, please make the clone based on the `canary` branch, since the `main` branch is the source of truth and should always reflect the latest stable release, also the PRs will be merged to the `canary` branch.

We use Node v20.9.0
We use Node v20.9.0 and recommend this specific version. If you have nvm installed, you can run `nvm install 20.9.0 && nvm use` in the root directory.

```bash
git clone https://github.com/dokploy/dokploy.git
Expand Down Expand Up @@ -87,6 +87,8 @@ pnpm run dokploy:dev

Go to http://localhost:3000 to see the development server

Note: this project uses Biome. If your editor is configured to use another formatter such as Prettier, it's recommended to either change it to use Biome or turn it off.

## Build

```bash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export const RestoreBackup = ({
}: Props) => {
const [isOpen, setIsOpen] = useState(false);
const [search, setSearch] = useState("");
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");

const { data: destinations = [] } = api.destination.all.useQuery();

Expand All @@ -99,13 +100,18 @@ export const RestoreBackup = ({
const destionationId = form.watch("destinationId");

const debouncedSetSearch = debounce((value: string) => {
setDebouncedSearchTerm(value);
}, 150);

const handleSearchChange = (value: string) => {
setSearch(value);
}, 300);
debouncedSetSearch(value);
};

const { data: files = [], isLoading } = api.backup.listBackupFiles.useQuery(
{
destinationId: destionationId,
search,
search: debouncedSearchTerm,
serverId: serverId ?? "",
},
{
Expand Down Expand Up @@ -284,7 +290,8 @@ export const RestoreBackup = ({
<Command>
<CommandInput
placeholder="Search backup files..."
onValueChange={debouncedSetSearch}
value={search}
onValueChange={handleSearchChange}
className="h-9"
/>
{isLoading ? (
Expand All @@ -308,6 +315,8 @@ export const RestoreBackup = ({
key={file}
onSelect={() => {
form.setValue("backupFile", file);
setSearch(file);
setDebouncedSearchTerm(file);
}}
>
<div className="flex w-full justify-between">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,9 @@ export const AddGitlabProvider = () => {
name="groupName"
render={({ field }) => (
<FormItem>
<FormLabel>Group Name (Optional)</FormLabel>
<FormLabel>
Group Name (Optional, Comma-Separated List)
</FormLabel>
<FormControl>
<Input
placeholder="For organization/group access use the slugish name of the group eg: my-org"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ export const EditGitlabProvider = ({ gitlabId }: Props) => {
name="groupName"
render={({ field }) => (
<FormItem>
<FormLabel>Group Name (Optional)</FormLabel>
<FormLabel>
Group Name (Optional, Comma-Separated List)
</FormLabel>
<FormControl>
<Input
placeholder="For organization/group access use the slugish name of the group eg: my-org"
Expand Down
174 changes: 86 additions & 88 deletions apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,61 +61,17 @@ export const Enable2FA = () => {
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [step, setStep] = useState<"password" | "verify">("password");
const [isPasswordLoading, setIsPasswordLoading] = useState(false);
const [otpValue, setOtpValue] = useState("");

const handlePasswordSubmit = async (formData: PasswordForm) => {
setIsPasswordLoading(true);
try {
const { data: enableData, error } = await authClient.twoFactor.enable({
password: formData.password,
issuer: formData.issuer,
});

if (!enableData) {
throw new Error(error?.message || "Error enabling 2FA");
}

if (enableData.backupCodes) {
setBackupCodes(enableData.backupCodes);
}

if (enableData.totpURI) {
const qrCodeUrl = await QRCode.toDataURL(enableData.totpURI);

setData({
qrCodeUrl,
secret: enableData.totpURI.split("secret=")[1]?.split("&")[0] || "",
totpURI: enableData.totpURI,
});

setStep("verify");
toast.success("Scan the QR code with your authenticator app");
} else {
throw new Error("No TOTP URI received from server");
}
} catch (error) {
toast.error(
error instanceof Error ? error.message : "Error setting up 2FA",
);
passwordForm.setError("password", {
message:
error instanceof Error ? error.message : "Error setting up 2FA",
});
} finally {
setIsPasswordLoading(false);
}
};

const handleVerifySubmit = async (formData: PinForm) => {
const handleVerifySubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const result = await authClient.twoFactor.verifyTotp({
code: formData.pin,
code: otpValue,
});

if (result.error) {
if (result.error.code === "INVALID_TWO_FACTOR_AUTHENTICATION") {
pinForm.setError("pin", {
message: "Invalid code. Please try again.",
});
toast.error("Invalid verification code");
return;
}
Expand All @@ -137,15 +93,11 @@ export const Enable2FA = () => {
? "Connection error. Please check your internet connection."
: error.message;

pinForm.setError("pin", {
message: errorMessage,
});
toast.error(errorMessage);
} else {
pinForm.setError("pin", {
message: "Error verifying code",
toast.error("Error verifying 2FA code", {
description: error instanceof Error ? error.message : "Unknown error",
});
toast.error("Error verifying 2FA code");
}
}
};
Expand All @@ -169,10 +121,62 @@ export const Enable2FA = () => {
setStep("password");
setData(null);
setBackupCodes([]);
passwordForm.reset();
pinForm.reset();
setOtpValue("");
passwordForm.reset({
password: "",
issuer: "",
});
}
}, [isDialogOpen, passwordForm, pinForm]);
}, [isDialogOpen, passwordForm]);

useEffect(() => {
if (step === "verify") {
setOtpValue("");
}
}, [step]);

const handlePasswordSubmit = async (formData: PasswordForm) => {
setIsPasswordLoading(true);
try {
const { data: enableData, error } = await authClient.twoFactor.enable({
password: formData.password,
issuer: formData.issuer,
});

if (!enableData) {
throw new Error(error?.message || "Error enabling 2FA");
}

if (enableData.backupCodes) {
setBackupCodes(enableData.backupCodes);
}

if (enableData.totpURI) {
const qrCodeUrl = await QRCode.toDataURL(enableData.totpURI);

setData({
qrCodeUrl,
secret: enableData.totpURI.split("secret=")[1]?.split("&")[0] || "",
totpURI: enableData.totpURI,
});

setStep("verify");
toast.success("Scan the QR code with your authenticator app");
} else {
throw new Error("No TOTP URI received from server");
}
} catch (error) {
toast.error(
error instanceof Error ? error.message : "Error setting up 2FA",
);
passwordForm.setError("password", {
message:
error instanceof Error ? error.message : "Error setting up 2FA",
});
} finally {
setIsPasswordLoading(false);
}
};

return (
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
Expand Down Expand Up @@ -233,7 +237,8 @@ export const Enable2FA = () => {
/>
</FormControl>
<FormDescription>
Enter your password to enable 2FA
Use a custom issuer to identify the service you're
authenticating with.
</FormDescription>
<FormMessage />
</FormItem>
Expand All @@ -250,11 +255,7 @@ export const Enable2FA = () => {
</Form>
) : (
<Form {...pinForm}>
<form
id="pin-form"
onSubmit={pinForm.handleSubmit(handleVerifySubmit)}
className="space-y-6"
>
<form onSubmit={handleVerifySubmit} className="space-y-6">
<div className="flex flex-col gap-6 justify-center items-center">
{data?.qrCodeUrl ? (
<>
Expand Down Expand Up @@ -306,36 +307,33 @@ export const Enable2FA = () => {
)}
</div>

<FormField
control={pinForm.control}
name="pin"
render={({ field }) => (
<FormItem className="flex flex-col justify-center items-center">
<FormLabel>Verification Code</FormLabel>
<FormControl>
<InputOTP maxLength={6} {...field}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
</FormControl>
<FormDescription>
Enter the 6-digit code from your authenticator app
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<div className="flex flex-col justify-center items-center">
<FormLabel>Verification Code</FormLabel>
<InputOTP
maxLength={6}
value={otpValue}
onChange={setOtpValue}
autoComplete="off"
>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
<FormDescription>
Enter the 6-digit code from your authenticator app
</FormDescription>
</div>

<Button
type="submit"
className="w-full"
isLoading={isPasswordLoading}
disabled={otpValue.length !== 6}
>
Enable 2FA
</Button>
Expand Down
28 changes: 16 additions & 12 deletions apps/dokploy/lib/languages.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
/**
* Sorted list based off of population of the country / speakers of the language.
*/
export const Languages = {
english: { code: "en", name: "English" },
polish: { code: "pl", name: "Polski" },
ukrainian: { code: "uk", name: "Українська" },
spanish: { code: "es", name: "Español" },
chineseSimplified: { code: "zh-Hans", name: "简体中文" },
chineseTraditional: { code: "zh-Hant", name: "繁體中文" },
portuguese: { code: "pt-br", name: "Português" },
russian: { code: "ru", name: "Русский" },
french: { code: "fr", name: "Français" },
japanese: { code: "ja", name: "日本語" },
german: { code: "de", name: "Deutsch" },
chineseTraditional: { code: "zh-Hant", name: "繁體中文" },
chineseSimplified: { code: "zh-Hans", name: "简体中文" },
turkish: { code: "tr", name: "Türkçe" },
kazakh: { code: "kz", name: "Қазақ" },
persian: { code: "fa", name: "فارسی" },
korean: { code: "ko", name: "한국어" },
portuguese: { code: "pt-br", name: "Português" },
french: { code: "fr", name: "Français" },
turkish: { code: "tr", name: "Türkçe" },
italian: { code: "it", name: "Italiano" },
japanese: { code: "ja", name: "日本語" },
spanish: { code: "es", name: "Español" },
polish: { code: "pl", name: "Polski" },
ukrainian: { code: "uk", name: "Українська" },
persian: { code: "fa", name: "فارسی" },
dutch: { code: "nl", name: "Nederlands" },
indonesian: { code: "id", name: "Bahasa Indonesia" },
kazakh: { code: "kz", name: "Қазақ" },
norwegian: { code: "no", name: "Norsk" },
azerbaijani: { code: "az", name: "Azərbaycan" },
indonesian: { code: "id", name: "Bahasa Indonesia" },
malayalam: { code: "ml", name: "മലയാളം" },
};

Expand Down
2 changes: 1 addition & 1 deletion apps/dokploy/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dokploy",
"version": "v0.21.6",
"version": "v0.21.7",
"private": true,
"license": "Apache-2.0",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion apps/dokploy/public/locales/nl/common.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{}
{}
Loading