mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-18 21:55:24 +02:00
Compare commits
1 Commits
dosu/doc-u
...
dosu/doc-u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4406e0542 |
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -7,7 +7,7 @@ Please describe in a short paragraph what this PR is about.
|
||||
Before submitting this PR, please make sure that:
|
||||
|
||||
- [ ] You created a dedicated branch based on the `canary` branch.
|
||||
- [ ] You have read the suggestions in the CONTRIBUTING.md file https://github.com/Dokploy/dokploy/blob/canary/CONTRIBUTING.md#pull-request
|
||||
- [ ] You have read the suggestions in the CONTRIBUTING.md file https://github.com/MkinG2k0/dokploy/blob/canary/CONTRIBUTING.md#pull-request
|
||||
- [ ] You have tested this PR in your local instance. If you have not tested it yet, please do so before submitting. This helps avoid wasting maintainers' time reviewing code that has not been verified by you.
|
||||
|
||||
## Issues related (if applicable)
|
||||
|
||||
@@ -20,7 +20,7 @@ Dokploy includes multiple features to make your life easier.
|
||||
|
||||
- **Applications**: Deploy any type of application (Node.js, PHP, Python, Go, Ruby, etc.).
|
||||
- **Databases**: Create and manage databases with support for MySQL, PostgreSQL, MongoDB, MariaDB, libsql, and Redis.
|
||||
- **Backups**: Automate backups for databases to external storage destinations (S3, SFTP, FTP, Google Drive).
|
||||
- **Backups**: Automate backups for databases to an external storage destination.
|
||||
- **Docker Compose**: Native support for Docker Compose to manage complex applications.
|
||||
- **Multi Node**: Scale applications to multiple nodes using Docker Swarm to manage the cluster.
|
||||
- **Templates**: Deploy open-source templates (Plausible, Pocketbase, Calcom, etc.) with a single click.
|
||||
|
||||
@@ -130,7 +130,7 @@ export const columns: ColumnDef<Container>[] = [
|
||||
</DockerTerminalModal>
|
||||
<RemoveContainerDialog
|
||||
containerId={container.containerId}
|
||||
serverId={container.serverId ?? undefined}
|
||||
serverId={container.serverId}
|
||||
/>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
|
||||
import { PenBoxIcon, PlusIcon, Trash2 } from "lucide-react";
|
||||
import { PenBoxIcon, PlusIcon } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useFieldArray, useForm } from "react-hook-form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
@@ -35,10 +35,6 @@ import {
|
||||
} from "@/components/ui/select";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { api } from "@/utils/api";
|
||||
import {
|
||||
ADDITIONAL_FLAG_ERROR,
|
||||
ADDITIONAL_FLAG_REGEX,
|
||||
} from "@dokploy/server/db/validations/destination";
|
||||
import { S3_PROVIDERS } from "./constants";
|
||||
|
||||
const addDestination = z.object({
|
||||
@@ -50,16 +46,6 @@ const addDestination = z.object({
|
||||
region: z.string(),
|
||||
endpoint: z.string().min(1, "Endpoint is required"),
|
||||
serverId: z.string().optional(),
|
||||
additionalFlags: z
|
||||
.array(
|
||||
z.object({
|
||||
value: z
|
||||
.string()
|
||||
.min(1, "Flag cannot be empty")
|
||||
.regex(ADDITIONAL_FLAG_REGEX, ADDITIONAL_FLAG_ERROR),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
});
|
||||
|
||||
type AddDestination = z.infer<typeof addDestination>;
|
||||
@@ -103,16 +89,9 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
region: "",
|
||||
secretAccessKey: "",
|
||||
endpoint: "",
|
||||
additionalFlags: [],
|
||||
},
|
||||
resolver: zodResolver(addDestination),
|
||||
});
|
||||
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
control: form.control,
|
||||
name: "additionalFlags",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (destination) {
|
||||
form.reset({
|
||||
@@ -123,8 +102,6 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
bucket: destination.bucket,
|
||||
region: destination.region,
|
||||
endpoint: destination.endpoint,
|
||||
additionalFlags:
|
||||
destination.additionalFlags?.map((f) => ({ value: f })) ?? [],
|
||||
});
|
||||
} else {
|
||||
form.reset();
|
||||
@@ -141,7 +118,6 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
region: data.region,
|
||||
secretAccessKey: data.secretAccessKey,
|
||||
destinationId: destinationId || "",
|
||||
additionalFlags: data.additionalFlags?.map((f) => f.value) ?? [],
|
||||
})
|
||||
.then(async () => {
|
||||
toast.success(`Destination ${destinationId ? "Updated" : "Created"}`);
|
||||
@@ -151,12 +127,9 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
}
|
||||
setOpen(false);
|
||||
})
|
||||
.catch((e) => {
|
||||
.catch(() => {
|
||||
toast.error(
|
||||
`Error ${destinationId ? "Updating" : "Creating"} the Destination`,
|
||||
{
|
||||
description: e.message,
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
@@ -168,7 +141,6 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
"secretAccessKey",
|
||||
"bucket",
|
||||
"endpoint",
|
||||
"additionalFlags",
|
||||
]);
|
||||
|
||||
if (!result) {
|
||||
@@ -207,8 +179,6 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
region,
|
||||
secretAccessKey: secretKey,
|
||||
serverId,
|
||||
additionalFlags:
|
||||
form.getValues("additionalFlags")?.map((f) => f.value) ?? [],
|
||||
})
|
||||
.then(() => {
|
||||
toast.success("Connection Success");
|
||||
@@ -388,48 +358,6 @@ export const HandleDestinations = ({ destinationId }: Props) => {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<FormLabel>Additional Flags (Optional)</FormLabel>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => append({ value: "" })}
|
||||
>
|
||||
<PlusIcon className="size-4" />
|
||||
Add Flag
|
||||
</Button>
|
||||
</div>
|
||||
{fields.map((field, index) => (
|
||||
<FormField
|
||||
key={field.id}
|
||||
control={form.control}
|
||||
name={`additionalFlags.${index}.value`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<div className="flex items-center gap-2">
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="--s3-sign-accept-encoding=false"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => remove(index)}
|
||||
>
|
||||
<Trash2 className="size-4 text-muted-foreground" />
|
||||
</Button>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<DialogFooter
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE "destination" ADD COLUMN "additionalFlags" text[];
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1086,13 +1086,6 @@
|
||||
"when": 1774337356154,
|
||||
"tag": "0154_careful_eternals",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 155,
|
||||
"version": "7",
|
||||
"when": 1774794547865,
|
||||
"tag": "0155_careless_clea",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -47,15 +47,8 @@ export const destinationRouter = createTRPCRouter({
|
||||
testConnection: withPermission("destination", "create")
|
||||
.input(apiCreateDestination)
|
||||
.mutation(async ({ input }) => {
|
||||
const {
|
||||
secretAccessKey,
|
||||
bucket,
|
||||
region,
|
||||
endpoint,
|
||||
accessKey,
|
||||
provider,
|
||||
additionalFlags,
|
||||
} = input;
|
||||
const { secretAccessKey, bucket, region, endpoint, accessKey, provider } =
|
||||
input;
|
||||
try {
|
||||
const rcloneFlags = [
|
||||
`--s3-access-key-id="${accessKey}"`,
|
||||
@@ -72,9 +65,6 @@ export const destinationRouter = createTRPCRouter({
|
||||
if (provider) {
|
||||
rcloneFlags.unshift(`--s3-provider="${provider}"`);
|
||||
}
|
||||
if (additionalFlags?.length) {
|
||||
rcloneFlags.push(...additionalFlags);
|
||||
}
|
||||
const rcloneDestination = `:s3:${bucket}`;
|
||||
const rcloneCommand = `rclone ls ${rcloneFlags.join(" ")} "${rcloneDestination}"`;
|
||||
|
||||
@@ -169,14 +159,7 @@ export const destinationRouter = createTRPCRouter({
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message:
|
||||
error instanceof Error
|
||||
? error?.message
|
||||
: "Error connecting to bucket",
|
||||
cause: error,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -3,10 +3,6 @@ import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
ADDITIONAL_FLAG_ERROR,
|
||||
ADDITIONAL_FLAG_REGEX,
|
||||
} from "../validations/destination";
|
||||
import { organization } from "./account";
|
||||
import { backups } from "./backups";
|
||||
|
||||
@@ -22,7 +18,6 @@ export const destinations = pgTable("destination", {
|
||||
bucket: text("bucket").notNull(),
|
||||
region: text("region").notNull(),
|
||||
endpoint: text("endpoint").notNull(),
|
||||
additionalFlags: text("additionalFlags").array(),
|
||||
organizationId: text("organizationId")
|
||||
.notNull()
|
||||
.references(() => organization.id, { onDelete: "cascade" }),
|
||||
@@ -49,9 +44,6 @@ const createSchema = createInsertSchema(destinations, {
|
||||
endpoint: z.string(),
|
||||
secretAccessKey: z.string(),
|
||||
region: z.string(),
|
||||
additionalFlags: z
|
||||
.array(z.string().regex(ADDITIONAL_FLAG_REGEX, ADDITIONAL_FLAG_ERROR))
|
||||
.default([]),
|
||||
});
|
||||
|
||||
export const apiCreateDestination = createSchema
|
||||
@@ -63,7 +55,6 @@ export const apiCreateDestination = createSchema
|
||||
region: true,
|
||||
endpoint: true,
|
||||
secretAccessKey: true,
|
||||
additionalFlags: true,
|
||||
})
|
||||
.required()
|
||||
.extend({
|
||||
@@ -90,7 +81,6 @@ export const apiUpdateDestination = createSchema
|
||||
secretAccessKey: true,
|
||||
destinationId: true,
|
||||
provider: true,
|
||||
additionalFlags: true,
|
||||
})
|
||||
.required()
|
||||
.extend({
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export const ADDITIONAL_FLAG_REGEX = /^--[a-zA-Z0-9-]+(=[a-zA-Z0-9._:/@-]+)?$/;
|
||||
export const ADDITIONAL_FLAG_ERROR =
|
||||
"Invalid flag format. Must start with -- (e.g. --s3-sign-accept-encoding=false)";
|
||||
@@ -1,7 +1,6 @@
|
||||
export * from "./auth/random-password";
|
||||
export * from "./constants/index";
|
||||
export * from "./db/constants";
|
||||
export * from "./db/validations/destination";
|
||||
export * from "./db/validations/domain";
|
||||
export * from "./db/validations/index";
|
||||
export * from "./lib/auth";
|
||||
|
||||
@@ -729,7 +729,6 @@ export const createCustomNotification = async (
|
||||
appDeploy: input.appDeploy,
|
||||
appBuildError: input.appBuildError,
|
||||
databaseBackup: input.databaseBackup,
|
||||
volumeBackup: input.volumeBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
notificationType: "custom",
|
||||
@@ -854,7 +853,6 @@ export const createLarkNotification = async (
|
||||
appDeploy: input.appDeploy,
|
||||
appBuildError: input.appBuildError,
|
||||
databaseBackup: input.databaseBackup,
|
||||
volumeBackup: input.volumeBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
notificationType: "lark",
|
||||
@@ -1051,7 +1049,6 @@ export const createMattermostNotification = async (
|
||||
appDeploy: input.appDeploy,
|
||||
appBuildError: input.appBuildError,
|
||||
databaseBackup: input.databaseBackup,
|
||||
volumeBackup: input.volumeBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
notificationType: "mattermost",
|
||||
@@ -1083,7 +1080,6 @@ export const updateMattermostNotification = async (
|
||||
appDeploy: input.appDeploy,
|
||||
appBuildError: input.appBuildError,
|
||||
databaseBackup: input.databaseBackup,
|
||||
volumeBackup: input.volumeBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
dockerCleanup: input.dockerCleanup,
|
||||
organizationId: input.organizationId,
|
||||
|
||||
@@ -79,10 +79,6 @@ export const getS3Credentials = (destination: Destination) => {
|
||||
rcloneFlags.unshift(`--s3-provider="${provider}"`);
|
||||
}
|
||||
|
||||
if (destination.additionalFlags?.length) {
|
||||
rcloneFlags.push(...destination.additionalFlags);
|
||||
}
|
||||
|
||||
return rcloneFlags;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user