From 0477329db7e45789caa53eef7501f4d3d74bfcbe Mon Sep 17 00:00:00 2001 From: chuyun Date: Wed, 27 Nov 2024 02:14:45 +0800 Subject: [PATCH] feat: add optional Provider attribute to S3 Destinations --- .../settings/destination/add-destination.tsx | 40 + .../settings/destination/constants.ts | 133 + .../destination/update-destination.tsx | 39 + .../settings/web-server/update-server.tsx | 2 +- apps/dokploy/drizzle/0045_smiling_blur.sql | 1 + apps/dokploy/drizzle/meta/0045_snapshot.json | 3981 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + .../dokploy/server/api/routers/destination.ts | 8 +- apps/dokploy/templates/templates.ts | 16 +- packages/server/src/db/schema/destination.ts | 3 + packages/server/src/utils/backups/utils.ts | 8 +- 11 files changed, 4224 insertions(+), 14 deletions(-) create mode 100644 apps/dokploy/components/dashboard/settings/destination/constants.ts create mode 100644 apps/dokploy/drizzle/0045_smiling_blur.sql create mode 100644 apps/dokploy/drizzle/meta/0045_snapshot.json diff --git a/apps/dokploy/components/dashboard/settings/destination/add-destination.tsx b/apps/dokploy/components/dashboard/settings/destination/add-destination.tsx index b8718d3b..a4486098 100644 --- a/apps/dokploy/components/dashboard/settings/destination/add-destination.tsx +++ b/apps/dokploy/components/dashboard/settings/destination/add-destination.tsx @@ -34,9 +34,11 @@ import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; +import { S3_PROVIDERS } from "./constants"; const addDestination = z.object({ name: z.string().min(1, "Name is required"), + provider: z.string().optional(), accessKeyId: z.string(), secretAccessKey: z.string(), bucket: z.string(), @@ -58,6 +60,7 @@ export const AddDestination = () => { api.destination.testConnection.useMutation(); const form = useForm({ defaultValues: { + provider: "", accessKeyId: "", bucket: "", name: "", @@ -73,6 +76,7 @@ export const AddDestination = () => { const onSubmit = async (data: AddDestination) => { await mutateAsync({ + provider: data.provider, accessKey: data.accessKeyId, bucket: data.bucket, endpoint: data.endpoint, @@ -123,6 +127,40 @@ export const AddDestination = () => { ); }} /> + { + return ( + + Provider + + + + + + ); + }} + /> { isLoading={isLoading} onClick={async () => { await testConnection({ + provider: form.getValues("provider"), accessKey: form.getValues("accessKeyId"), bucket: form.getValues("bucket"), endpoint: form.getValues("endpoint"), @@ -283,6 +322,7 @@ export const AddDestination = () => { variant="secondary" onClick={async () => { await testConnection({ + provider: form.getValues("provider"), accessKey: form.getValues("accessKeyId"), bucket: form.getValues("bucket"), endpoint: form.getValues("endpoint"), diff --git a/apps/dokploy/components/dashboard/settings/destination/constants.ts b/apps/dokploy/components/dashboard/settings/destination/constants.ts new file mode 100644 index 00000000..f43e47d1 --- /dev/null +++ b/apps/dokploy/components/dashboard/settings/destination/constants.ts @@ -0,0 +1,133 @@ +export const S3_PROVIDERS: Array<{ + key: string; + name: string; +}> = [ + { + key: "AWS", + name: "Amazon Web Services (AWS) S3", + }, + { + key: "Alibaba", + name: "Alibaba Cloud Object Storage System (OSS) formerly Aliyun", + }, + { + key: "ArvanCloud", + name: "Arvan Cloud Object Storage (AOS)", + }, + { + key: "Ceph", + name: "Ceph Object Storage", + }, + { + key: "ChinaMobile", + name: "China Mobile Ecloud Elastic Object Storage (EOS)", + }, + { + key: "Cloudflare", + name: "Cloudflare R2 Storage", + }, + { + key: "DigitalOcean", + name: "DigitalOcean Spaces", + }, + { + key: "Dreamhost", + name: "Dreamhost DreamObjects", + }, + { + key: "GCS", + name: "Google Cloud Storage", + }, + { + key: "HuaweiOBS", + name: "Huawei Object Storage Service", + }, + { + key: "IBMCOS", + name: "IBM COS S3", + }, + { + key: "IDrive", + name: "IDrive e2", + }, + { + key: "IONOS", + name: "IONOS Cloud", + }, + { + key: "LyveCloud", + name: "Seagate Lyve Cloud", + }, + { + key: "Leviia", + name: "Leviia Object Storage", + }, + { + key: "Liara", + name: "Liara Object Storage", + }, + { + key: "Linode", + name: "Linode Object Storage", + }, + { + key: "Magalu", + name: "Magalu Object Storage", + }, + { + key: "Minio", + name: "Minio Object Storage", + }, + { + key: "Netease", + name: "Netease Object Storage (NOS)", + }, + { + key: "Petabox", + name: "Petabox Object Storage", + }, + { + key: "RackCorp", + name: "RackCorp Object Storage", + }, + { + key: "Rclone", + name: "Rclone S3 Server", + }, + { + key: "Scaleway", + name: "Scaleway Object Storage", + }, + { + key: "SeaweedFS", + name: "SeaweedFS S3", + }, + { + key: "StackPath", + name: "StackPath Object Storage", + }, + { + key: "Storj", + name: "Storj (S3 Compatible Gateway)", + }, + { + key: "Synology", + name: "Synology C2 Object Storage", + }, + { + key: "TencentCOS", + name: "Tencent Cloud Object Storage (COS)", + }, + { + key: "Wasabi", + name: "Wasabi Object Storage", + }, + { + key: "Qiniu", + name: "Qiniu Object Storage (Kodo)", + }, + { + key: "Other", + name: "Any other S3 compatible provider", + }, +]; diff --git a/apps/dokploy/components/dashboard/settings/destination/update-destination.tsx b/apps/dokploy/components/dashboard/settings/destination/update-destination.tsx index fbf08c97..474354ba 100644 --- a/apps/dokploy/components/dashboard/settings/destination/update-destination.tsx +++ b/apps/dokploy/components/dashboard/settings/destination/update-destination.tsx @@ -35,9 +35,11 @@ import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; +import { S3_PROVIDERS } from "./constants"; const updateDestination = z.object({ name: z.string().min(1, "Name is required"), + provider: z.string().optional(), accessKeyId: z.string(), secretAccessKey: z.string(), bucket: z.string(), @@ -70,6 +72,7 @@ export const UpdateDestination = ({ destinationId }: Props) => { api.destination.testConnection.useMutation(); const form = useForm({ defaultValues: { + provider: "", accessKeyId: "", bucket: "", name: "", @@ -152,6 +155,40 @@ export const UpdateDestination = ({ destinationId }: Props) => { ); }} /> + { + return ( + + Provider + + + + + + ); + }} + /> { variant={"secondary"} onClick={async () => { await testConnection({ + provider: form.getValues("provider"), accessKey: form.getValues("accessKeyId"), bucket: form.getValues("bucket"), endpoint: form.getValues("endpoint"), @@ -311,6 +349,7 @@ export const UpdateDestination = ({ destinationId }: Props) => { variant="secondary" onClick={async () => { await testConnection({ + provider: form.getValues("provider"), accessKey: form.getValues("accessKeyId"), bucket: form.getValues("bucket"), endpoint: form.getValues("endpoint"), diff --git a/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx b/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx index 7c300e46..48a61c7a 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx @@ -48,7 +48,7 @@ export const UpdateServer = () => {
  • Some bug that is blocking to use some features
  • - We recommend checking the latest version for any breaking changes + We recommend checking the latest version for any breaking changes before updating. Go to{" "} { - const { secretAccessKey, bucket, region, endpoint, accessKey } = input; - + const { secretAccessKey, bucket, region, endpoint, accessKey, provider } = + input; try { const rcloneFlags = [ - // `--s3-provider=Cloudflare`, `--s3-access-key-id=${accessKey}`, `--s3-secret-access-key=${secretAccessKey}`, `--s3-region=${region}`, @@ -52,6 +51,9 @@ export const destinationRouter = createTRPCRouter({ "--s3-no-check-bucket", "--s3-force-path-style", ]; + if (provider) { + rcloneFlags.unshift(`--s3-provider=${provider}`); + } const rcloneDestination = `:s3:${bucket}`; const rcloneCommand = `rclone ls ${rcloneFlags.join(" ")} "${rcloneDestination}"`; diff --git a/apps/dokploy/templates/templates.ts b/apps/dokploy/templates/templates.ts index f6ed672c..e2591124 100644 --- a/apps/dokploy/templates/templates.ts +++ b/apps/dokploy/templates/templates.ts @@ -881,8 +881,8 @@ export const templates: TemplateData[] = [ }, tags: ["forum", "community", "discussion"], load: () => import("./discourse/index").then((m) => m.generate), - }, - { + }, + { id: "immich", name: "Immich", version: "v1.121.0", @@ -896,8 +896,8 @@ export const templates: TemplateData[] = [ }, tags: ["photos", "videos", "backup", "media"], load: () => import("./immich/index").then((m) => m.generate), - }, - { + }, + { id: "twenty", name: "Twenty CRM", version: "latest", @@ -911,8 +911,8 @@ export const templates: TemplateData[] = [ }, tags: ["crm", "sales", "business"], load: () => import("./twenty/index").then((m) => m.generate), - }, - { + }, + { id: "yourls", name: "YOURLS", version: "1.9.2", @@ -926,8 +926,8 @@ export const templates: TemplateData[] = [ }, tags: ["url-shortener", "php"], load: () => import("./yourls/index").then((m) => m.generate), - }, - { + }, + { id: "ryot", name: "Ryot", version: "v7.10", diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index bd9c7762..320a3d7c 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -12,6 +12,7 @@ export const destinations = pgTable("destination", { .primaryKey() .$defaultFn(() => nanoid()), name: text("name").notNull(), + provider: text("provider"), accessKey: text("accessKey").notNull(), secretAccessKey: text("secretAccessKey").notNull(), bucket: text("bucket").notNull(), @@ -37,6 +38,7 @@ export const destinationsRelations = relations( const createSchema = createInsertSchema(destinations, { destinationId: z.string(), name: z.string().min(1), + provider: z.string(), accessKey: z.string(), bucket: z.string(), endpoint: z.string(), @@ -47,6 +49,7 @@ const createSchema = createInsertSchema(destinations, { export const apiCreateDestination = createSchema .pick({ name: true, + provider: true, accessKey: true, bucket: true, region: true, diff --git a/packages/server/src/utils/backups/utils.ts b/packages/server/src/utils/backups/utils.ts index b9656ff2..0d78ff96 100644 --- a/packages/server/src/utils/backups/utils.ts +++ b/packages/server/src/utils/backups/utils.ts @@ -28,9 +28,9 @@ export const removeScheduleBackup = (backupId: string) => { }; export const getS3Credentials = (destination: Destination) => { - const { accessKey, secretAccessKey, bucket, region, endpoint } = destination; + const { accessKey, secretAccessKey, bucket, region, endpoint, provider } = + destination; const rcloneFlags = [ - // `--s3-provider=Cloudflare`, `--s3-access-key-id=${accessKey}`, `--s3-secret-access-key=${secretAccessKey}`, `--s3-region=${region}`, @@ -39,5 +39,9 @@ export const getS3Credentials = (destination: Destination) => { "--s3-force-path-style", ]; + if (provider) { + rcloneFlags.unshift(`--s3-provider=${provider}`); + } + return rcloneFlags; };