From 815b8136fa0f8e803c43e66ed0002952515d54c3 Mon Sep 17 00:00:00 2001 From: Tam Nguyen Date: Mon, 30 Mar 2026 08:59:14 +1100 Subject: [PATCH 1/7] fix: further typos --- .../compose/network/network-root.test.ts | 2 +- .../compose/network/network-service.test.ts | 212 +++--- ...m.test.ts => service-volumes-from.test.ts} | 0 .../__test__/env/stack-environment.test.ts | 198 ++--- .../advanced/redirects/handle-redirect.tsx | 2 +- ...ow-enviroment.tsx => show-environment.tsx} | 0 .../dashboard/application/logs/show.tsx | 4 +- .../dashboard/compose/logs/show-stack.tsx | 4 +- .../database/backups/restore-backup.tsx | 6 +- .../dashboard/docker/logs/terminal-line.tsx | 2 +- .../docker/show/{colums.tsx => columns.tsx} | 0 .../dashboard/docker/show/show-containers.tsx | 2 +- .../settings/servers/setup-server.tsx | 2 +- .../settings/servers/show-servers.tsx | 4 +- ...scription.tsx => welcome-subscription.tsx} | 2 +- apps/dokploy/components/ui/file-tree.tsx | 12 +- .../pages/api/deploy/[refreshToken].ts | 12 +- .../api/deploy/compose/[refreshToken].ts | 6 +- apps/dokploy/pages/api/stripe/webhook.ts | 12 +- .../services/compose/[composeId].tsx | 2 +- .../services/libsql/[libsqlId].tsx | 2 +- .../services/mariadb/[mariadbId].tsx | 2 +- .../services/mongo/[mongoId].tsx | 2 +- .../services/mysql/[mysqlId].tsx | 2 +- .../services/postgres/[postgresId].tsx | 2 +- .../services/redis/[redisId].tsx | 2 +- .../dokploy/server/api/routers/destination.ts | 4 +- packages/server/src/index.ts | 2 +- packages/server/src/services/deployment.ts | 12 +- packages/server/src/services/destination.ts | 2 +- packages/server/src/services/settings.ts | 4 +- packages/server/src/services/user.ts | 678 +++++++++--------- packages/server/src/setup/setup.ts | 8 +- packages/server/src/utils/builders/compose.ts | 152 ++-- .../server/src/utils/builders/docker-file.ts | 134 ++-- packages/server/src/utils/docker/utils.ts | 2 +- ...l-deployments.ts => cancel-deployments.ts} | 0 37 files changed, 747 insertions(+), 747 deletions(-) rename apps/dokploy/__test__/compose/service/{sevice-volumes-from.test.ts => service-volumes-from.test.ts} (100%) rename apps/dokploy/components/dashboard/application/environment/{show-enviroment.tsx => show-environment.tsx} (100%) rename apps/dokploy/components/dashboard/docker/show/{colums.tsx => columns.tsx} (100%) rename apps/dokploy/components/dashboard/settings/servers/welcome-stripe/{welcome-suscription.tsx => welcome-subscription.tsx} (99%) rename packages/server/src/utils/startup/{cancell-deployments.ts => cancel-deployments.ts} (100%) diff --git a/apps/dokploy/__test__/compose/network/network-root.test.ts b/apps/dokploy/__test__/compose/network/network-root.test.ts index 0d3c841d4..1a6817913 100644 --- a/apps/dokploy/__test__/compose/network/network-root.test.ts +++ b/apps/dokploy/__test__/compose/network/network-root.test.ts @@ -292,7 +292,7 @@ networks: dokploy-network: `; -test("It shoudn't add suffix to dokploy-network", () => { +test("It shouldn't add suffix to dokploy-network", () => { const composeData = parse(composeFile7) as ComposeSpecification; const suffix = generateRandomHash(); diff --git a/apps/dokploy/__test__/compose/network/network-service.test.ts b/apps/dokploy/__test__/compose/network/network-service.test.ts index e07fa1546..91eb5da4e 100644 --- a/apps/dokploy/__test__/compose/network/network-service.test.ts +++ b/apps/dokploy/__test__/compose/network/network-service.test.ts @@ -1,7 +1,7 @@ import type { ComposeSpecification } from "@dokploy/server"; import { - addSuffixToServiceNetworks, - generateRandomHash, + addSuffixToServiceNetworks, + generateRandomHash, } from "@dokploy/server"; import { expect, test } from "vitest"; import { parse } from "yaml"; @@ -23,30 +23,30 @@ services: `; test("Add suffix to networks in services", () => { - const composeData = parse(composeFile) as ComposeSpecification; + const composeData = parse(composeFile) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const services = addSuffixToServiceNetworks(composeData.services, suffix); - const actualComposeData = { ...composeData, services }; + if (!composeData?.services) { + return; + } + const services = addSuffixToServiceNetworks(composeData.services, suffix); + const actualComposeData = { ...composeData, services }; - expect(actualComposeData?.services?.web?.networks).toContain( - `frontend-${suffix}`, - ); + expect(actualComposeData?.services?.web?.networks).toContain( + `frontend-${suffix}`, + ); - expect(actualComposeData?.services?.api?.networks).toContain( - `backend-${suffix}`, - ); + expect(actualComposeData?.services?.api?.networks).toContain( + `backend-${suffix}`, + ); - const apiNetworks = actualComposeData?.services?.api?.networks; + const apiNetworks = actualComposeData?.services?.api?.networks; - expect(apiNetworks).toBeDefined(); - expect(actualComposeData?.services?.api?.networks).toContain( - `backend-${suffix}`, - ); + expect(apiNetworks).toBeDefined(); + expect(actualComposeData?.services?.api?.networks).toContain( + `backend-${suffix}`, + ); }); // Caso 2: Objeto con aliases @@ -67,29 +67,29 @@ networks: `; test("Add suffix to networks in services with aliases", () => { - const composeData = parse(composeFile2) as ComposeSpecification; + const composeData = parse(composeFile2) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const services = addSuffixToServiceNetworks(composeData.services, suffix); - const actualComposeData = { ...composeData, services }; + if (!composeData?.services) { + return; + } + const services = addSuffixToServiceNetworks(composeData.services, suffix); + const actualComposeData = { ...composeData, services }; - expect(actualComposeData.services?.api?.networks).toHaveProperty( - `frontend-${suffix}`, - ); + expect(actualComposeData.services?.api?.networks).toHaveProperty( + `frontend-${suffix}`, + ); - const networkConfig = actualComposeData?.services?.api?.networks as { - [key: string]: { aliases?: string[] }; - }; - expect(networkConfig[`frontend-${suffix}`]).toBeDefined(); - expect(networkConfig[`frontend-${suffix}`]?.aliases).toContain("api"); + const networkConfig = actualComposeData?.services?.api?.networks as { + [key: string]: { aliases?: string[] }; + }; + expect(networkConfig[`frontend-${suffix}`]).toBeDefined(); + expect(networkConfig[`frontend-${suffix}`]?.aliases).toContain("api"); - expect(actualComposeData.services?.api?.networks).not.toHaveProperty( - "frontend-ash", - ); + expect(actualComposeData.services?.api?.networks).not.toHaveProperty( + "frontend-ash", + ); }); const composeFile3 = ` @@ -107,19 +107,19 @@ networks: `; test("Add suffix to networks in services (Object with simple networks)", () => { - const composeData = parse(composeFile3) as ComposeSpecification; + const composeData = parse(composeFile3) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const services = addSuffixToServiceNetworks(composeData.services, suffix); - const actualComposeData = { ...composeData, services }; + if (!composeData?.services) { + return; + } + const services = addSuffixToServiceNetworks(composeData.services, suffix); + const actualComposeData = { ...composeData, services }; - expect(actualComposeData.services?.redis?.networks).toHaveProperty( - `backend-${suffix}`, - ); + expect(actualComposeData.services?.redis?.networks).toHaveProperty( + `backend-${suffix}`, + ); }); const composeFileCombined = ` @@ -153,36 +153,36 @@ networks: `; test("Add suffix to networks in services (combined case)", () => { - const composeData = parse(composeFileCombined) as ComposeSpecification; + const composeData = parse(composeFileCombined) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const services = addSuffixToServiceNetworks(composeData.services, suffix); - const actualComposeData = { ...composeData, services }; + if (!composeData?.services) { + return; + } + const services = addSuffixToServiceNetworks(composeData.services, suffix); + const actualComposeData = { ...composeData, services }; - // Caso 1: ListOfStrings - expect(actualComposeData.services?.web?.networks).toContain( - `frontend-${suffix}`, - ); - expect(actualComposeData.services?.web?.networks).toContain( - `backend-${suffix}`, - ); + // Caso 1: ListOfStrings + expect(actualComposeData.services?.web?.networks).toContain( + `frontend-${suffix}`, + ); + expect(actualComposeData.services?.web?.networks).toContain( + `backend-${suffix}`, + ); - // Caso 2: Objeto con aliases - const apiNetworks = actualComposeData.services?.api?.networks as { - [key: string]: unknown; - }; - expect(apiNetworks).toHaveProperty(`frontend-${suffix}`); - expect(apiNetworks[`frontend-${suffix}`]).toBeDefined(); - expect(apiNetworks).not.toHaveProperty("frontend"); + // Caso 2: Objeto con aliases + const apiNetworks = actualComposeData.services?.api?.networks as { + [key: string]: unknown; + }; + expect(apiNetworks).toHaveProperty(`frontend-${suffix}`); + expect(apiNetworks[`frontend-${suffix}`]).toBeDefined(); + expect(apiNetworks).not.toHaveProperty("frontend"); - // Caso 3: Objeto con redes simples - const redisNetworks = actualComposeData.services?.redis?.networks; - expect(redisNetworks).toHaveProperty(`backend-${suffix}`); - expect(redisNetworks).not.toHaveProperty("backend"); + // Caso 3: Objeto con redes simples + const redisNetworks = actualComposeData.services?.redis?.networks; + expect(redisNetworks).toHaveProperty(`backend-${suffix}`); + expect(redisNetworks).not.toHaveProperty("backend"); }); const composeFile7 = ` @@ -195,19 +195,19 @@ services: - dokploy-network `; -test("It shoudn't add suffix to dokploy-network in services", () => { - const composeData = parse(composeFile7) as ComposeSpecification; +test("It shouldn't add suffix to dokploy-network in services", () => { + const composeData = parse(composeFile7) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const networks = addSuffixToServiceNetworks(composeData.services, suffix); - const service = networks.web; + if (!composeData?.services) { + return; + } + const networks = addSuffixToServiceNetworks(composeData.services, suffix); + const service = networks.web; - expect(service).toBeDefined(); - expect(service?.networks).toContain("dokploy-network"); + expect(service).toBeDefined(); + expect(service?.networks).toContain("dokploy-network"); }); const composeFile8 = ` @@ -241,35 +241,35 @@ services: dokploy-network: aliases: - apid - + `; -test("It shoudn't add suffix to dokploy-network in services multiples cases", () => { - const composeData = parse(composeFile8) as ComposeSpecification; +test("It shouldn't add suffix to dokploy-network in services multiples cases", () => { + const composeData = parse(composeFile8) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const networks = addSuffixToServiceNetworks(composeData.services, suffix); - const service = networks.web; - const api = networks.api; - const redis = networks.redis; - const db = networks.db; + if (!composeData?.services) { + return; + } + const networks = addSuffixToServiceNetworks(composeData.services, suffix); + const service = networks.web; + const api = networks.api; + const redis = networks.redis; + const db = networks.db; - const dbNetworks = db?.networks as { - [key: string]: unknown; - }; + const dbNetworks = db?.networks as { + [key: string]: unknown; + }; - const apiNetworks = api?.networks as { - [key: string]: unknown; - }; + const apiNetworks = api?.networks as { + [key: string]: unknown; + }; - expect(service).toBeDefined(); - expect(service?.networks).toContain("dokploy-network"); + expect(service).toBeDefined(); + expect(service?.networks).toContain("dokploy-network"); - expect(redis?.networks).toHaveProperty("dokploy-network"); - expect(dbNetworks["dokploy-network"]).toBeDefined(); - expect(apiNetworks["dokploy-network"]).toBeDefined(); + expect(redis?.networks).toHaveProperty("dokploy-network"); + expect(dbNetworks["dokploy-network"]).toBeDefined(); + expect(apiNetworks["dokploy-network"]).toBeDefined(); }); diff --git a/apps/dokploy/__test__/compose/service/sevice-volumes-from.test.ts b/apps/dokploy/__test__/compose/service/service-volumes-from.test.ts similarity index 100% rename from apps/dokploy/__test__/compose/service/sevice-volumes-from.test.ts rename to apps/dokploy/__test__/compose/service/service-volumes-from.test.ts diff --git a/apps/dokploy/__test__/env/stack-environment.test.ts b/apps/dokploy/__test__/env/stack-environment.test.ts index 13f5adb53..cde7be9db 100644 --- a/apps/dokploy/__test__/env/stack-environment.test.ts +++ b/apps/dokploy/__test__/env/stack-environment.test.ts @@ -1,4 +1,4 @@ -import { getEnviromentVariablesObject } from "@dokploy/server/index"; +import { getEnvironmentVariablesObject } from "@dokploy/server/index"; import { describe, expect, it } from "vitest"; const projectEnv = ` @@ -15,29 +15,29 @@ DATABASE_NAME=dev_database SECRET_KEY=env-secret-123 `; -describe("getEnviromentVariablesObject with environment variables (Stack compose)", () => { - it("resolves environment variables correctly for Stack compose", () => { - const serviceEnv = ` +describe("getEnvironmentVariablesObject with environment variables (Stack compose)", () => { + it("resolves environment variables correctly for Stack compose", () => { + const serviceEnv = ` FOO=\${{environment.NODE_ENV}} BAR=\${{environment.API_URL}} BAZ=test `; - const result = getEnviromentVariablesObject( - serviceEnv, - projectEnv, - environmentEnv, - ); + const result = getEnvironmentVariablesObject( + serviceEnv, + projectEnv, + environmentEnv, + ); - expect(result).toEqual({ - FOO: "development", - BAR: "https://api.dev.example.com", - BAZ: "test", - }); - }); + expect(result).toEqual({ + FOO: "development", + BAR: "https://api.dev.example.com", + BAZ: "test", + }); + }); - it("resolves both project and environment variables for Stack compose", () => { - const serviceEnv = ` + it("resolves both project and environment variables for Stack compose", () => { + const serviceEnv = ` ENVIRONMENT=\${{project.ENVIRONMENT}} NODE_ENV=\${{environment.NODE_ENV}} API_URL=\${{environment.API_URL}} @@ -45,140 +45,140 @@ DATABASE_URL=\${{project.DATABASE_URL}} SERVICE_PORT=4000 `; - const result = getEnviromentVariablesObject( - serviceEnv, - projectEnv, - environmentEnv, - ); + const result = getEnvironmentVariablesObject( + serviceEnv, + projectEnv, + environmentEnv, + ); - expect(result).toEqual({ - ENVIRONMENT: "staging", - NODE_ENV: "development", - API_URL: "https://api.dev.example.com", - DATABASE_URL: "postgres://postgres:postgres@localhost:5432/project_db", - SERVICE_PORT: "4000", - }); - }); + expect(result).toEqual({ + ENVIRONMENT: "staging", + NODE_ENV: "development", + API_URL: "https://api.dev.example.com", + DATABASE_URL: "postgres://postgres:postgres@localhost:5432/project_db", + SERVICE_PORT: "4000", + }); + }); - it("handles multiple environment references in single value for Stack compose", () => { - const multiRefEnv = ` + it("handles multiple environment references in single value for Stack compose", () => { + const multiRefEnv = ` HOST=localhost PORT=5432 USERNAME=postgres PASSWORD=secret123 `; - const serviceEnv = ` + const serviceEnv = ` DATABASE_URL=postgresql://\${{environment.USERNAME}}:\${{environment.PASSWORD}}@\${{environment.HOST}}:\${{environment.PORT}}/mydb `; - const result = getEnviromentVariablesObject(serviceEnv, "", multiRefEnv); + const result = getEnvironmentVariablesObject(serviceEnv, "", multiRefEnv); - expect(result).toEqual({ - DATABASE_URL: "postgresql://postgres:secret123@localhost:5432/mydb", - }); - }); + expect(result).toEqual({ + DATABASE_URL: "postgresql://postgres:secret123@localhost:5432/mydb", + }); + }); - it("throws error for undefined environment variables in Stack compose", () => { - const serviceWithUndefined = ` + it("throws error for undefined environment variables in Stack compose", () => { + const serviceWithUndefined = ` UNDEFINED_VAR=\${{environment.UNDEFINED_VAR}} `; - expect(() => - getEnviromentVariablesObject(serviceWithUndefined, "", environmentEnv), - ).toThrow("Invalid environment variable: environment.UNDEFINED_VAR"); - }); + expect(() => + getEnvironmentVariablesObject(serviceWithUndefined, "", environmentEnv), + ).toThrow("Invalid environment variable: environment.UNDEFINED_VAR"); + }); - it("allows service variables to override environment variables in Stack compose", () => { - const serviceOverrideEnv = ` + it("allows service variables to override environment variables in Stack compose", () => { + const serviceOverrideEnv = ` NODE_ENV=production API_URL=\${{environment.API_URL}} `; - const result = getEnviromentVariablesObject( - serviceOverrideEnv, - "", - environmentEnv, - ); + const result = getEnvironmentVariablesObject( + serviceOverrideEnv, + "", + environmentEnv, + ); - expect(result).toEqual({ - NODE_ENV: "production", - API_URL: "https://api.dev.example.com", - }); - }); + expect(result).toEqual({ + NODE_ENV: "production", + API_URL: "https://api.dev.example.com", + }); + }); - it("resolves complex references with project, environment, and service variables for Stack compose", () => { - const complexServiceEnv = ` + it("resolves complex references with project, environment, and service variables for Stack compose", () => { + const complexServiceEnv = ` FULL_DATABASE_URL=\${{project.DATABASE_URL}}/\${{environment.DATABASE_NAME}} API_ENDPOINT=\${{environment.API_URL}}/\${{project.ENVIRONMENT}}/api SERVICE_NAME=my-service COMPLEX_VAR=\${{SERVICE_NAME}}-\${{environment.NODE_ENV}}-\${{project.ENVIRONMENT}} `; - const result = getEnviromentVariablesObject( - complexServiceEnv, - projectEnv, - environmentEnv, - ); + const result = getEnvironmentVariablesObject( + complexServiceEnv, + projectEnv, + environmentEnv, + ); - expect(result).toEqual({ - FULL_DATABASE_URL: - "postgres://postgres:postgres@localhost:5432/project_db/dev_database", - API_ENDPOINT: "https://api.dev.example.com/staging/api", - SERVICE_NAME: "my-service", - COMPLEX_VAR: "my-service-development-staging", - }); - }); + expect(result).toEqual({ + FULL_DATABASE_URL: + "postgres://postgres:postgres@localhost:5432/project_db/dev_database", + API_ENDPOINT: "https://api.dev.example.com/staging/api", + SERVICE_NAME: "my-service", + COMPLEX_VAR: "my-service-development-staging", + }); + }); - it("maintains precedence: service > environment > project in Stack compose", () => { - const conflictingProjectEnv = ` + it("maintains precedence: service > environment > project in Stack compose", () => { + const conflictingProjectEnv = ` NODE_ENV=production-project API_URL=https://project.api.com DATABASE_NAME=project_db `; - const conflictingEnvironmentEnv = ` + const conflictingEnvironmentEnv = ` NODE_ENV=development-environment API_URL=https://environment.api.com DATABASE_NAME=env_db `; - const serviceWithConflicts = ` + const serviceWithConflicts = ` NODE_ENV=service-override PROJECT_ENV=\${{project.NODE_ENV}} ENV_VAR=\${{environment.API_URL}} DB_NAME=\${{environment.DATABASE_NAME}} `; - const result = getEnviromentVariablesObject( - serviceWithConflicts, - conflictingProjectEnv, - conflictingEnvironmentEnv, - ); + const result = getEnvironmentVariablesObject( + serviceWithConflicts, + conflictingProjectEnv, + conflictingEnvironmentEnv, + ); - expect(result).toEqual({ - NODE_ENV: "service-override", - PROJECT_ENV: "production-project", - ENV_VAR: "https://environment.api.com", - DB_NAME: "env_db", - }); - }); + expect(result).toEqual({ + NODE_ENV: "service-override", + PROJECT_ENV: "production-project", + ENV_VAR: "https://environment.api.com", + DB_NAME: "env_db", + }); + }); - it("handles empty environment variables in Stack compose", () => { - const serviceWithEmpty = ` + it("handles empty environment variables in Stack compose", () => { + const serviceWithEmpty = ` SERVICE_VAR=test PROJECT_VAR=\${{project.ENVIRONMENT}} `; - const result = getEnviromentVariablesObject( - serviceWithEmpty, - projectEnv, - "", - ); + const result = getEnvironmentVariablesObject( + serviceWithEmpty, + projectEnv, + "", + ); - expect(result).toEqual({ - SERVICE_VAR: "test", - PROJECT_VAR: "staging", - }); - }); + expect(result).toEqual({ + SERVICE_VAR: "test", + PROJECT_VAR: "staging", + }); + }); }); diff --git a/apps/dokploy/components/dashboard/application/advanced/redirects/handle-redirect.tsx b/apps/dokploy/components/dashboard/application/advanced/redirects/handle-redirect.tsx index 172c042f1..603a6d6c8 100644 --- a/apps/dokploy/components/dashboard/application/advanced/redirects/handle-redirect.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/redirects/handle-redirect.tsx @@ -149,7 +149,7 @@ export const HandleRedirect = ({ const onDialogToggle = (open: boolean) => { setIsOpen(open); - // commented for the moment because not reseting the form if accidentally closed the dialog can be considered as a feature instead of a bug + // commented for the moment because not resetting the form if accidentally closed the dialog can be considered as a feature instead of a bug // setPresetSelected(""); // form.reset(); }; diff --git a/apps/dokploy/components/dashboard/application/environment/show-enviroment.tsx b/apps/dokploy/components/dashboard/application/environment/show-environment.tsx similarity index 100% rename from apps/dokploy/components/dashboard/application/environment/show-enviroment.tsx rename to apps/dokploy/components/dashboard/application/environment/show-environment.tsx diff --git a/apps/dokploy/components/dashboard/application/logs/show.tsx b/apps/dokploy/components/dashboard/application/logs/show.tsx index cbb6bce09..06b257766 100644 --- a/apps/dokploy/components/dashboard/application/logs/show.tsx +++ b/apps/dokploy/components/dashboard/application/logs/show.tsx @@ -91,7 +91,7 @@ export const ShowDockerLogs = ({ appName, serverId }: Props) => { }, [option, services, containers]); const isLoading = option === "native" ? containersLoading : servicesLoading; - const containersLenght = + const containersLength = option === "native" ? containers?.length : services?.length; return ( @@ -167,7 +167,7 @@ export const ShowDockerLogs = ({ appName, serverId }: Props) => { )} - Containers ({containersLenght}) + Containers ({containersLength}) diff --git a/apps/dokploy/components/dashboard/compose/logs/show-stack.tsx b/apps/dokploy/components/dashboard/compose/logs/show-stack.tsx index 159ab3485..4c3067b15 100644 --- a/apps/dokploy/components/dashboard/compose/logs/show-stack.tsx +++ b/apps/dokploy/components/dashboard/compose/logs/show-stack.tsx @@ -77,7 +77,7 @@ export const ShowDockerLogsStack = ({ appName, serverId }: Props) => { }, [option, services, containers]); const isLoading = option === "native" ? containersLoading : servicesLoading; - const containersLenght = + const containersLength = option === "native" ? containers?.length : services?.length; return ( @@ -152,7 +152,7 @@ export const ShowDockerLogsStack = ({ appName, serverId }: Props) => { )} - Containers ({containersLenght}) + Containers ({containersLength}) diff --git a/apps/dokploy/components/dashboard/database/backups/restore-backup.tsx b/apps/dokploy/components/dashboard/database/backups/restore-backup.tsx index 00647aea7..7b212acb9 100644 --- a/apps/dokploy/components/dashboard/database/backups/restore-backup.tsx +++ b/apps/dokploy/components/dashboard/database/backups/restore-backup.tsx @@ -225,7 +225,7 @@ export const RestoreBackup = ({ resolver: zodResolver(RestoreBackupSchema), }); - const destionationId = form.watch("destinationId"); + const destinationId = form.watch("destinationId"); const currentDatabaseType = form.watch("databaseType"); const metadata = form.watch("metadata"); @@ -240,12 +240,12 @@ export const RestoreBackup = ({ const { data: files = [], isPending } = api.backup.listBackupFiles.useQuery( { - destinationId: destionationId, + destinationId: destinationId, search: debouncedSearchTerm, serverId: serverId ?? "", }, { - enabled: isOpen && !!destionationId, + enabled: isOpen && !!destinationId, }, ); diff --git a/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx b/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx index 9d4f47c4a..bed5c6f5d 100644 --- a/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx +++ b/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx @@ -103,7 +103,7 @@ export function TerminalLine({ log, noTimestamp, searchTerm }: LogLineProps) { > {" "}
- {/* Icon to expand the log item maybe implement a colapsible later */} + {/* Icon to expand the log item maybe implement a collapsible later */} {/* */} {tooltip(color, rawTimestamp)} {!noTimestamp && ( diff --git a/apps/dokploy/components/dashboard/docker/show/colums.tsx b/apps/dokploy/components/dashboard/docker/show/columns.tsx similarity index 100% rename from apps/dokploy/components/dashboard/docker/show/colums.tsx rename to apps/dokploy/components/dashboard/docker/show/columns.tsx diff --git a/apps/dokploy/components/dashboard/docker/show/show-containers.tsx b/apps/dokploy/components/dashboard/docker/show/show-containers.tsx index 69b0a0da2..8a19566e8 100644 --- a/apps/dokploy/components/dashboard/docker/show/show-containers.tsx +++ b/apps/dokploy/components/dashboard/docker/show/show-containers.tsx @@ -35,7 +35,7 @@ import { TableRow, } from "@/components/ui/table"; import { api, type RouterOutputs } from "@/utils/api"; -import { columns } from "./colums"; +import { columns } from "./columns"; export type Container = NonNullable< RouterOutputs["docker"]["getContainers"] >[0]; diff --git a/apps/dokploy/components/dashboard/settings/servers/setup-server.tsx b/apps/dokploy/components/dashboard/settings/servers/setup-server.tsx index 0d4d3a44f..570955fc8 100644 --- a/apps/dokploy/components/dashboard/settings/servers/setup-server.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/setup-server.tsx @@ -161,7 +161,7 @@ export const SetupServer = ({ serverId, asButton = false }: Props) => {
  • 1. Add the public SSH Key when you create a server in your - preffered provider (Hostinger, Digital Ocean, Hetzner, + preferred provider (Hostinger, Digital Ocean, Hetzner, etc){" "}
  • 2. Add The SSH Key to Server Manually
  • diff --git a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx index 859098394..7342aafb4 100644 --- a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx @@ -48,7 +48,7 @@ import { ShowMonitoringModal } from "./show-monitoring-modal"; import { ShowSchedulesModal } from "./show-schedules-modal"; import { ShowSwarmOverviewModal } from "./show-swarm-overview-modal"; import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal"; -import { WelcomeSuscription } from "./welcome-stripe/welcome-suscription"; +import { Welcomesubscription } from "./welcome-stripe/welcome-subscription"; export const ShowServers = () => { const router = useRouter(); @@ -63,7 +63,7 @@ export const ShowServers = () => { return (
    - {query?.success && isCloud && } + {query?.success && isCloud && }
    diff --git a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-suscription.tsx b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-subscription.tsx similarity index 99% rename from apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-suscription.tsx rename to apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-subscription.tsx index 004f79f74..295b53516 100644 --- a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-suscription.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-subscription.tsx @@ -51,7 +51,7 @@ export const { useStepper, steps, Scoped } = defineStepper( { id: "complete", title: "Complete", description: "Checkout complete" }, ); -export const WelcomeSuscription = () => { +export const Welcomesubscription = () => { const [showConfetti, setShowConfetti] = useState(false); const stepper = useStepper(); const [isOpen, setIsOpen] = useState(true); diff --git a/apps/dokploy/components/ui/file-tree.tsx b/apps/dokploy/components/ui/file-tree.tsx index e346bf4a6..c1d5dc335 100644 --- a/apps/dokploy/components/ui/file-tree.tsx +++ b/apps/dokploy/components/ui/file-tree.tsx @@ -19,7 +19,7 @@ interface TreeDataItem { type TreeProps = React.HTMLAttributes & { data: TreeDataItem[] | TreeDataItem; - initialSlelectedItemId?: string; + initialSelectedItemId?: string; onSelectChange?: (item: TreeDataItem | undefined) => void; expandAll?: boolean; folderIcon?: LucideIcon; @@ -30,7 +30,7 @@ const Tree = React.forwardRef( ( { data, - initialSlelectedItemId, + initialSelectedItemId, onSelectChange, expandAll, folderIcon, @@ -42,7 +42,7 @@ const Tree = React.forwardRef( ) => { const [selectedItemId, setSelectedItemId] = React.useState< string | undefined - >(initialSlelectedItemId); + >(initialSelectedItemId); const handleSelectChange = React.useCallback( (item: TreeDataItem | undefined) => { @@ -55,7 +55,7 @@ const Tree = React.forwardRef( ); const expandedItemIds = React.useMemo(() => { - if (!initialSlelectedItemId) { + if (!initialSelectedItemId) { return [] as string[]; } @@ -81,9 +81,9 @@ const Tree = React.forwardRef( } } - walkTreeItems(data, initialSlelectedItemId); + walkTreeItems(data, initialSelectedItemId); return ids; - }, [data, initialSlelectedItemId]); + }, [data, initialSelectedItemId]); const { ref: refRoot } = useResizeObserver(); diff --git a/apps/dokploy/pages/api/deploy/[refreshToken].ts b/apps/dokploy/pages/api/deploy/[refreshToken].ts index 14b45f3d7..1c57731a7 100644 --- a/apps/dokploy/pages/api/deploy/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/[refreshToken].ts @@ -196,7 +196,7 @@ export default async function handler( return; } - const commitedPaths = await extractCommitedPaths( + const committedPaths = await extractCommittedPaths( req.body, application.bitbucket, application.bitbucketRepositorySlug || @@ -206,7 +206,7 @@ export default async function handler( const shouldDeployPaths = shouldDeploy( application.watchPaths, - commitedPaths, + committedPaths, ); if (!shouldDeployPaths) { @@ -538,7 +538,7 @@ export const getProviderByHeader = (headers: any) => { return null; }; -export const extractCommitedPaths = async ( +export const extractCommittedPaths = async ( body: any, bitbucket: Bitbucket | null, repository: string, @@ -548,7 +548,7 @@ export const extractCommitedPaths = async ( const commitHashes = changes .map((change: any) => change.new?.target?.hash) .filter(Boolean); - const commitedPaths: string[] = []; + const committedPaths: string[] = []; const username = bitbucket?.bitbucketWorkspaceName || bitbucket?.bitbucketUsername || ""; for (const commit of commitHashes) { @@ -559,7 +559,7 @@ export const extractCommitedPaths = async ( }); const data = await response.json(); for (const value of data.values) { - if (value?.new?.path) commitedPaths.push(value.new.path); + if (value?.new?.path) committedPaths.push(value.new.path); } } catch (error) { console.error( @@ -571,5 +571,5 @@ export const extractCommitedPaths = async ( } } - return commitedPaths; + return committedPaths; }; diff --git a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts index da3082bb7..c998e83b9 100644 --- a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts @@ -8,7 +8,7 @@ import { myQueue } from "@/server/queues/queueSetup"; import { deploy } from "@/server/utils/deploy"; import { extractBranchName, - extractCommitedPaths, + extractCommittedPaths, extractCommitMessage, extractHash, getProviderByHeader, @@ -97,7 +97,7 @@ export default async function handler( return; } - const commitedPaths = await extractCommitedPaths( + const committedPaths = await extractCommittedPaths( req.body, composeResult.bitbucket, composeResult.bitbucketRepositorySlug || @@ -107,7 +107,7 @@ export default async function handler( const shouldDeployPaths = shouldDeploy( composeResult.watchPaths, - commitedPaths, + committedPaths, ); if (!shouldDeployPaths) { diff --git a/apps/dokploy/pages/api/stripe/webhook.ts b/apps/dokploy/pages/api/stripe/webhook.ts index 60468bd2c..deaa5572c 100644 --- a/apps/dokploy/pages/api/stripe/webhook.ts +++ b/apps/dokploy/pages/api/stripe/webhook.ts @@ -174,27 +174,27 @@ export default async function handler( case "invoice.payment_succeeded": { const newInvoice = event.data.object as Stripe.Invoice; - const suscription = await stripe.subscriptions.retrieve( + const subscription = await stripe.subscriptions.retrieve( newInvoice.subscription as string, ); - if (suscription.status !== "active") { + if (subscription.status !== "active") { console.log( - `Skipping invoice.payment_succeeded for subscription ${suscription.id} with status ${suscription.status}`, + `Skipping invoice.payment_succeeded for subscription ${subscription.id} with status ${subscription.status}`, ); break; } const serversQuantity = getSubscriptionServersQuantity( - suscription?.items?.data ?? [], + subscription?.items?.data ?? [], ); await db .update(user) .set({ serversQuantity }) - .where(eq(user.stripeCustomerId, suscription.customer as string)); + .where(eq(user.stripeCustomerId, subscription.customer as string)); const admin = await findUserByStripeCustomerId( - suscription.customer as string, + subscription.customer as string, ); if (!admin) { diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/compose/[composeId].tsx index 078bf5b6b..781dd7795 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/compose/[composeId].tsx @@ -16,7 +16,7 @@ import { ShowImport } from "@/components/dashboard/application/advanced/import/s import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes"; import { ShowDeployments } from "@/components/dashboard/application/deployments/show-deployments"; import { ShowDomains } from "@/components/dashboard/application/domains/show-domains"; -import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment"; +import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowPatches } from "@/components/dashboard/application/patches/show-patches"; import { ShowSchedules } from "@/components/dashboard/application/schedules/show-schedules"; import { ShowVolumeBackups } from "@/components/dashboard/application/volume-backups/show-volume-backups"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/libsql/[libsqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/libsql/[libsqlId].tsx index 6abb53c2b..c9563ebe6 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/libsql/[libsqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/libsql/[libsqlId].tsx @@ -10,7 +10,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { type ReactElement, useState } from "react"; import superjson from "superjson"; -import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment"; +import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { ShowBackups } from "@/components/dashboard/database/backups/show-backups"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mariadb/[mariadbId].tsx index 3e3a7d7de..b54804279 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mariadb/[mariadbId].tsx @@ -10,7 +10,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { type ReactElement, useState } from "react"; import superjson from "superjson"; -import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment"; +import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { ShowBackups } from "@/components/dashboard/database/backups/show-backups"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mongo/[mongoId].tsx index ea6483499..402718625 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mongo/[mongoId].tsx @@ -10,7 +10,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { type ReactElement, useState } from "react"; import superjson from "superjson"; -import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment"; +import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { ShowBackups } from "@/components/dashboard/database/backups/show-backups"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mysql/[mysqlId].tsx index ff45c0694..55e1ee6e0 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/mysql/[mysqlId].tsx @@ -10,7 +10,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { type ReactElement, useState } from "react"; import superjson from "superjson"; -import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment"; +import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { ShowBackups } from "@/components/dashboard/database/backups/show-backups"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/postgres/[postgresId].tsx index 15e91a0bd..f73ce35cb 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/postgres/[postgresId].tsx @@ -10,7 +10,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { type ReactElement, useState } from "react"; import superjson from "superjson"; -import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment"; +import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { ShowBackups } from "@/components/dashboard/database/backups/show-backups"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/redis/[redisId].tsx index 05a9e0c91..8847ed891 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/environment/[environmentId]/services/redis/[redisId].tsx @@ -10,7 +10,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { type ReactElement, useState } from "react"; import superjson from "superjson"; -import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment"; +import { ShowEnvironment } from "@/components/dashboard/application/environment/show-environment"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { DeleteService } from "@/components/dashboard/compose/delete-service"; import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring"; diff --git a/apps/dokploy/server/api/routers/destination.ts b/apps/dokploy/server/api/routers/destination.ts index 9f528c16c..cf7395a3f 100644 --- a/apps/dokploy/server/api/routers/destination.ts +++ b/apps/dokploy/server/api/routers/destination.ts @@ -1,5 +1,5 @@ import { - createDestintation, + createDestination, execAsync, execAsyncRemote, findDestinationById, @@ -25,7 +25,7 @@ export const destinationRouter = createTRPCRouter({ .input(apiCreateDestination) .mutation(async ({ input, ctx }) => { try { - const result = await createDestintation( + const result = await createDestination( input, ctx.session.activeOrganizationId, ); diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 22e8872bd..e6fd0ba59 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -121,7 +121,7 @@ export * from "./utils/providers/raw"; export * from "./utils/schedules/index"; export * from "./utils/schedules/utils"; export * from "./utils/servers/remote-docker"; -export * from "./utils/startup/cancell-deployments"; +export * from "./utils/startup/cancel-deployments"; export * from "./utils/tracking/hubspot"; export * from "./utils/traefik/application"; export * from "./utils/traefik/domain"; diff --git a/packages/server/src/services/deployment.ts b/packages/server/src/services/deployment.ts index a9f059465..7b6f0c730 100644 --- a/packages/server/src/services/deployment.ts +++ b/packages/server/src/services/deployment.ts @@ -177,7 +177,7 @@ export const createDeployment = async ( status: "error", logPath: "", description: deployment.description || "", - errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`, + errorMessage: `An error have occurred: ${error instanceof Error ? error.message : error}`, startedAt: new Date().toISOString(), finishedAt: new Date().toISOString(), }) @@ -257,7 +257,7 @@ export const createDeploymentPreview = async ( status: "error", logPath: "", description: deployment.description || "", - errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`, + errorMessage: `An error have occurred: ${error instanceof Error ? error.message : error}`, startedAt: new Date().toISOString(), finishedAt: new Date().toISOString(), }) @@ -334,7 +334,7 @@ echo "Initializing deployment\n" >> ${logFilePath}; status: "error", logPath: "", description: deployment.description || "", - errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`, + errorMessage: `An error have occurred: ${error instanceof Error ? error.message : error}`, startedAt: new Date().toISOString(), finishedAt: new Date().toISOString(), }) @@ -418,7 +418,7 @@ echo "Initializing backup\n" >> ${logFilePath}; status: "error", logPath: "", description: deployment.description || "", - errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`, + errorMessage: `An error have occurred: ${error instanceof Error ? error.message : error}`, startedAt: new Date().toISOString(), finishedAt: new Date().toISOString(), }) @@ -493,7 +493,7 @@ export const createDeploymentSchedule = async ( status: "error", logPath: "", description: deployment.description || "", - errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`, + errorMessage: `An error have occurred: ${error instanceof Error ? error.message : error}`, startedAt: new Date().toISOString(), finishedAt: new Date().toISOString(), }) @@ -578,7 +578,7 @@ export const createDeploymentVolumeBackup = async ( status: "error", logPath: "", description: deployment.description || "", - errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`, + errorMessage: `An error have occurred: ${error instanceof Error ? error.message : error}`, startedAt: new Date().toISOString(), finishedAt: new Date().toISOString(), }) diff --git a/packages/server/src/services/destination.ts b/packages/server/src/services/destination.ts index fa48d0d15..9cbc9afa3 100644 --- a/packages/server/src/services/destination.ts +++ b/packages/server/src/services/destination.ts @@ -9,7 +9,7 @@ import type { z } from "zod"; export type Destination = typeof destinations.$inferSelect; -export const createDestintation = async ( +export const createDestination = async ( input: z.infer, organizationId: string, ) => { diff --git a/packages/server/src/services/settings.ts b/packages/server/src/services/settings.ts index 07aaf690c..ecfb7f6de 100644 --- a/packages/server/src/services/settings.ts +++ b/packages/server/src/services/settings.ts @@ -383,12 +383,12 @@ export const readPorts = async ( const seenPorts = new Set(); for (const key in parsedResult) { if (Object.hasOwn(parsedResult, key)) { - const containerPortMapppings = parsedResult[key]; + const containerPortMappings = parsedResult[key]; const protocol = key.split("/")[1]; const targetPort = Number.parseInt(key.split("/")[0] ?? "0", 10); // Take only the first mapping to avoid duplicates (IPv4 and IPv6) - const firstMapping = containerPortMapppings[0]; + const firstMapping = containerPortMappings[0]; if (firstMapping) { const publishedPort = Number.parseInt(firstMapping.HostPort, 10); const portKey = `${targetPort}-${publishedPort}-${protocol}`; diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index 83287a3be..5e66c6f2c 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -7,452 +7,452 @@ import { auth } from "../lib/auth"; export type User = typeof user.$inferSelect; export const addNewProject = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const userR = await findMemberById(userId, organizationId); + const userR = await findMemberById(userId, organizationId); - await db - .update(member) - .set({ - accessedProjects: [...userR.accessedProjects, projectId], - }) - .where( - and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), - ); + await db + .update(member) + .set({ + accessedProjects: [...userR.accessedProjects, projectId], + }) + .where( + and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), + ); }; export const addNewEnvironment = async ( - userId: string, - environmentId: string, - organizationId: string, + userId: string, + environmentId: string, + organizationId: string, ) => { - const userR = await findMemberById(userId, organizationId); + const userR = await findMemberById(userId, organizationId); - await db - .update(member) - .set({ - accessedEnvironments: [...userR.accessedEnvironments, environmentId], - }) - .where( - and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), - ); + await db + .update(member) + .set({ + accessedEnvironments: [...userR.accessedEnvironments, environmentId], + }) + .where( + and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), + ); }; export const addNewService = async ( - userId: string, - serviceId: string, - organizationId: string, + userId: string, + serviceId: string, + organizationId: string, ) => { - const userR = await findMemberById(userId, organizationId); - await db - .update(member) - .set({ - accessedServices: [...userR.accessedServices, serviceId], - }) - .where( - and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), - ); + const userR = await findMemberById(userId, organizationId); + await db + .update(member) + .set({ + accessedServices: [...userR.accessedServices, serviceId], + }) + .where( + and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), + ); }; export const canPerformCreationService = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const { accessedProjects, canCreateServices } = await findMemberById( - userId, - organizationId, - ); - const haveAccessToProject = accessedProjects.includes(projectId); + const { accessedProjects, canCreateServices } = await findMemberById( + userId, + organizationId, + ); + const haveAccessToProject = accessedProjects.includes(projectId); - if (canCreateServices && haveAccessToProject) { - return true; - } + if (canCreateServices && haveAccessToProject) { + return true; + } - return false; + return false; }; export const canPerformAccessService = async ( - userId: string, - serviceId: string, - organizationId: string, + userId: string, + serviceId: string, + organizationId: string, ) => { - const { accessedServices } = await findMemberById(userId, organizationId); - const haveAccessToService = accessedServices.includes(serviceId); + const { accessedServices } = await findMemberById(userId, organizationId); + const haveAccessToService = accessedServices.includes(serviceId); - if (haveAccessToService) { - return true; - } + if (haveAccessToService) { + return true; + } - return false; + return false; }; -export const canPeformDeleteService = async ( - userId: string, - serviceId: string, - organizationId: string, +export const canPerformDeleteService = async ( + userId: string, + serviceId: string, + organizationId: string, ) => { - const { accessedServices, canDeleteServices } = await findMemberById( - userId, - organizationId, - ); - const haveAccessToService = accessedServices.includes(serviceId); + const { accessedServices, canDeleteServices } = await findMemberById( + userId, + organizationId, + ); + const haveAccessToService = accessedServices.includes(serviceId); - if (canDeleteServices && haveAccessToService) { - return true; - } + if (canDeleteServices && haveAccessToService) { + return true; + } - return false; + return false; }; export const canPerformCreationProject = async ( - userId: string, - organizationId: string, + userId: string, + organizationId: string, ) => { - const { canCreateProjects } = await findMemberById(userId, organizationId); + const { canCreateProjects } = await findMemberById(userId, organizationId); - if (canCreateProjects) { - return true; - } + if (canCreateProjects) { + return true; + } - return false; + return false; }; export const canPerformDeleteProject = async ( - userId: string, - organizationId: string, + userId: string, + organizationId: string, ) => { - const { canDeleteProjects } = await findMemberById(userId, organizationId); + const { canDeleteProjects } = await findMemberById(userId, organizationId); - if (canDeleteProjects) { - return true; - } + if (canDeleteProjects) { + return true; + } - return false; + return false; }; export const canPerformAccessProject = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const { accessedProjects } = await findMemberById(userId, organizationId); + const { accessedProjects } = await findMemberById(userId, organizationId); - const haveAccessToProject = accessedProjects.includes(projectId); + const haveAccessToProject = accessedProjects.includes(projectId); - if (haveAccessToProject) { - return true; - } - return false; + if (haveAccessToProject) { + return true; + } + return false; }; export const canPerformAccessEnvironment = async ( - userId: string, - environmentId: string, - organizationId: string, + userId: string, + environmentId: string, + organizationId: string, ) => { - const { accessedEnvironments } = await findMemberById(userId, organizationId); - const haveAccessToEnvironment = accessedEnvironments.includes(environmentId); + const { accessedEnvironments } = await findMemberById(userId, organizationId); + const haveAccessToEnvironment = accessedEnvironments.includes(environmentId); - if (haveAccessToEnvironment) { - return true; - } + if (haveAccessToEnvironment) { + return true; + } - return false; + return false; }; export const canPerformDeleteEnvironment = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const { accessedProjects, canDeleteEnvironments } = await findMemberById( - userId, - organizationId, - ); - const haveAccessToProject = accessedProjects.includes(projectId); + const { accessedProjects, canDeleteEnvironments } = await findMemberById( + userId, + organizationId, + ); + const haveAccessToProject = accessedProjects.includes(projectId); - if (canDeleteEnvironments && haveAccessToProject) { - return true; - } + if (canDeleteEnvironments && haveAccessToProject) { + return true; + } - return false; + return false; }; export const canAccessToTraefikFiles = async ( - userId: string, - organizationId: string, + userId: string, + organizationId: string, ) => { - const { canAccessToTraefikFiles } = await findMemberById( - userId, - organizationId, - ); - return canAccessToTraefikFiles; + const { canAccessToTraefikFiles } = await findMemberById( + userId, + organizationId, + ); + return canAccessToTraefikFiles; }; export const checkServiceAccess = async ( - userId: string, - serviceId: string, - organizationId: string, - action = "access" as "access" | "create" | "delete", + userId: string, + serviceId: string, + organizationId: string, + action = "access" as "access" | "create" | "delete", ) => { - let hasPermission = false; - switch (action) { - case "create": - hasPermission = await canPerformCreationService( - userId, - serviceId, - organizationId, - ); - break; - case "access": - hasPermission = await canPerformAccessService( - userId, - serviceId, - organizationId, - ); - break; - case "delete": - hasPermission = await canPeformDeleteService( - userId, - serviceId, - organizationId, - ); - break; - default: - hasPermission = false; - } - if (!hasPermission) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "Permission denied", - }); - } + let hasPermission = false; + switch (action) { + case "create": + hasPermission = await canPerformCreationService( + userId, + serviceId, + organizationId, + ); + break; + case "access": + hasPermission = await canPerformAccessService( + userId, + serviceId, + organizationId, + ); + break; + case "delete": + hasPermission = await canPerformDeleteService( + userId, + serviceId, + organizationId, + ); + break; + default: + hasPermission = false; + } + if (!hasPermission) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Permission denied", + }); + } }; export const checkEnvironmentAccess = async ( - userId: string, - environmentId: string, - organizationId: string, - action = "access" as const, + userId: string, + environmentId: string, + organizationId: string, + action = "access" as const, ) => { - let hasPermission = false; - switch (action) { - case "access": - hasPermission = await canPerformAccessEnvironment( - userId, - environmentId, - organizationId, - ); - break; - default: - hasPermission = false; - } - if (!hasPermission) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "Permission denied", - }); - } + let hasPermission = false; + switch (action) { + case "access": + hasPermission = await canPerformAccessEnvironment( + userId, + environmentId, + organizationId, + ); + break; + default: + hasPermission = false; + } + if (!hasPermission) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Permission denied", + }); + } }; export const checkEnvironmentDeletionPermission = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const member = await findMemberById(userId, organizationId); + const member = await findMemberById(userId, organizationId); - if (!member) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "User not found in organization", - }); - } + if (!member) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "User not found in organization", + }); + } - if (member.role === "owner" || member.role === "admin") { - return true; - } + if (member.role === "owner" || member.role === "admin") { + return true; + } - if (!member.canDeleteEnvironments) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You don't have permission to delete environments", - }); - } + if (!member.canDeleteEnvironments) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have permission to delete environments", + }); + } - const hasProjectAccess = member.accessedProjects.includes(projectId); - if (!hasProjectAccess) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You don't have access to this project", - }); - } + const hasProjectAccess = member.accessedProjects.includes(projectId); + if (!hasProjectAccess) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this project", + }); + } - return true; + return true; }; export const checkProjectAccess = async ( - authId: string, - action: "create" | "delete" | "access", - organizationId: string, - projectId?: string, + authId: string, + action: "create" | "delete" | "access", + organizationId: string, + projectId?: string, ) => { - let hasPermission = false; - switch (action) { - case "access": - hasPermission = await canPerformAccessProject( - authId, - projectId as string, - organizationId, - ); - break; - case "create": - hasPermission = await canPerformCreationProject(authId, organizationId); - break; - case "delete": - hasPermission = await canPerformDeleteProject(authId, organizationId); - break; - default: - hasPermission = false; - } - if (!hasPermission) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "Permission denied", - }); - } + let hasPermission = false; + switch (action) { + case "access": + hasPermission = await canPerformAccessProject( + authId, + projectId as string, + organizationId, + ); + break; + case "create": + hasPermission = await canPerformCreationProject(authId, organizationId); + break; + case "delete": + hasPermission = await canPerformDeleteProject(authId, organizationId); + break; + default: + hasPermission = false; + } + if (!hasPermission) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Permission denied", + }); + } }; export const checkEnvironmentCreationPermission = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - // Get user's member record - const member = await findMemberById(userId, organizationId); + // Get user's member record + const member = await findMemberById(userId, organizationId); - if (!member) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "User not found in organization", - }); - } + if (!member) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "User not found in organization", + }); + } - // Owners and admins can always create environments - if (member.role === "owner" || member.role === "admin") { - return true; - } + // Owners and admins can always create environments + if (member.role === "owner" || member.role === "admin") { + return true; + } - // Check if user has canCreateEnvironments permission - if (!member.canCreateEnvironments) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You don't have permission to create environments", - }); - } + // Check if user has canCreateEnvironments permission + if (!member.canCreateEnvironments) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have permission to create environments", + }); + } - // Check if user has access to the project - const hasProjectAccess = member.accessedProjects.includes(projectId); - if (!hasProjectAccess) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You don't have access to this project", - }); - } + // Check if user has access to the project + const hasProjectAccess = member.accessedProjects.includes(projectId); + if (!hasProjectAccess) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this project", + }); + } - return true; + return true; }; export const findMemberById = async ( - userId: string, - organizationId: string, + userId: string, + organizationId: string, ) => { - const result = await db.query.member.findFirst({ - where: and( - eq(member.userId, userId), - eq(member.organizationId, organizationId), - ), - with: { - user: true, - }, - }); + const result = await db.query.member.findFirst({ + where: and( + eq(member.userId, userId), + eq(member.organizationId, organizationId), + ), + with: { + user: true, + }, + }); - if (!result) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "Permission denied", - }); - } - return result; + if (!result) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Permission denied", + }); + } + return result; }; export const updateUser = async (userId: string, userData: Partial) => { - // Validate email if it's being updated - if (userData.email !== undefined) { - if (!userData.email || userData.email.trim() === "") { - throw new Error("Email is required and cannot be empty"); - } + // Validate email if it's being updated + if (userData.email !== undefined) { + if (!userData.email || userData.email.trim() === "") { + throw new Error("Email is required and cannot be empty"); + } - // Basic email format validation - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(userData.email)) { - throw new Error("Please enter a valid email address"); - } - } + // Basic email format validation + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(userData.email)) { + throw new Error("Please enter a valid email address"); + } + } - const userResult = await db - .update(user) - .set({ - ...userData, - }) - .where(eq(user.id, userId)) - .returning() - .then((res) => res[0]); + const userResult = await db + .update(user) + .set({ + ...userData, + }) + .where(eq(user.id, userId)) + .returning() + .then((res) => res[0]); - return userResult; + return userResult; }; export const createApiKey = async ( - userId: string, - input: { - name: string; - prefix?: string; - expiresIn?: number; - metadata: { - organizationId: string; - }; - rateLimitEnabled?: boolean; - rateLimitTimeWindow?: number; - rateLimitMax?: number; - remaining?: number; - refillAmount?: number; - refillInterval?: number; - }, + userId: string, + input: { + name: string; + prefix?: string; + expiresIn?: number; + metadata: { + organizationId: string; + }; + rateLimitEnabled?: boolean; + rateLimitTimeWindow?: number; + rateLimitMax?: number; + remaining?: number; + refillAmount?: number; + refillInterval?: number; + }, ) => { - const result = await auth.createApiKey({ - body: { - name: input.name, - expiresIn: input.expiresIn, - prefix: input.prefix, - rateLimitEnabled: input.rateLimitEnabled, - rateLimitTimeWindow: input.rateLimitTimeWindow, - rateLimitMax: input.rateLimitMax, - remaining: input.remaining, - refillAmount: input.refillAmount, - refillInterval: input.refillInterval, - userId, - }, - }); + const result = await auth.createApiKey({ + body: { + name: input.name, + expiresIn: input.expiresIn, + prefix: input.prefix, + rateLimitEnabled: input.rateLimitEnabled, + rateLimitTimeWindow: input.rateLimitTimeWindow, + rateLimitMax: input.rateLimitMax, + remaining: input.remaining, + refillAmount: input.refillAmount, + refillInterval: input.refillInterval, + userId, + }, + }); - if (input.metadata) { - await db - .update(apikey) - .set({ metadata: JSON.stringify(input.metadata) }) - .where(eq(apikey.id, result.id)); - } + if (input.metadata) { + await db + .update(apikey) + .set({ metadata: JSON.stringify(input.metadata) }) + .where(eq(apikey.id, result.id)); + } - return result; + return result; }; diff --git a/packages/server/src/setup/setup.ts b/packages/server/src/setup/setup.ts index 4c01bf6cb..5171063d6 100644 --- a/packages/server/src/setup/setup.ts +++ b/packages/server/src/setup/setup.ts @@ -3,13 +3,13 @@ import { docker } from "../constants"; export const initializeSwarm = async () => { const swarmInitialized = await dockerSwarmInitialized(); if (swarmInitialized) { - console.log("Swarm is already initilized"); + console.log("Swarm is already initialized"); } else { await docker.swarmInit({ AdvertiseAddr: "127.0.0.1", ListenAddr: "0.0.0.0", }); - console.log("Swarm was initilized"); + console.log("Swarm was initialized"); } }; @@ -26,14 +26,14 @@ export const dockerSwarmInitialized = async () => { export const initializeNetwork = async () => { const networkInitialized = await dockerNetworkInitialized(); if (networkInitialized) { - console.log("Network is already initilized"); + console.log("Network is already initialized"); } else { docker.createNetwork({ Attachable: true, Name: "dokploy-network", Driver: "overlay", }); - console.log("Network was initilized"); + console.log("Network was initialized"); } }; diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index ca2b8a6b5..32aecbd4c 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -5,26 +5,26 @@ import boxen from "boxen"; import { quote } from "shell-quote"; import { writeDomainsToCompose } from "../docker/domain"; import { - encodeBase64, - getEnviromentVariablesObject, - prepareEnvironmentVariables, + encodeBase64, + getEnvironmentVariablesObject, + prepareEnvironmentVariables, } from "../docker/utils"; export type ComposeNested = InferResultType< - "compose", - { environment: { with: { project: true } }; mounts: true; domains: true } + "compose", + { environment: { with: { project: true } }; mounts: true; domains: true } >; export const getBuildComposeCommand = async (compose: ComposeNested) => { - const { COMPOSE_PATH } = paths(!!compose.serverId); - const { sourceType, appName, mounts, composeType, domains } = compose; - const command = createCommand(compose); - const envCommand = getCreateEnvFileCommand(compose); - const projectPath = join(COMPOSE_PATH, compose.appName, "code"); - const exportEnvCommand = getExportEnvCommand(compose); + const { COMPOSE_PATH } = paths(!!compose.serverId); + const { sourceType, appName, mounts, composeType, domains } = compose; + const command = createCommand(compose); + const envCommand = getCreateEnvFileCommand(compose); + const projectPath = join(COMPOSE_PATH, compose.appName, "code"); + const exportEnvCommand = getExportEnvCommand(compose); - const newCompose = await writeDomainsToCompose(compose, domains); - const logContent = ` + const newCompose = await writeDomainsToCompose(compose, domains); + const logContent = ` App Name: ${appName} Build Compose 🐳 Detected: ${mounts.length} mounts 📂 @@ -32,31 +32,31 @@ Command: docker ${command} Source Type: docker ${sourceType} ✅ Compose Type: ${composeType} ✅`; - const logBox = boxen(logContent, { - padding: { - left: 1, - right: 1, - bottom: 1, - }, - width: 80, - borderStyle: "double", - }); + const logBox = boxen(logContent, { + padding: { + left: 1, + right: 1, + bottom: 1, + }, + width: 80, + borderStyle: "double", + }); - const bashCommand = ` + const bashCommand = ` set -e { echo "${logBox}"; - + ${newCompose} - + ${envCommand} - + cd "${projectPath}"; ${compose.isolatedDeployment ? `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create ${compose.composeType === "stack" ? "--driver overlay" : ""} --attachable ${compose.appName}` : ""} env -i PATH="$PATH" ${exportEnvCommand} docker ${command.split(" ").join(" ")} 2>&1 || { echo "Error: ❌ Docker command failed"; exit 1; } ${compose.isolatedDeployment ? `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` : ""} - + echo "Docker Compose Deployed: ✅"; } || { echo "Error: ❌ Script execution failed"; @@ -64,81 +64,81 @@ Compose Type: ${composeType} ✅`; } `; - return bashCommand; + return bashCommand; }; const sanitizeCommand = (command: string) => { - const sanitizedCommand = command.trim(); + const sanitizedCommand = command.trim(); - const parts = sanitizedCommand.split(/\s+/); + const parts = sanitizedCommand.split(/\s+/); - const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1")); + const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1")); - return restCommand.join(" "); + return restCommand.join(" "); }; export const createCommand = (compose: ComposeNested) => { - const { composeType, appName, sourceType } = compose; - if (compose.command) { - return `${sanitizeCommand(compose.command)}`; - } + const { composeType, appName, sourceType } = compose; + if (compose.command) { + return `${sanitizeCommand(compose.command)}`; + } - const path = - sourceType === "raw" ? "docker-compose.yml" : compose.composePath; - let command = ""; + const path = + sourceType === "raw" ? "docker-compose.yml" : compose.composePath; + let command = ""; - if (composeType === "docker-compose") { - command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`; - } else if (composeType === "stack") { - command = `stack deploy -c ${path} ${appName} --prune --with-registry-auth`; - } + if (composeType === "docker-compose") { + command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`; + } else if (composeType === "stack") { + command = `stack deploy -c ${path} ${appName} --prune --with-registry-auth`; + } - return command; + return command; }; export const getCreateEnvFileCommand = (compose: ComposeNested) => { - const { COMPOSE_PATH } = paths(!!compose.serverId); - const { env, composePath, appName } = compose; - const composeFilePath = - join(COMPOSE_PATH, appName, "code", composePath) || - join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); + const { COMPOSE_PATH } = paths(!!compose.serverId); + const { env, composePath, appName } = compose; + const composeFilePath = + join(COMPOSE_PATH, appName, "code", composePath) || + join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); - const envFilePath = join(dirname(composeFilePath), ".env"); + const envFilePath = join(dirname(composeFilePath), ".env"); - let envContent = `APP_NAME=${appName}\n`; - envContent += env || ""; - if (!envContent.includes("DOCKER_CONFIG")) { - envContent += "\nDOCKER_CONFIG=/root/.docker"; - } + let envContent = `APP_NAME=${appName}\n`; + envContent += env || ""; + if (!envContent.includes("DOCKER_CONFIG")) { + envContent += "\nDOCKER_CONFIG=/root/.docker"; + } - if (compose.randomize) { - envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; - } + if (compose.randomize) { + envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; + } - const envFileContent = prepareEnvironmentVariables( - envContent, - compose.environment.project.env, - compose.environment.env, - ).join("\n"); + const envFileContent = prepareEnvironmentVariables( + envContent, + compose.environment.project.env, + compose.environment.env, + ).join("\n"); - const encodedContent = encodeBase64(envFileContent); - return ` + const encodedContent = encodeBase64(envFileContent); + return ` touch ${envFilePath}; echo "${encodedContent}" | base64 -d > "${envFilePath}"; `; }; const getExportEnvCommand = (compose: ComposeNested) => { - if (compose.composeType !== "stack") return ""; + if (compose.composeType !== "stack") return ""; - const envVars = getEnviromentVariablesObject( - compose.env, - compose.environment.project.env, - compose.environment.env, - ); - const exports = Object.entries(envVars) - .map(([key, value]) => `${key}=${quote([value])}`) - .join(" "); + const envVars = getEnvironmentVariablesObject( + compose.env, + compose.environment.project.env, + compose.environment.env, + ); + const exports = Object.entries(envVars) + .map(([key, value]) => `${key}=${quote([value])}`) + .join(" "); - return exports ? `${exports}` : ""; + return exports ? `${exports}` : ""; }; diff --git a/packages/server/src/utils/builders/docker-file.ts b/packages/server/src/utils/builders/docker-file.ts index ea53a5bff..f2fedf461 100644 --- a/packages/server/src/utils/builders/docker-file.ts +++ b/packages/server/src/utils/builders/docker-file.ts @@ -1,105 +1,105 @@ import { - getEnviromentVariablesObject, - prepareEnvironmentVariablesForShell, + getEnvironmentVariablesObject, + prepareEnvironmentVariablesForShell, } from "@dokploy/server/utils/docker/utils"; import { quote } from "shell-quote"; import { - getBuildAppDirectory, - getDockerContextPath, + getBuildAppDirectory, + getDockerContextPath, } from "../filesystem/directory"; import type { ApplicationNested } from "."; import { createEnvFileCommand } from "./utils"; export const getDockerCommand = (application: ApplicationNested) => { - const { - appName, - env, - publishDirectory, - buildArgs, - buildSecrets, - dockerBuildStage, - cleanCache, - createEnvFile, - } = application; - const dockerFilePath = getBuildAppDirectory(application); + const { + appName, + env, + publishDirectory, + buildArgs, + buildSecrets, + dockerBuildStage, + cleanCache, + createEnvFile, + } = application; + const dockerFilePath = getBuildAppDirectory(application); - try { - const image = `${appName}`; + try { + const image = `${appName}`; - const defaultContextPath = - dockerFilePath.substring(0, dockerFilePath.lastIndexOf("/") + 1) || "."; + const defaultContextPath = + dockerFilePath.substring(0, dockerFilePath.lastIndexOf("/") + 1) || "."; - const dockerContextPath = - getDockerContextPath(application) || defaultContextPath; + const dockerContextPath = + getDockerContextPath(application) || defaultContextPath; - const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."]; + const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."]; - if (dockerBuildStage) { - commandArgs.push("--target", dockerBuildStage); - } + if (dockerBuildStage) { + commandArgs.push("--target", dockerBuildStage); + } - if (cleanCache) { - commandArgs.push("--no-cache"); - } + if (cleanCache) { + commandArgs.push("--no-cache"); + } - const args = prepareEnvironmentVariablesForShell( - buildArgs, - application.environment.project.env, - application.environment.env, - ); + const args = prepareEnvironmentVariablesForShell( + buildArgs, + application.environment.project.env, + application.environment.env, + ); - for (const arg of args) { - commandArgs.push("--build-arg", arg); - } + for (const arg of args) { + commandArgs.push("--build-arg", arg); + } - const secrets = getEnviromentVariablesObject( - buildSecrets, - application.environment.project.env, - application.environment.env, - ); + const secrets = getEnvironmentVariablesObject( + buildSecrets, + application.environment.project.env, + application.environment.env, + ); - const joinedSecrets = Object.entries(secrets) - .map(([key, value]) => `${key}=${quote([value])}`) - .join(" "); + const joinedSecrets = Object.entries(secrets) + .map(([key, value]) => `${key}=${quote([value])}`) + .join(" "); - /* + /* Do not generate an environment file when publishDirectory is specified, as it could be publicly exposed. Also respect the createEnvFile flag. */ - let command = ""; - if (!publishDirectory && createEnvFile) { - command += createEnvFileCommand( - dockerFilePath, - env, - application.environment.project.env, - application.environment.env, - ); - } + let command = ""; + if (!publishDirectory && createEnvFile) { + command += createEnvFileCommand( + dockerFilePath, + env, + application.environment.project.env, + application.environment.env, + ); + } - for (const key in secrets) { - // Although buildx is smart enough to know we may be referring to an environment variable name, - // we still make sure it doesn't fall back to `type=file`. - // See: https://docs.docker.com/reference/cli/docker/buildx/build/#secret - commandArgs.push("--secret", `type=env,id=${key}`); - } + for (const key in secrets) { + // Although buildx is smart enough to know we may be referring to an environment variable name, + // we still make sure it doesn't fall back to `type=file`. + // See: https://docs.docker.com/reference/cli/docker/buildx/build/#secret + commandArgs.push("--secret", `type=env,id=${key}`); + } - command += ` + command += ` echo "Building ${appName}" ; -cd ${dockerContextPath} || { +cd ${dockerContextPath} || { echo "❌ The path ${dockerContextPath} does not exist" ; exit 1; } -${joinedSecrets} docker ${commandArgs.join(" ")} || { +${joinedSecrets} docker ${commandArgs.join(" ")} || { echo "❌ Docker build failed" ; exit 1; } echo "✅ Docker build completed." ; `; - return command; - } catch (error) { - throw error; - } + return command; + } catch (error) { + throw error; + } }; diff --git a/packages/server/src/utils/docker/utils.ts b/packages/server/src/utils/docker/utils.ts index b2c7e5d7b..dd645cd1b 100644 --- a/packages/server/src/utils/docker/utils.ts +++ b/packages/server/src/utils/docker/utils.ts @@ -434,7 +434,7 @@ export const parseEnvironmentKeyValuePair = ( return [key, valueParts.join("=")]; }; -export const getEnviromentVariablesObject = ( +export const getEnvironmentVariablesObject = ( input: string | null, projectEnv?: string | null, environmentEnv?: string | null, diff --git a/packages/server/src/utils/startup/cancell-deployments.ts b/packages/server/src/utils/startup/cancel-deployments.ts similarity index 100% rename from packages/server/src/utils/startup/cancell-deployments.ts rename to packages/server/src/utils/startup/cancel-deployments.ts From 6d17f629425d0c287fc89932a42e4034f8eeae2a Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:02:53 +0000 Subject: [PATCH 2/7] [autofix.ci] apply automated fixes --- .../compose/network/network-service.test.ts | 206 +++--- .../__test__/env/stack-environment.test.ts | 194 ++--- packages/server/src/services/user.ts | 676 +++++++++--------- packages/server/src/utils/builders/compose.ts | 144 ++-- .../server/src/utils/builders/docker-file.ts | 130 ++-- 5 files changed, 675 insertions(+), 675 deletions(-) diff --git a/apps/dokploy/__test__/compose/network/network-service.test.ts b/apps/dokploy/__test__/compose/network/network-service.test.ts index 91eb5da4e..073e61615 100644 --- a/apps/dokploy/__test__/compose/network/network-service.test.ts +++ b/apps/dokploy/__test__/compose/network/network-service.test.ts @@ -1,7 +1,7 @@ import type { ComposeSpecification } from "@dokploy/server"; import { - addSuffixToServiceNetworks, - generateRandomHash, + addSuffixToServiceNetworks, + generateRandomHash, } from "@dokploy/server"; import { expect, test } from "vitest"; import { parse } from "yaml"; @@ -23,30 +23,30 @@ services: `; test("Add suffix to networks in services", () => { - const composeData = parse(composeFile) as ComposeSpecification; + const composeData = parse(composeFile) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const services = addSuffixToServiceNetworks(composeData.services, suffix); - const actualComposeData = { ...composeData, services }; + if (!composeData?.services) { + return; + } + const services = addSuffixToServiceNetworks(composeData.services, suffix); + const actualComposeData = { ...composeData, services }; - expect(actualComposeData?.services?.web?.networks).toContain( - `frontend-${suffix}`, - ); + expect(actualComposeData?.services?.web?.networks).toContain( + `frontend-${suffix}`, + ); - expect(actualComposeData?.services?.api?.networks).toContain( - `backend-${suffix}`, - ); + expect(actualComposeData?.services?.api?.networks).toContain( + `backend-${suffix}`, + ); - const apiNetworks = actualComposeData?.services?.api?.networks; + const apiNetworks = actualComposeData?.services?.api?.networks; - expect(apiNetworks).toBeDefined(); - expect(actualComposeData?.services?.api?.networks).toContain( - `backend-${suffix}`, - ); + expect(apiNetworks).toBeDefined(); + expect(actualComposeData?.services?.api?.networks).toContain( + `backend-${suffix}`, + ); }); // Caso 2: Objeto con aliases @@ -67,29 +67,29 @@ networks: `; test("Add suffix to networks in services with aliases", () => { - const composeData = parse(composeFile2) as ComposeSpecification; + const composeData = parse(composeFile2) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const services = addSuffixToServiceNetworks(composeData.services, suffix); - const actualComposeData = { ...composeData, services }; + if (!composeData?.services) { + return; + } + const services = addSuffixToServiceNetworks(composeData.services, suffix); + const actualComposeData = { ...composeData, services }; - expect(actualComposeData.services?.api?.networks).toHaveProperty( - `frontend-${suffix}`, - ); + expect(actualComposeData.services?.api?.networks).toHaveProperty( + `frontend-${suffix}`, + ); - const networkConfig = actualComposeData?.services?.api?.networks as { - [key: string]: { aliases?: string[] }; - }; - expect(networkConfig[`frontend-${suffix}`]).toBeDefined(); - expect(networkConfig[`frontend-${suffix}`]?.aliases).toContain("api"); + const networkConfig = actualComposeData?.services?.api?.networks as { + [key: string]: { aliases?: string[] }; + }; + expect(networkConfig[`frontend-${suffix}`]).toBeDefined(); + expect(networkConfig[`frontend-${suffix}`]?.aliases).toContain("api"); - expect(actualComposeData.services?.api?.networks).not.toHaveProperty( - "frontend-ash", - ); + expect(actualComposeData.services?.api?.networks).not.toHaveProperty( + "frontend-ash", + ); }); const composeFile3 = ` @@ -107,19 +107,19 @@ networks: `; test("Add suffix to networks in services (Object with simple networks)", () => { - const composeData = parse(composeFile3) as ComposeSpecification; + const composeData = parse(composeFile3) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const services = addSuffixToServiceNetworks(composeData.services, suffix); - const actualComposeData = { ...composeData, services }; + if (!composeData?.services) { + return; + } + const services = addSuffixToServiceNetworks(composeData.services, suffix); + const actualComposeData = { ...composeData, services }; - expect(actualComposeData.services?.redis?.networks).toHaveProperty( - `backend-${suffix}`, - ); + expect(actualComposeData.services?.redis?.networks).toHaveProperty( + `backend-${suffix}`, + ); }); const composeFileCombined = ` @@ -153,36 +153,36 @@ networks: `; test("Add suffix to networks in services (combined case)", () => { - const composeData = parse(composeFileCombined) as ComposeSpecification; + const composeData = parse(composeFileCombined) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const services = addSuffixToServiceNetworks(composeData.services, suffix); - const actualComposeData = { ...composeData, services }; + if (!composeData?.services) { + return; + } + const services = addSuffixToServiceNetworks(composeData.services, suffix); + const actualComposeData = { ...composeData, services }; - // Caso 1: ListOfStrings - expect(actualComposeData.services?.web?.networks).toContain( - `frontend-${suffix}`, - ); - expect(actualComposeData.services?.web?.networks).toContain( - `backend-${suffix}`, - ); + // Caso 1: ListOfStrings + expect(actualComposeData.services?.web?.networks).toContain( + `frontend-${suffix}`, + ); + expect(actualComposeData.services?.web?.networks).toContain( + `backend-${suffix}`, + ); - // Caso 2: Objeto con aliases - const apiNetworks = actualComposeData.services?.api?.networks as { - [key: string]: unknown; - }; - expect(apiNetworks).toHaveProperty(`frontend-${suffix}`); - expect(apiNetworks[`frontend-${suffix}`]).toBeDefined(); - expect(apiNetworks).not.toHaveProperty("frontend"); + // Caso 2: Objeto con aliases + const apiNetworks = actualComposeData.services?.api?.networks as { + [key: string]: unknown; + }; + expect(apiNetworks).toHaveProperty(`frontend-${suffix}`); + expect(apiNetworks[`frontend-${suffix}`]).toBeDefined(); + expect(apiNetworks).not.toHaveProperty("frontend"); - // Caso 3: Objeto con redes simples - const redisNetworks = actualComposeData.services?.redis?.networks; - expect(redisNetworks).toHaveProperty(`backend-${suffix}`); - expect(redisNetworks).not.toHaveProperty("backend"); + // Caso 3: Objeto con redes simples + const redisNetworks = actualComposeData.services?.redis?.networks; + expect(redisNetworks).toHaveProperty(`backend-${suffix}`); + expect(redisNetworks).not.toHaveProperty("backend"); }); const composeFile7 = ` @@ -196,18 +196,18 @@ services: `; test("It shouldn't add suffix to dokploy-network in services", () => { - const composeData = parse(composeFile7) as ComposeSpecification; + const composeData = parse(composeFile7) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const networks = addSuffixToServiceNetworks(composeData.services, suffix); - const service = networks.web; + if (!composeData?.services) { + return; + } + const networks = addSuffixToServiceNetworks(composeData.services, suffix); + const service = networks.web; - expect(service).toBeDefined(); - expect(service?.networks).toContain("dokploy-network"); + expect(service).toBeDefined(); + expect(service?.networks).toContain("dokploy-network"); }); const composeFile8 = ` @@ -245,31 +245,31 @@ services: `; test("It shouldn't add suffix to dokploy-network in services multiples cases", () => { - const composeData = parse(composeFile8) as ComposeSpecification; + const composeData = parse(composeFile8) as ComposeSpecification; - const suffix = generateRandomHash(); + const suffix = generateRandomHash(); - if (!composeData?.services) { - return; - } - const networks = addSuffixToServiceNetworks(composeData.services, suffix); - const service = networks.web; - const api = networks.api; - const redis = networks.redis; - const db = networks.db; + if (!composeData?.services) { + return; + } + const networks = addSuffixToServiceNetworks(composeData.services, suffix); + const service = networks.web; + const api = networks.api; + const redis = networks.redis; + const db = networks.db; - const dbNetworks = db?.networks as { - [key: string]: unknown; - }; + const dbNetworks = db?.networks as { + [key: string]: unknown; + }; - const apiNetworks = api?.networks as { - [key: string]: unknown; - }; + const apiNetworks = api?.networks as { + [key: string]: unknown; + }; - expect(service).toBeDefined(); - expect(service?.networks).toContain("dokploy-network"); + expect(service).toBeDefined(); + expect(service?.networks).toContain("dokploy-network"); - expect(redis?.networks).toHaveProperty("dokploy-network"); - expect(dbNetworks["dokploy-network"]).toBeDefined(); - expect(apiNetworks["dokploy-network"]).toBeDefined(); + expect(redis?.networks).toHaveProperty("dokploy-network"); + expect(dbNetworks["dokploy-network"]).toBeDefined(); + expect(apiNetworks["dokploy-network"]).toBeDefined(); }); diff --git a/apps/dokploy/__test__/env/stack-environment.test.ts b/apps/dokploy/__test__/env/stack-environment.test.ts index cde7be9db..773adf3ed 100644 --- a/apps/dokploy/__test__/env/stack-environment.test.ts +++ b/apps/dokploy/__test__/env/stack-environment.test.ts @@ -16,28 +16,28 @@ SECRET_KEY=env-secret-123 `; describe("getEnvironmentVariablesObject with environment variables (Stack compose)", () => { - it("resolves environment variables correctly for Stack compose", () => { - const serviceEnv = ` + it("resolves environment variables correctly for Stack compose", () => { + const serviceEnv = ` FOO=\${{environment.NODE_ENV}} BAR=\${{environment.API_URL}} BAZ=test `; - const result = getEnvironmentVariablesObject( - serviceEnv, - projectEnv, - environmentEnv, - ); + const result = getEnvironmentVariablesObject( + serviceEnv, + projectEnv, + environmentEnv, + ); - expect(result).toEqual({ - FOO: "development", - BAR: "https://api.dev.example.com", - BAZ: "test", - }); - }); + expect(result).toEqual({ + FOO: "development", + BAR: "https://api.dev.example.com", + BAZ: "test", + }); + }); - it("resolves both project and environment variables for Stack compose", () => { - const serviceEnv = ` + it("resolves both project and environment variables for Stack compose", () => { + const serviceEnv = ` ENVIRONMENT=\${{project.ENVIRONMENT}} NODE_ENV=\${{environment.NODE_ENV}} API_URL=\${{environment.API_URL}} @@ -45,140 +45,140 @@ DATABASE_URL=\${{project.DATABASE_URL}} SERVICE_PORT=4000 `; - const result = getEnvironmentVariablesObject( - serviceEnv, - projectEnv, - environmentEnv, - ); + const result = getEnvironmentVariablesObject( + serviceEnv, + projectEnv, + environmentEnv, + ); - expect(result).toEqual({ - ENVIRONMENT: "staging", - NODE_ENV: "development", - API_URL: "https://api.dev.example.com", - DATABASE_URL: "postgres://postgres:postgres@localhost:5432/project_db", - SERVICE_PORT: "4000", - }); - }); + expect(result).toEqual({ + ENVIRONMENT: "staging", + NODE_ENV: "development", + API_URL: "https://api.dev.example.com", + DATABASE_URL: "postgres://postgres:postgres@localhost:5432/project_db", + SERVICE_PORT: "4000", + }); + }); - it("handles multiple environment references in single value for Stack compose", () => { - const multiRefEnv = ` + it("handles multiple environment references in single value for Stack compose", () => { + const multiRefEnv = ` HOST=localhost PORT=5432 USERNAME=postgres PASSWORD=secret123 `; - const serviceEnv = ` + const serviceEnv = ` DATABASE_URL=postgresql://\${{environment.USERNAME}}:\${{environment.PASSWORD}}@\${{environment.HOST}}:\${{environment.PORT}}/mydb `; - const result = getEnvironmentVariablesObject(serviceEnv, "", multiRefEnv); + const result = getEnvironmentVariablesObject(serviceEnv, "", multiRefEnv); - expect(result).toEqual({ - DATABASE_URL: "postgresql://postgres:secret123@localhost:5432/mydb", - }); - }); + expect(result).toEqual({ + DATABASE_URL: "postgresql://postgres:secret123@localhost:5432/mydb", + }); + }); - it("throws error for undefined environment variables in Stack compose", () => { - const serviceWithUndefined = ` + it("throws error for undefined environment variables in Stack compose", () => { + const serviceWithUndefined = ` UNDEFINED_VAR=\${{environment.UNDEFINED_VAR}} `; - expect(() => - getEnvironmentVariablesObject(serviceWithUndefined, "", environmentEnv), - ).toThrow("Invalid environment variable: environment.UNDEFINED_VAR"); - }); + expect(() => + getEnvironmentVariablesObject(serviceWithUndefined, "", environmentEnv), + ).toThrow("Invalid environment variable: environment.UNDEFINED_VAR"); + }); - it("allows service variables to override environment variables in Stack compose", () => { - const serviceOverrideEnv = ` + it("allows service variables to override environment variables in Stack compose", () => { + const serviceOverrideEnv = ` NODE_ENV=production API_URL=\${{environment.API_URL}} `; - const result = getEnvironmentVariablesObject( - serviceOverrideEnv, - "", - environmentEnv, - ); + const result = getEnvironmentVariablesObject( + serviceOverrideEnv, + "", + environmentEnv, + ); - expect(result).toEqual({ - NODE_ENV: "production", - API_URL: "https://api.dev.example.com", - }); - }); + expect(result).toEqual({ + NODE_ENV: "production", + API_URL: "https://api.dev.example.com", + }); + }); - it("resolves complex references with project, environment, and service variables for Stack compose", () => { - const complexServiceEnv = ` + it("resolves complex references with project, environment, and service variables for Stack compose", () => { + const complexServiceEnv = ` FULL_DATABASE_URL=\${{project.DATABASE_URL}}/\${{environment.DATABASE_NAME}} API_ENDPOINT=\${{environment.API_URL}}/\${{project.ENVIRONMENT}}/api SERVICE_NAME=my-service COMPLEX_VAR=\${{SERVICE_NAME}}-\${{environment.NODE_ENV}}-\${{project.ENVIRONMENT}} `; - const result = getEnvironmentVariablesObject( - complexServiceEnv, - projectEnv, - environmentEnv, - ); + const result = getEnvironmentVariablesObject( + complexServiceEnv, + projectEnv, + environmentEnv, + ); - expect(result).toEqual({ - FULL_DATABASE_URL: - "postgres://postgres:postgres@localhost:5432/project_db/dev_database", - API_ENDPOINT: "https://api.dev.example.com/staging/api", - SERVICE_NAME: "my-service", - COMPLEX_VAR: "my-service-development-staging", - }); - }); + expect(result).toEqual({ + FULL_DATABASE_URL: + "postgres://postgres:postgres@localhost:5432/project_db/dev_database", + API_ENDPOINT: "https://api.dev.example.com/staging/api", + SERVICE_NAME: "my-service", + COMPLEX_VAR: "my-service-development-staging", + }); + }); - it("maintains precedence: service > environment > project in Stack compose", () => { - const conflictingProjectEnv = ` + it("maintains precedence: service > environment > project in Stack compose", () => { + const conflictingProjectEnv = ` NODE_ENV=production-project API_URL=https://project.api.com DATABASE_NAME=project_db `; - const conflictingEnvironmentEnv = ` + const conflictingEnvironmentEnv = ` NODE_ENV=development-environment API_URL=https://environment.api.com DATABASE_NAME=env_db `; - const serviceWithConflicts = ` + const serviceWithConflicts = ` NODE_ENV=service-override PROJECT_ENV=\${{project.NODE_ENV}} ENV_VAR=\${{environment.API_URL}} DB_NAME=\${{environment.DATABASE_NAME}} `; - const result = getEnvironmentVariablesObject( - serviceWithConflicts, - conflictingProjectEnv, - conflictingEnvironmentEnv, - ); + const result = getEnvironmentVariablesObject( + serviceWithConflicts, + conflictingProjectEnv, + conflictingEnvironmentEnv, + ); - expect(result).toEqual({ - NODE_ENV: "service-override", - PROJECT_ENV: "production-project", - ENV_VAR: "https://environment.api.com", - DB_NAME: "env_db", - }); - }); + expect(result).toEqual({ + NODE_ENV: "service-override", + PROJECT_ENV: "production-project", + ENV_VAR: "https://environment.api.com", + DB_NAME: "env_db", + }); + }); - it("handles empty environment variables in Stack compose", () => { - const serviceWithEmpty = ` + it("handles empty environment variables in Stack compose", () => { + const serviceWithEmpty = ` SERVICE_VAR=test PROJECT_VAR=\${{project.ENVIRONMENT}} `; - const result = getEnvironmentVariablesObject( - serviceWithEmpty, - projectEnv, - "", - ); + const result = getEnvironmentVariablesObject( + serviceWithEmpty, + projectEnv, + "", + ); - expect(result).toEqual({ - SERVICE_VAR: "test", - PROJECT_VAR: "staging", - }); - }); + expect(result).toEqual({ + SERVICE_VAR: "test", + PROJECT_VAR: "staging", + }); + }); }); diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index 5e66c6f2c..ed43f3862 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -7,452 +7,452 @@ import { auth } from "../lib/auth"; export type User = typeof user.$inferSelect; export const addNewProject = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const userR = await findMemberById(userId, organizationId); + const userR = await findMemberById(userId, organizationId); - await db - .update(member) - .set({ - accessedProjects: [...userR.accessedProjects, projectId], - }) - .where( - and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), - ); + await db + .update(member) + .set({ + accessedProjects: [...userR.accessedProjects, projectId], + }) + .where( + and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), + ); }; export const addNewEnvironment = async ( - userId: string, - environmentId: string, - organizationId: string, + userId: string, + environmentId: string, + organizationId: string, ) => { - const userR = await findMemberById(userId, organizationId); + const userR = await findMemberById(userId, organizationId); - await db - .update(member) - .set({ - accessedEnvironments: [...userR.accessedEnvironments, environmentId], - }) - .where( - and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), - ); + await db + .update(member) + .set({ + accessedEnvironments: [...userR.accessedEnvironments, environmentId], + }) + .where( + and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), + ); }; export const addNewService = async ( - userId: string, - serviceId: string, - organizationId: string, + userId: string, + serviceId: string, + organizationId: string, ) => { - const userR = await findMemberById(userId, organizationId); - await db - .update(member) - .set({ - accessedServices: [...userR.accessedServices, serviceId], - }) - .where( - and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), - ); + const userR = await findMemberById(userId, organizationId); + await db + .update(member) + .set({ + accessedServices: [...userR.accessedServices, serviceId], + }) + .where( + and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), + ); }; export const canPerformCreationService = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const { accessedProjects, canCreateServices } = await findMemberById( - userId, - organizationId, - ); - const haveAccessToProject = accessedProjects.includes(projectId); + const { accessedProjects, canCreateServices } = await findMemberById( + userId, + organizationId, + ); + const haveAccessToProject = accessedProjects.includes(projectId); - if (canCreateServices && haveAccessToProject) { - return true; - } + if (canCreateServices && haveAccessToProject) { + return true; + } - return false; + return false; }; export const canPerformAccessService = async ( - userId: string, - serviceId: string, - organizationId: string, + userId: string, + serviceId: string, + organizationId: string, ) => { - const { accessedServices } = await findMemberById(userId, organizationId); - const haveAccessToService = accessedServices.includes(serviceId); + const { accessedServices } = await findMemberById(userId, organizationId); + const haveAccessToService = accessedServices.includes(serviceId); - if (haveAccessToService) { - return true; - } + if (haveAccessToService) { + return true; + } - return false; + return false; }; export const canPerformDeleteService = async ( - userId: string, - serviceId: string, - organizationId: string, + userId: string, + serviceId: string, + organizationId: string, ) => { - const { accessedServices, canDeleteServices } = await findMemberById( - userId, - organizationId, - ); - const haveAccessToService = accessedServices.includes(serviceId); + const { accessedServices, canDeleteServices } = await findMemberById( + userId, + organizationId, + ); + const haveAccessToService = accessedServices.includes(serviceId); - if (canDeleteServices && haveAccessToService) { - return true; - } + if (canDeleteServices && haveAccessToService) { + return true; + } - return false; + return false; }; export const canPerformCreationProject = async ( - userId: string, - organizationId: string, + userId: string, + organizationId: string, ) => { - const { canCreateProjects } = await findMemberById(userId, organizationId); + const { canCreateProjects } = await findMemberById(userId, organizationId); - if (canCreateProjects) { - return true; - } + if (canCreateProjects) { + return true; + } - return false; + return false; }; export const canPerformDeleteProject = async ( - userId: string, - organizationId: string, + userId: string, + organizationId: string, ) => { - const { canDeleteProjects } = await findMemberById(userId, organizationId); + const { canDeleteProjects } = await findMemberById(userId, organizationId); - if (canDeleteProjects) { - return true; - } + if (canDeleteProjects) { + return true; + } - return false; + return false; }; export const canPerformAccessProject = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const { accessedProjects } = await findMemberById(userId, organizationId); + const { accessedProjects } = await findMemberById(userId, organizationId); - const haveAccessToProject = accessedProjects.includes(projectId); + const haveAccessToProject = accessedProjects.includes(projectId); - if (haveAccessToProject) { - return true; - } - return false; + if (haveAccessToProject) { + return true; + } + return false; }; export const canPerformAccessEnvironment = async ( - userId: string, - environmentId: string, - organizationId: string, + userId: string, + environmentId: string, + organizationId: string, ) => { - const { accessedEnvironments } = await findMemberById(userId, organizationId); - const haveAccessToEnvironment = accessedEnvironments.includes(environmentId); + const { accessedEnvironments } = await findMemberById(userId, organizationId); + const haveAccessToEnvironment = accessedEnvironments.includes(environmentId); - if (haveAccessToEnvironment) { - return true; - } + if (haveAccessToEnvironment) { + return true; + } - return false; + return false; }; export const canPerformDeleteEnvironment = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const { accessedProjects, canDeleteEnvironments } = await findMemberById( - userId, - organizationId, - ); - const haveAccessToProject = accessedProjects.includes(projectId); + const { accessedProjects, canDeleteEnvironments } = await findMemberById( + userId, + organizationId, + ); + const haveAccessToProject = accessedProjects.includes(projectId); - if (canDeleteEnvironments && haveAccessToProject) { - return true; - } + if (canDeleteEnvironments && haveAccessToProject) { + return true; + } - return false; + return false; }; export const canAccessToTraefikFiles = async ( - userId: string, - organizationId: string, + userId: string, + organizationId: string, ) => { - const { canAccessToTraefikFiles } = await findMemberById( - userId, - organizationId, - ); - return canAccessToTraefikFiles; + const { canAccessToTraefikFiles } = await findMemberById( + userId, + organizationId, + ); + return canAccessToTraefikFiles; }; export const checkServiceAccess = async ( - userId: string, - serviceId: string, - organizationId: string, - action = "access" as "access" | "create" | "delete", + userId: string, + serviceId: string, + organizationId: string, + action = "access" as "access" | "create" | "delete", ) => { - let hasPermission = false; - switch (action) { - case "create": - hasPermission = await canPerformCreationService( - userId, - serviceId, - organizationId, - ); - break; - case "access": - hasPermission = await canPerformAccessService( - userId, - serviceId, - organizationId, - ); - break; - case "delete": - hasPermission = await canPerformDeleteService( - userId, - serviceId, - organizationId, - ); - break; - default: - hasPermission = false; - } - if (!hasPermission) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "Permission denied", - }); - } + let hasPermission = false; + switch (action) { + case "create": + hasPermission = await canPerformCreationService( + userId, + serviceId, + organizationId, + ); + break; + case "access": + hasPermission = await canPerformAccessService( + userId, + serviceId, + organizationId, + ); + break; + case "delete": + hasPermission = await canPerformDeleteService( + userId, + serviceId, + organizationId, + ); + break; + default: + hasPermission = false; + } + if (!hasPermission) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Permission denied", + }); + } }; export const checkEnvironmentAccess = async ( - userId: string, - environmentId: string, - organizationId: string, - action = "access" as const, + userId: string, + environmentId: string, + organizationId: string, + action = "access" as const, ) => { - let hasPermission = false; - switch (action) { - case "access": - hasPermission = await canPerformAccessEnvironment( - userId, - environmentId, - organizationId, - ); - break; - default: - hasPermission = false; - } - if (!hasPermission) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "Permission denied", - }); - } + let hasPermission = false; + switch (action) { + case "access": + hasPermission = await canPerformAccessEnvironment( + userId, + environmentId, + organizationId, + ); + break; + default: + hasPermission = false; + } + if (!hasPermission) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Permission denied", + }); + } }; export const checkEnvironmentDeletionPermission = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - const member = await findMemberById(userId, organizationId); + const member = await findMemberById(userId, organizationId); - if (!member) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "User not found in organization", - }); - } + if (!member) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "User not found in organization", + }); + } - if (member.role === "owner" || member.role === "admin") { - return true; - } + if (member.role === "owner" || member.role === "admin") { + return true; + } - if (!member.canDeleteEnvironments) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You don't have permission to delete environments", - }); - } + if (!member.canDeleteEnvironments) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have permission to delete environments", + }); + } - const hasProjectAccess = member.accessedProjects.includes(projectId); - if (!hasProjectAccess) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You don't have access to this project", - }); - } + const hasProjectAccess = member.accessedProjects.includes(projectId); + if (!hasProjectAccess) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this project", + }); + } - return true; + return true; }; export const checkProjectAccess = async ( - authId: string, - action: "create" | "delete" | "access", - organizationId: string, - projectId?: string, + authId: string, + action: "create" | "delete" | "access", + organizationId: string, + projectId?: string, ) => { - let hasPermission = false; - switch (action) { - case "access": - hasPermission = await canPerformAccessProject( - authId, - projectId as string, - organizationId, - ); - break; - case "create": - hasPermission = await canPerformCreationProject(authId, organizationId); - break; - case "delete": - hasPermission = await canPerformDeleteProject(authId, organizationId); - break; - default: - hasPermission = false; - } - if (!hasPermission) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "Permission denied", - }); - } + let hasPermission = false; + switch (action) { + case "access": + hasPermission = await canPerformAccessProject( + authId, + projectId as string, + organizationId, + ); + break; + case "create": + hasPermission = await canPerformCreationProject(authId, organizationId); + break; + case "delete": + hasPermission = await canPerformDeleteProject(authId, organizationId); + break; + default: + hasPermission = false; + } + if (!hasPermission) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Permission denied", + }); + } }; export const checkEnvironmentCreationPermission = async ( - userId: string, - projectId: string, - organizationId: string, + userId: string, + projectId: string, + organizationId: string, ) => { - // Get user's member record - const member = await findMemberById(userId, organizationId); + // Get user's member record + const member = await findMemberById(userId, organizationId); - if (!member) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "User not found in organization", - }); - } + if (!member) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "User not found in organization", + }); + } - // Owners and admins can always create environments - if (member.role === "owner" || member.role === "admin") { - return true; - } + // Owners and admins can always create environments + if (member.role === "owner" || member.role === "admin") { + return true; + } - // Check if user has canCreateEnvironments permission - if (!member.canCreateEnvironments) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You don't have permission to create environments", - }); - } + // Check if user has canCreateEnvironments permission + if (!member.canCreateEnvironments) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have permission to create environments", + }); + } - // Check if user has access to the project - const hasProjectAccess = member.accessedProjects.includes(projectId); - if (!hasProjectAccess) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You don't have access to this project", - }); - } + // Check if user has access to the project + const hasProjectAccess = member.accessedProjects.includes(projectId); + if (!hasProjectAccess) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this project", + }); + } - return true; + return true; }; export const findMemberById = async ( - userId: string, - organizationId: string, + userId: string, + organizationId: string, ) => { - const result = await db.query.member.findFirst({ - where: and( - eq(member.userId, userId), - eq(member.organizationId, organizationId), - ), - with: { - user: true, - }, - }); + const result = await db.query.member.findFirst({ + where: and( + eq(member.userId, userId), + eq(member.organizationId, organizationId), + ), + with: { + user: true, + }, + }); - if (!result) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "Permission denied", - }); - } - return result; + if (!result) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Permission denied", + }); + } + return result; }; export const updateUser = async (userId: string, userData: Partial) => { - // Validate email if it's being updated - if (userData.email !== undefined) { - if (!userData.email || userData.email.trim() === "") { - throw new Error("Email is required and cannot be empty"); - } + // Validate email if it's being updated + if (userData.email !== undefined) { + if (!userData.email || userData.email.trim() === "") { + throw new Error("Email is required and cannot be empty"); + } - // Basic email format validation - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(userData.email)) { - throw new Error("Please enter a valid email address"); - } - } + // Basic email format validation + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(userData.email)) { + throw new Error("Please enter a valid email address"); + } + } - const userResult = await db - .update(user) - .set({ - ...userData, - }) - .where(eq(user.id, userId)) - .returning() - .then((res) => res[0]); + const userResult = await db + .update(user) + .set({ + ...userData, + }) + .where(eq(user.id, userId)) + .returning() + .then((res) => res[0]); - return userResult; + return userResult; }; export const createApiKey = async ( - userId: string, - input: { - name: string; - prefix?: string; - expiresIn?: number; - metadata: { - organizationId: string; - }; - rateLimitEnabled?: boolean; - rateLimitTimeWindow?: number; - rateLimitMax?: number; - remaining?: number; - refillAmount?: number; - refillInterval?: number; - }, + userId: string, + input: { + name: string; + prefix?: string; + expiresIn?: number; + metadata: { + organizationId: string; + }; + rateLimitEnabled?: boolean; + rateLimitTimeWindow?: number; + rateLimitMax?: number; + remaining?: number; + refillAmount?: number; + refillInterval?: number; + }, ) => { - const result = await auth.createApiKey({ - body: { - name: input.name, - expiresIn: input.expiresIn, - prefix: input.prefix, - rateLimitEnabled: input.rateLimitEnabled, - rateLimitTimeWindow: input.rateLimitTimeWindow, - rateLimitMax: input.rateLimitMax, - remaining: input.remaining, - refillAmount: input.refillAmount, - refillInterval: input.refillInterval, - userId, - }, - }); + const result = await auth.createApiKey({ + body: { + name: input.name, + expiresIn: input.expiresIn, + prefix: input.prefix, + rateLimitEnabled: input.rateLimitEnabled, + rateLimitTimeWindow: input.rateLimitTimeWindow, + rateLimitMax: input.rateLimitMax, + remaining: input.remaining, + refillAmount: input.refillAmount, + refillInterval: input.refillInterval, + userId, + }, + }); - if (input.metadata) { - await db - .update(apikey) - .set({ metadata: JSON.stringify(input.metadata) }) - .where(eq(apikey.id, result.id)); - } + if (input.metadata) { + await db + .update(apikey) + .set({ metadata: JSON.stringify(input.metadata) }) + .where(eq(apikey.id, result.id)); + } - return result; + return result; }; diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index 32aecbd4c..316570626 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -5,26 +5,26 @@ import boxen from "boxen"; import { quote } from "shell-quote"; import { writeDomainsToCompose } from "../docker/domain"; import { - encodeBase64, - getEnvironmentVariablesObject, - prepareEnvironmentVariables, + encodeBase64, + getEnvironmentVariablesObject, + prepareEnvironmentVariables, } from "../docker/utils"; export type ComposeNested = InferResultType< - "compose", - { environment: { with: { project: true } }; mounts: true; domains: true } + "compose", + { environment: { with: { project: true } }; mounts: true; domains: true } >; export const getBuildComposeCommand = async (compose: ComposeNested) => { - const { COMPOSE_PATH } = paths(!!compose.serverId); - const { sourceType, appName, mounts, composeType, domains } = compose; - const command = createCommand(compose); - const envCommand = getCreateEnvFileCommand(compose); - const projectPath = join(COMPOSE_PATH, compose.appName, "code"); - const exportEnvCommand = getExportEnvCommand(compose); + const { COMPOSE_PATH } = paths(!!compose.serverId); + const { sourceType, appName, mounts, composeType, domains } = compose; + const command = createCommand(compose); + const envCommand = getCreateEnvFileCommand(compose); + const projectPath = join(COMPOSE_PATH, compose.appName, "code"); + const exportEnvCommand = getExportEnvCommand(compose); - const newCompose = await writeDomainsToCompose(compose, domains); - const logContent = ` + const newCompose = await writeDomainsToCompose(compose, domains); + const logContent = ` App Name: ${appName} Build Compose 🐳 Detected: ${mounts.length} mounts 📂 @@ -32,17 +32,17 @@ Command: docker ${command} Source Type: docker ${sourceType} ✅ Compose Type: ${composeType} ✅`; - const logBox = boxen(logContent, { - padding: { - left: 1, - right: 1, - bottom: 1, - }, - width: 80, - borderStyle: "double", - }); + const logBox = boxen(logContent, { + padding: { + left: 1, + right: 1, + bottom: 1, + }, + width: 80, + borderStyle: "double", + }); - const bashCommand = ` + const bashCommand = ` set -e { echo "${logBox}"; @@ -64,81 +64,81 @@ Compose Type: ${composeType} ✅`; } `; - return bashCommand; + return bashCommand; }; const sanitizeCommand = (command: string) => { - const sanitizedCommand = command.trim(); + const sanitizedCommand = command.trim(); - const parts = sanitizedCommand.split(/\s+/); + const parts = sanitizedCommand.split(/\s+/); - const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1")); + const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1")); - return restCommand.join(" "); + return restCommand.join(" "); }; export const createCommand = (compose: ComposeNested) => { - const { composeType, appName, sourceType } = compose; - if (compose.command) { - return `${sanitizeCommand(compose.command)}`; - } + const { composeType, appName, sourceType } = compose; + if (compose.command) { + return `${sanitizeCommand(compose.command)}`; + } - const path = - sourceType === "raw" ? "docker-compose.yml" : compose.composePath; - let command = ""; + const path = + sourceType === "raw" ? "docker-compose.yml" : compose.composePath; + let command = ""; - if (composeType === "docker-compose") { - command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`; - } else if (composeType === "stack") { - command = `stack deploy -c ${path} ${appName} --prune --with-registry-auth`; - } + if (composeType === "docker-compose") { + command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`; + } else if (composeType === "stack") { + command = `stack deploy -c ${path} ${appName} --prune --with-registry-auth`; + } - return command; + return command; }; export const getCreateEnvFileCommand = (compose: ComposeNested) => { - const { COMPOSE_PATH } = paths(!!compose.serverId); - const { env, composePath, appName } = compose; - const composeFilePath = - join(COMPOSE_PATH, appName, "code", composePath) || - join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); + const { COMPOSE_PATH } = paths(!!compose.serverId); + const { env, composePath, appName } = compose; + const composeFilePath = + join(COMPOSE_PATH, appName, "code", composePath) || + join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); - const envFilePath = join(dirname(composeFilePath), ".env"); + const envFilePath = join(dirname(composeFilePath), ".env"); - let envContent = `APP_NAME=${appName}\n`; - envContent += env || ""; - if (!envContent.includes("DOCKER_CONFIG")) { - envContent += "\nDOCKER_CONFIG=/root/.docker"; - } + let envContent = `APP_NAME=${appName}\n`; + envContent += env || ""; + if (!envContent.includes("DOCKER_CONFIG")) { + envContent += "\nDOCKER_CONFIG=/root/.docker"; + } - if (compose.randomize) { - envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; - } + if (compose.randomize) { + envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; + } - const envFileContent = prepareEnvironmentVariables( - envContent, - compose.environment.project.env, - compose.environment.env, - ).join("\n"); + const envFileContent = prepareEnvironmentVariables( + envContent, + compose.environment.project.env, + compose.environment.env, + ).join("\n"); - const encodedContent = encodeBase64(envFileContent); - return ` + const encodedContent = encodeBase64(envFileContent); + return ` touch ${envFilePath}; echo "${encodedContent}" | base64 -d > "${envFilePath}"; `; }; const getExportEnvCommand = (compose: ComposeNested) => { - if (compose.composeType !== "stack") return ""; + if (compose.composeType !== "stack") return ""; - const envVars = getEnvironmentVariablesObject( - compose.env, - compose.environment.project.env, - compose.environment.env, - ); - const exports = Object.entries(envVars) - .map(([key, value]) => `${key}=${quote([value])}`) - .join(" "); + const envVars = getEnvironmentVariablesObject( + compose.env, + compose.environment.project.env, + compose.environment.env, + ); + const exports = Object.entries(envVars) + .map(([key, value]) => `${key}=${quote([value])}`) + .join(" "); - return exports ? `${exports}` : ""; + return exports ? `${exports}` : ""; }; diff --git a/packages/server/src/utils/builders/docker-file.ts b/packages/server/src/utils/builders/docker-file.ts index f2fedf461..b20e3f170 100644 --- a/packages/server/src/utils/builders/docker-file.ts +++ b/packages/server/src/utils/builders/docker-file.ts @@ -1,90 +1,90 @@ import { - getEnvironmentVariablesObject, - prepareEnvironmentVariablesForShell, + getEnvironmentVariablesObject, + prepareEnvironmentVariablesForShell, } from "@dokploy/server/utils/docker/utils"; import { quote } from "shell-quote"; import { - getBuildAppDirectory, - getDockerContextPath, + getBuildAppDirectory, + getDockerContextPath, } from "../filesystem/directory"; import type { ApplicationNested } from "."; import { createEnvFileCommand } from "./utils"; export const getDockerCommand = (application: ApplicationNested) => { - const { - appName, - env, - publishDirectory, - buildArgs, - buildSecrets, - dockerBuildStage, - cleanCache, - createEnvFile, - } = application; - const dockerFilePath = getBuildAppDirectory(application); + const { + appName, + env, + publishDirectory, + buildArgs, + buildSecrets, + dockerBuildStage, + cleanCache, + createEnvFile, + } = application; + const dockerFilePath = getBuildAppDirectory(application); - try { - const image = `${appName}`; + try { + const image = `${appName}`; - const defaultContextPath = - dockerFilePath.substring(0, dockerFilePath.lastIndexOf("/") + 1) || "."; + const defaultContextPath = + dockerFilePath.substring(0, dockerFilePath.lastIndexOf("/") + 1) || "."; - const dockerContextPath = - getDockerContextPath(application) || defaultContextPath; + const dockerContextPath = + getDockerContextPath(application) || defaultContextPath; - const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."]; + const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."]; - if (dockerBuildStage) { - commandArgs.push("--target", dockerBuildStage); - } + if (dockerBuildStage) { + commandArgs.push("--target", dockerBuildStage); + } - if (cleanCache) { - commandArgs.push("--no-cache"); - } + if (cleanCache) { + commandArgs.push("--no-cache"); + } - const args = prepareEnvironmentVariablesForShell( - buildArgs, - application.environment.project.env, - application.environment.env, - ); + const args = prepareEnvironmentVariablesForShell( + buildArgs, + application.environment.project.env, + application.environment.env, + ); - for (const arg of args) { - commandArgs.push("--build-arg", arg); - } + for (const arg of args) { + commandArgs.push("--build-arg", arg); + } - const secrets = getEnvironmentVariablesObject( - buildSecrets, - application.environment.project.env, - application.environment.env, - ); + const secrets = getEnvironmentVariablesObject( + buildSecrets, + application.environment.project.env, + application.environment.env, + ); - const joinedSecrets = Object.entries(secrets) - .map(([key, value]) => `${key}=${quote([value])}`) - .join(" "); + const joinedSecrets = Object.entries(secrets) + .map(([key, value]) => `${key}=${quote([value])}`) + .join(" "); - /* + /* Do not generate an environment file when publishDirectory is specified, as it could be publicly exposed. Also respect the createEnvFile flag. */ - let command = ""; - if (!publishDirectory && createEnvFile) { - command += createEnvFileCommand( - dockerFilePath, - env, - application.environment.project.env, - application.environment.env, - ); - } + let command = ""; + if (!publishDirectory && createEnvFile) { + command += createEnvFileCommand( + dockerFilePath, + env, + application.environment.project.env, + application.environment.env, + ); + } - for (const key in secrets) { - // Although buildx is smart enough to know we may be referring to an environment variable name, - // we still make sure it doesn't fall back to `type=file`. - // See: https://docs.docker.com/reference/cli/docker/buildx/build/#secret - commandArgs.push("--secret", `type=env,id=${key}`); - } + for (const key in secrets) { + // Although buildx is smart enough to know we may be referring to an environment variable name, + // we still make sure it doesn't fall back to `type=file`. + // See: https://docs.docker.com/reference/cli/docker/buildx/build/#secret + commandArgs.push("--secret", `type=env,id=${key}`); + } - command += ` + command += ` echo "Building ${appName}" ; cd ${dockerContextPath} || { echo "❌ The path ${dockerContextPath} does not exist" ; @@ -98,8 +98,8 @@ ${joinedSecrets} docker ${commandArgs.join(" ")} || { echo "✅ Docker build completed." ; `; - return command; - } catch (error) { - throw error; - } + return command; + } catch (error) { + throw error; + } }; From 9a1bee5287c9c7f57c6113a6fb15ae6243b8719b Mon Sep 17 00:00:00 2001 From: Tam Nguyen Date: Mon, 30 Mar 2026 09:32:05 +1100 Subject: [PATCH 3/7] fix: more grammar and spelling mistakes --- .../advanced/cluster/show-cluster-settings.tsx | 6 +++--- .../advanced/redirects/handle-redirect.tsx | 6 +++--- .../volume-backups/handle-volume-backups.tsx | 4 ++-- .../free/container/docker-block-chart.tsx | 6 +++--- .../free/container/docker-cpu-chart.tsx | 6 +++--- .../free/container/docker-disk-chart.tsx | 6 +++--- .../free/container/docker-memory-chart.tsx | 6 +++--- .../free/container/docker-network-chart.tsx | 6 +++--- .../show-free-container-monitoring.tsx | 18 +++++++++--------- .../git/gitlab/add-gitlab-provider.tsx | 2 +- .../git/gitlab/edit-gitlab-provider.tsx | 2 +- .../settings/servers/show-servers.tsx | 4 ++-- .../welcome-stripe/welcome-subscription.tsx | 2 +- .../dashboard/settings/users/change-role.tsx | 2 +- .../dashboard/settings/users/show-users.tsx | 2 +- apps/dokploy/components/ui/breadcrumb.tsx | 2 +- .../dokploy/server/api/routers/organization.ts | 4 ++-- apps/dokploy/server/api/trpc.ts | 2 +- 18 files changed, 43 insertions(+), 43 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx b/apps/dokploy/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx index 02db06345..95f849480 100644 --- a/apps/dokploy/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx @@ -40,12 +40,12 @@ interface Props { type: "application" | "mariadb" | "mongo" | "mysql" | "postgres" | "redis"; } -const AddRedirectchema = z.object({ +const AddRedirectSchema = z.object({ replicas: z.number().min(1, "Replicas must be at least 1"), registryId: z.string().optional(), }); -type AddCommand = z.infer; +type AddCommand = z.infer; export const ShowClusterSettings = ({ id, type }: Props) => { const queryMap = { @@ -87,7 +87,7 @@ export const ShowClusterSettings = ({ id, type }: Props) => { : {}), replicas: data?.replicas || 1, }, - resolver: zodResolver(AddRedirectchema), + resolver: zodResolver(AddRedirectSchema), }); useEffect(() => { diff --git a/apps/dokploy/components/dashboard/application/advanced/redirects/handle-redirect.tsx b/apps/dokploy/components/dashboard/application/advanced/redirects/handle-redirect.tsx index 603a6d6c8..683e0ebba 100644 --- a/apps/dokploy/components/dashboard/application/advanced/redirects/handle-redirect.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/redirects/handle-redirect.tsx @@ -37,13 +37,13 @@ import { Separator } from "@/components/ui/separator"; import { Switch } from "@/components/ui/switch"; import { api } from "@/utils/api"; -const AddRedirectchema = z.object({ +const AddRedirectSchema = z.object({ regex: z.string().min(1, "Regex required"), permanent: z.boolean().default(false), replacement: z.string().min(1, "Replacement required"), }); -type AddRedirect = z.infer; +type AddRedirect = z.infer; // Default presets const redirectPresets = [ @@ -110,7 +110,7 @@ export const HandleRedirect = ({ regex: "", replacement: "", }, - resolver: zodResolver(AddRedirectchema), + resolver: zodResolver(AddRedirectSchema), }); useEffect(() => { diff --git a/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx b/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx index 0d87080d7..f3d60f27f 100644 --- a/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx +++ b/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx @@ -483,7 +483,7 @@ export const HandleVolumeBackups = ({ - Choose the volume to backup, if you dont see the + Choose the volume to backup. If you do not see the volume here, you can type the volume name manually @@ -518,7 +518,7 @@ export const HandleVolumeBackups = ({ - Choose the volume to backup, if you dont see the volume + Choose the volume to backup. If you do not see the volume here, you can type the volume name manually diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-block-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-block-chart.tsx index 718ddafa4..6dc5cd90c 100644 --- a/apps/dokploy/components/dashboard/monitoring/free/container/docker-block-chart.tsx +++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-block-chart.tsx @@ -11,11 +11,11 @@ import { import type { DockerStatsJSON } from "./show-free-container-monitoring"; interface Props { - acummulativeData: DockerStatsJSON["block"]; + accumulativeData: DockerStatsJSON["block"]; } -export const DockerBlockChart = ({ acummulativeData }: Props) => { - const transformedData = acummulativeData.map((item, index) => { +export const DockerBlockChart = ({ accumulativeData }: Props) => { + const transformedData = accumulativeData.map((item, index) => { return { time: item.time, name: `Point ${index + 1}`, diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-cpu-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-cpu-chart.tsx index c24a63638..67404268b 100644 --- a/apps/dokploy/components/dashboard/monitoring/free/container/docker-cpu-chart.tsx +++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-cpu-chart.tsx @@ -11,11 +11,11 @@ import { import type { DockerStatsJSON } from "./show-free-container-monitoring"; interface Props { - acummulativeData: DockerStatsJSON["cpu"]; + accumulativeData: DockerStatsJSON["cpu"]; } -export const DockerCpuChart = ({ acummulativeData }: Props) => { - const transformedData = acummulativeData.map((item, index) => { +export const DockerCpuChart = ({ accumulativeData }: Props) => { + const transformedData = accumulativeData.map((item, index) => { return { name: `Point ${index + 1}`, time: item.time, diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-disk-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-disk-chart.tsx index 5fe62154c..58cefe6b3 100644 --- a/apps/dokploy/components/dashboard/monitoring/free/container/docker-disk-chart.tsx +++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-disk-chart.tsx @@ -11,12 +11,12 @@ import { import type { DockerStatsJSON } from "./show-free-container-monitoring"; interface Props { - acummulativeData: DockerStatsJSON["disk"]; + accumulativeData: DockerStatsJSON["disk"]; diskTotal: number; } -export const DockerDiskChart = ({ acummulativeData, diskTotal }: Props) => { - const transformedData = acummulativeData.map((item, index) => { +export const DockerDiskChart = ({ accumulativeData, diskTotal }: Props) => { + const transformedData = accumulativeData.map((item, index) => { return { time: item.time, name: `Point ${index + 1}`, diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-memory-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-memory-chart.tsx index 34a3913a7..226623fa2 100644 --- a/apps/dokploy/components/dashboard/monitoring/free/container/docker-memory-chart.tsx +++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-memory-chart.tsx @@ -12,15 +12,15 @@ import type { DockerStatsJSON } from "./show-free-container-monitoring"; import { convertMemoryToBytes } from "./show-free-container-monitoring"; interface Props { - acummulativeData: DockerStatsJSON["memory"]; + accumulativeData: DockerStatsJSON["memory"]; memoryLimitGB: number; } export const DockerMemoryChart = ({ - acummulativeData, + accumulativeData, memoryLimitGB, }: Props) => { - const transformedData = acummulativeData.map((item, index) => { + const transformedData = accumulativeData.map((item, index) => { return { time: item.time, name: `Point ${index + 1}`, diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-network-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-network-chart.tsx index 5e2414cea..8dafcb465 100644 --- a/apps/dokploy/components/dashboard/monitoring/free/container/docker-network-chart.tsx +++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-network-chart.tsx @@ -11,11 +11,11 @@ import { import type { DockerStatsJSON } from "./show-free-container-monitoring"; interface Props { - acummulativeData: DockerStatsJSON["network"]; + accumulativeData: DockerStatsJSON["network"]; } -export const DockerNetworkChart = ({ acummulativeData }: Props) => { - const transformedData = acummulativeData.map((item, index) => { +export const DockerNetworkChart = ({ accumulativeData }: Props) => { + const transformedData = accumulativeData.map((item, index) => { return { time: item.time, name: `Point ${index + 1}`, diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx index 42bb361bb..6e572c224 100644 --- a/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx +++ b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx @@ -124,7 +124,7 @@ export const ContainerFreeMonitoring = ({ refetchOnWindowFocus: false, }, ); - const [acummulativeData, setAcummulativeData] = useState({ + const [accumulativeData, setAccumulativeData] = useState({ cpu: [], memory: [], block: [], @@ -136,7 +136,7 @@ export const ContainerFreeMonitoring = ({ useEffect(() => { setCurrentData(defaultData); - setAcummulativeData({ + setAccumulativeData({ cpu: [], memory: [], block: [], @@ -155,7 +155,7 @@ export const ContainerFreeMonitoring = ({ network: data.network[data.network.length - 1] ?? currentData.network, disk: data.disk[data.disk.length - 1] ?? currentData.disk, }); - setAcummulativeData({ + setAccumulativeData({ block: data?.block || [], cpu: data?.cpu || [], disk: data?.disk || [], @@ -184,7 +184,7 @@ export const ContainerFreeMonitoring = ({ setCurrentData(data); const MAX_DATA_POINTS = 300; - setAcummulativeData((prevData) => ({ + setAccumulativeData((prevData) => ({ cpu: [...prevData.cpu, data.cpu].slice(-MAX_DATA_POINTS), memory: [...prevData.memory, data.memory].slice(-MAX_DATA_POINTS), block: [...prevData.block, data.block].slice(-MAX_DATA_POINTS), @@ -228,7 +228,7 @@ export const ContainerFreeMonitoring = ({ )} className="w-[100%]" /> - +
    @@ -252,7 +252,7 @@ export const ContainerFreeMonitoring = ({ className="w-[100%]" />
    @@ -294,7 +294,7 @@ export const ContainerFreeMonitoring = ({ {`Read: ${currentData.block.value.readMb} / Write: ${currentData.block.value.writeMb} `} - +
@@ -307,7 +307,7 @@ export const ContainerFreeMonitoring = ({ {`In MB: ${currentData.network.value.inputMb} / Out MB: ${currentData.network.value.outputMb} `} - + diff --git a/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx index 7c637f5ef..863d5d0f1 100644 --- a/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx @@ -283,7 +283,7 @@ export const AddGitlabProvider = () => { diff --git a/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx index e48df084b..73c3b4523 100644 --- a/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx @@ -192,7 +192,7 @@ export const EditGitlabProvider = ({ gitlabId }: Props) => { diff --git a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx index 7342aafb4..1326c554a 100644 --- a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx @@ -48,7 +48,7 @@ import { ShowMonitoringModal } from "./show-monitoring-modal"; import { ShowSchedulesModal } from "./show-schedules-modal"; import { ShowSwarmOverviewModal } from "./show-swarm-overview-modal"; import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal"; -import { Welcomesubscription } from "./welcome-stripe/welcome-subscription"; +import { WelcomeSubscription } from "./welcome-stripe/welcome-subscription"; export const ShowServers = () => { const router = useRouter(); @@ -63,7 +63,7 @@ export const ShowServers = () => { return (
- {query?.success && isCloud && } + {query?.success && isCloud && }
diff --git a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-subscription.tsx b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-subscription.tsx index 295b53516..91dce72b9 100644 --- a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-subscription.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-subscription.tsx @@ -51,7 +51,7 @@ export const { useStepper, steps, Scoped } = defineStepper( { id: "complete", title: "Complete", description: "Checkout complete" }, ); -export const Welcomesubscription = () => { +export const WelcomeSubscription = () => { const [showConfetti, setShowConfetti] = useState(false); const stepper = useStepper(); const [isOpen, setIsOpen] = useState(true); diff --git a/apps/dokploy/components/dashboard/settings/users/change-role.tsx b/apps/dokploy/components/dashboard/settings/users/change-role.tsx index 2178284b1..dfa35a28d 100644 --- a/apps/dokploy/components/dashboard/settings/users/change-role.tsx +++ b/apps/dokploy/components/dashboard/settings/users/change-role.tsx @@ -153,7 +153,7 @@ export const ChangeRole = ({ memberId, currentRole, userEmail }: Props) => { )}
- Note: Owner role is intransferible. + Note: Owner role is nontransferable. diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx index 75aa839f9..23356dcd4 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx @@ -122,7 +122,7 @@ export const ShowUsers = () => { // Can change role based on hierarchy: // - Owner: Can change anyone's role (except themselves and other owners) // - Admin: Can only change member/custom roles (not other admins or owners) - // - Owner role is intransferible + // - Owner role is nontransferable const canChangeRole = member.role !== "owner" && member.user.id !== session?.user?.id && diff --git a/apps/dokploy/components/ui/breadcrumb.tsx b/apps/dokploy/components/ui/breadcrumb.tsx index a189f6fa1..8bf95ea32 100644 --- a/apps/dokploy/components/ui/breadcrumb.tsx +++ b/apps/dokploy/components/ui/breadcrumb.tsx @@ -101,7 +101,7 @@ const BreadcrumbEllipsis = ({ More ); -BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"; +BreadcrumbEllipsis.displayName = "BreadcrumbEllipsis"; export { Breadcrumb, diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts index 2f7d45287..47d0fc75f 100644 --- a/apps/dokploy/server/api/routers/organization.ts +++ b/apps/dokploy/server/api/routers/organization.ts @@ -409,11 +409,11 @@ export const organizationRouter = createTRPCRouter({ }); } - // Owner role is intransferible - cannot change to or from owner + // Owner role is nontransferable - cannot change to or from owner if (target.role === "owner" || input.role === "owner") { throw new TRPCError({ code: "FORBIDDEN", - message: "The owner role is intransferible", + message: "The owner role is nontransferable", }); } diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index 486640349..d0b43e76f 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -106,7 +106,7 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { * 2. INITIALIZATION * * This is where the tRPC API is initialized, connecting the context and transformer. We also parse - * ZodErrors so that you get typesafety on the frontend if your procedure fails due to validation + * ZodErrors so that you get type safety on the frontend if your procedure fails due to validation * errors on the backend. */ From f83ab2923d399b725a07f5ca755e3bbd33ddc300 Mon Sep 17 00:00:00 2001 From: Tam Nguyen Date: Mon, 30 Mar 2026 09:33:38 +1100 Subject: [PATCH 4/7] stlye: format and lint --- .../permissions/enterprise-only-resources.test.ts | 2 +- .../application/deployments/show-deployments.tsx | 2 +- .../components/dashboard/application/patches/index.ts | 2 +- .../components/dashboard/deployments/show-queue-table.tsx | 2 +- .../settings/destination/handle-destinations.tsx | 8 ++++---- .../settings/notifications/handle-notifications.tsx | 2 +- apps/dokploy/lib/auth-client.ts | 2 +- apps/dokploy/pages/api/deploy/compose/[refreshToken].ts | 2 +- apps/dokploy/pages/dashboard/settings/users.tsx | 4 ++-- apps/dokploy/server/api/routers/ai.ts | 2 +- apps/dokploy/server/api/routers/backup.ts | 2 +- apps/dokploy/server/api/routers/certificate.ts | 2 +- apps/dokploy/server/api/routers/compose.ts | 4 ++-- apps/dokploy/server/api/routers/git-provider.ts | 2 +- apps/dokploy/server/api/routers/mongo.ts | 7 ++++--- apps/dokploy/server/api/routers/mysql.ts | 4 ++-- apps/dokploy/server/api/routers/organization.ts | 2 +- apps/dokploy/server/api/routers/postgres.ts | 7 ++++--- apps/dokploy/server/api/routers/redis.ts | 7 ++++--- apps/dokploy/server/api/routers/registry.ts | 2 +- apps/dokploy/server/api/routers/schedule.ts | 2 +- apps/dokploy/server/api/routers/server.ts | 2 +- apps/dokploy/server/api/routers/ssh-key.ts | 2 +- apps/dokploy/server/api/utils/audit.ts | 2 +- packages/server/auth-schema2.ts | 6 +++--- packages/server/src/db/schema/index.ts | 2 +- packages/server/src/db/schema/volume-backups.ts | 2 +- packages/server/src/services/deployment.ts | 2 +- packages/server/src/services/proprietary/audit-log.ts | 2 +- packages/server/src/utils/providers/github.ts | 2 +- packages/server/src/utils/providers/gitlab.ts | 2 +- 31 files changed, 48 insertions(+), 45 deletions(-) diff --git a/apps/dokploy/__test__/permissions/enterprise-only-resources.test.ts b/apps/dokploy/__test__/permissions/enterprise-only-resources.test.ts index 3138085e3..bb6f5f18b 100644 --- a/apps/dokploy/__test__/permissions/enterprise-only-resources.test.ts +++ b/apps/dokploy/__test__/permissions/enterprise-only-resources.test.ts @@ -1,8 +1,8 @@ -import { describe, it, expect } from "vitest"; import { enterpriseOnlyResources, statements, } from "@dokploy/server/lib/access-control"; +import { describe, expect, it } from "vitest"; const FREE_TIER_RESOURCES = [ "organization", diff --git a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx index 3cecef1ec..ccf2564b0 100644 --- a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx +++ b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx @@ -1,3 +1,4 @@ +import copy from "copy-to-clipboard"; import { ChevronDown, ChevronUp, @@ -11,7 +12,6 @@ import { } from "lucide-react"; import React, { useEffect, useMemo, useState } from "react"; import { toast } from "sonner"; -import copy from "copy-to-clipboard"; import { AlertBlock } from "@/components/shared/alert-block"; import { DateTooltip } from "@/components/shared/date-tooltip"; import { DialogAction } from "@/components/shared/dialog-action"; diff --git a/apps/dokploy/components/dashboard/application/patches/index.ts b/apps/dokploy/components/dashboard/application/patches/index.ts index 1854bd3e5..053e644b7 100644 --- a/apps/dokploy/components/dashboard/application/patches/index.ts +++ b/apps/dokploy/components/dashboard/application/patches/index.ts @@ -1,2 +1,2 @@ -export * from "./show-patches"; export * from "./patch-editor"; +export * from "./show-patches"; diff --git a/apps/dokploy/components/dashboard/deployments/show-queue-table.tsx b/apps/dokploy/components/dashboard/deployments/show-queue-table.tsx index e46b33a6a..22b132f16 100644 --- a/apps/dokploy/components/dashboard/deployments/show-queue-table.tsx +++ b/apps/dokploy/components/dashboard/deployments/show-queue-table.tsx @@ -1,8 +1,8 @@ "use client"; import type { inferRouterOutputs } from "@trpc/server"; -import Link from "next/link"; import { ArrowRight, ListTodo, Loader2, XCircle } from "lucide-react"; +import Link from "next/link"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { diff --git a/apps/dokploy/components/dashboard/settings/destination/handle-destinations.tsx b/apps/dokploy/components/dashboard/settings/destination/handle-destinations.tsx index 25a3a1048..e7ecf92b2 100644 --- a/apps/dokploy/components/dashboard/settings/destination/handle-destinations.tsx +++ b/apps/dokploy/components/dashboard/settings/destination/handle-destinations.tsx @@ -1,3 +1,7 @@ +import { + ADDITIONAL_FLAG_ERROR, + ADDITIONAL_FLAG_REGEX, +} from "@dokploy/server/db/validations/destination"; import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema"; import { PenBoxIcon, PlusIcon, Trash2 } from "lucide-react"; import { useEffect, useState } from "react"; @@ -35,10 +39,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({ diff --git a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx index 28d762c1c..0617aa68d 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx @@ -12,9 +12,9 @@ import { toast } from "sonner"; import { z } from "zod"; import { DiscordIcon, - MattermostIcon, GotifyIcon, LarkIcon, + MattermostIcon, NtfyIcon, PushoverIcon, ResendIcon, diff --git a/apps/dokploy/lib/auth-client.ts b/apps/dokploy/lib/auth-client.ts index 6d786cc11..864ba1f68 100644 --- a/apps/dokploy/lib/auth-client.ts +++ b/apps/dokploy/lib/auth-client.ts @@ -1,5 +1,5 @@ -import { ssoClient } from "@better-auth/sso/client"; import { apiKeyClient } from "@better-auth/api-key/client"; +import { ssoClient } from "@better-auth/sso/client"; import { adminClient, inferAdditionalFields, diff --git a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts index c998e83b9..640a2531d 100644 --- a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts @@ -8,8 +8,8 @@ import { myQueue } from "@/server/queues/queueSetup"; import { deploy } from "@/server/utils/deploy"; import { extractBranchName, - extractCommittedPaths, extractCommitMessage, + extractCommittedPaths, extractHash, getProviderByHeader, } from "../[refreshToken]"; diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index 43c014279..a3bd953d1 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -3,10 +3,10 @@ import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; import type { ReactElement } from "react"; import superjson from "superjson"; -import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { ManageCustomRoles } from "@/components/proprietary/roles/manage-custom-roles"; import { ShowInvitations } from "@/components/dashboard/settings/users/show-invitations"; import { ShowUsers } from "@/components/dashboard/settings/users/show-users"; +import { DashboardLayout } from "@/components/layouts/dashboard-layout"; +import { ManageCustomRoles } from "@/components/proprietary/roles/manage-custom-roles"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; diff --git a/apps/dokploy/server/api/routers/ai.ts b/apps/dokploy/server/api/routers/ai.ts index b46fcf99a..a4527497d 100644 --- a/apps/dokploy/server/api/routers/ai.ts +++ b/apps/dokploy/server/api/routers/ai.ts @@ -17,11 +17,11 @@ import { suggestVariants, } from "@dokploy/server/services/ai"; import { createComposeByTemplate } from "@dokploy/server/services/compose"; -import { findProjectById } from "@dokploy/server/services/project"; import { addNewService, checkServiceAccess, } from "@dokploy/server/services/permission"; +import { findProjectById } from "@dokploy/server/services/project"; import { getProviderHeaders, getProviderName, diff --git a/apps/dokploy/server/api/routers/backup.ts b/apps/dokploy/server/api/routers/backup.ts index 6d358f631..ad3b40622 100644 --- a/apps/dokploy/server/api/routers/backup.ts +++ b/apps/dokploy/server/api/routers/backup.ts @@ -28,6 +28,7 @@ import { updateBackupById, } from "@dokploy/server"; import { findDestinationById } from "@dokploy/server/services/destination"; +import { checkServicePermissionAndAccess } from "@dokploy/server/services/permission"; import { runComposeBackup } from "@dokploy/server/utils/backups/compose"; import { getS3Credentials, @@ -53,7 +54,6 @@ import { protectedProcedure, withPermission, } from "@/server/api/trpc"; -import { checkServicePermissionAndAccess } from "@dokploy/server/services/permission"; import { audit } from "@/server/api/utils/audit"; import { apiCreateBackup, diff --git a/apps/dokploy/server/api/routers/certificate.ts b/apps/dokploy/server/api/routers/certificate.ts index 0ebd33e7f..e506a846b 100644 --- a/apps/dokploy/server/api/routers/certificate.ts +++ b/apps/dokploy/server/api/routers/certificate.ts @@ -7,8 +7,8 @@ import { import { db } from "@dokploy/server/db"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; -import { audit } from "@/server/api/utils/audit"; import { createTRPCRouter, withPermission } from "@/server/api/trpc"; +import { audit } from "@/server/api/utils/audit"; import { apiCreateCertificate, apiFindCertificate, diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 0d3782eab..6e272a6cc 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -31,13 +31,13 @@ import { updateCompose, updateDeploymentStatus, } from "@dokploy/server"; +import { db } from "@dokploy/server/db"; import { addNewService, checkServiceAccess, checkServicePermissionAndAccess, findMemberByUserId, } from "@dokploy/server/services/permission"; -import { db } from "@dokploy/server/db"; import { type CompleteTemplate, fetchTemplateFiles, @@ -75,8 +75,8 @@ import { } from "@/server/queues/queueSetup"; import { cancelDeployment, deploy } from "@/server/utils/deploy"; import { generatePassword } from "@/templates/utils"; -import { audit } from "../utils/audit"; import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc"; +import { audit } from "../utils/audit"; export const composeRouter = createTRPCRouter({ create: protectedProcedure diff --git a/apps/dokploy/server/api/routers/git-provider.ts b/apps/dokploy/server/api/routers/git-provider.ts index b0aa8627d..0b186ae9a 100644 --- a/apps/dokploy/server/api/routers/git-provider.ts +++ b/apps/dokploy/server/api/routers/git-provider.ts @@ -2,12 +2,12 @@ import { findGitProviderById, removeGitProvider } from "@dokploy/server"; import { db } from "@dokploy/server/db"; import { TRPCError } from "@trpc/server"; import { and, desc, eq } from "drizzle-orm"; -import { audit } from "@/server/api/utils/audit"; import { createTRPCRouter, protectedProcedure, withPermission, } from "@/server/api/trpc"; +import { audit } from "@/server/api/utils/audit"; import { apiRemoveGitProvider, gitProvider } from "@/server/db/schema"; export const gitProviderRouter = createTRPCRouter({ diff --git a/apps/dokploy/server/api/routers/mongo.ts b/apps/dokploy/server/api/routers/mongo.ts index a64535e24..37d8c23f6 100644 --- a/apps/dokploy/server/api/routers/mongo.ts +++ b/apps/dokploy/server/api/routers/mongo.ts @@ -17,18 +17,18 @@ import { stopServiceRemote, updateMongoById, } from "@dokploy/server"; +import { db } from "@dokploy/server/db"; import { addNewService, checkServiceAccess, checkServicePermissionAndAccess, findMemberByUserId, } from "@dokploy/server/services/permission"; -import { db } from "@dokploy/server/db"; import { TRPCError } from "@trpc/server"; import { and, desc, eq, ilike, or, sql } from "drizzle-orm"; import { z } from "zod"; -import { audit } from "@/server/api/utils/audit"; import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; +import { audit } from "@/server/api/utils/audit"; import { apiChangeMongoStatus, apiCreateMongo, @@ -39,9 +39,10 @@ import { apiSaveEnvironmentVariablesMongo, apiSaveExternalPortMongo, apiUpdateMongo, + environments, mongo as mongoTable, + projects, } from "@/server/db/schema"; -import { environments, projects } from "@/server/db/schema"; import { cancelJobs } from "@/server/utils/backup"; export const mongoRouter = createTRPCRouter({ create: protectedProcedure diff --git a/apps/dokploy/server/api/routers/mysql.ts b/apps/dokploy/server/api/routers/mysql.ts index abb0f97a7..e611dab1d 100644 --- a/apps/dokploy/server/api/routers/mysql.ts +++ b/apps/dokploy/server/api/routers/mysql.ts @@ -17,18 +17,18 @@ import { stopServiceRemote, updateMySqlById, } from "@dokploy/server"; +import { db } from "@dokploy/server/db"; import { addNewService, checkServiceAccess, checkServicePermissionAndAccess, findMemberByUserId, } from "@dokploy/server/services/permission"; -import { db } from "@dokploy/server/db"; import { TRPCError } from "@trpc/server"; import { and, desc, eq, ilike, or, sql } from "drizzle-orm"; import { z } from "zod"; -import { audit } from "@/server/api/utils/audit"; import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; +import { audit } from "@/server/api/utils/audit"; import { apiChangeMySqlStatus, apiCreateMySql, diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts index 47d0fc75f..2f9da6d71 100644 --- a/apps/dokploy/server/api/routers/organization.ts +++ b/apps/dokploy/server/api/routers/organization.ts @@ -1,10 +1,10 @@ import { db } from "@dokploy/server/db"; import { IS_CLOUD } from "@dokploy/server/index"; -import { audit } from "@/server/api/utils/audit"; import { TRPCError } from "@trpc/server"; import { and, desc, eq, exists } from "drizzle-orm"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { audit } from "@/server/api/utils/audit"; import { invitation, member, diff --git a/apps/dokploy/server/api/routers/postgres.ts b/apps/dokploy/server/api/routers/postgres.ts index 3b3cfd208..44984ee43 100644 --- a/apps/dokploy/server/api/routers/postgres.ts +++ b/apps/dokploy/server/api/routers/postgres.ts @@ -18,18 +18,18 @@ import { stopServiceRemote, updatePostgresById, } from "@dokploy/server"; +import { db } from "@dokploy/server/db"; import { addNewService, checkServiceAccess, checkServicePermissionAndAccess, findMemberByUserId, } from "@dokploy/server/services/permission"; -import { db } from "@dokploy/server/db"; import { TRPCError } from "@trpc/server"; import { and, desc, eq, ilike, or, sql } from "drizzle-orm"; import { z } from "zod"; -import { audit } from "@/server/api/utils/audit"; import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; +import { audit } from "@/server/api/utils/audit"; import { apiChangePostgresStatus, apiCreatePostgres, @@ -40,9 +40,10 @@ import { apiSaveEnvironmentVariablesPostgres, apiSaveExternalPortPostgres, apiUpdatePostgres, + environments, postgres as postgresTable, + projects, } from "@/server/db/schema"; -import { environments, projects } from "@/server/db/schema"; import { cancelJobs } from "@/server/utils/backup"; export const postgresRouter = createTRPCRouter({ diff --git a/apps/dokploy/server/api/routers/redis.ts b/apps/dokploy/server/api/routers/redis.ts index 01d922aa4..c2c65878e 100644 --- a/apps/dokploy/server/api/routers/redis.ts +++ b/apps/dokploy/server/api/routers/redis.ts @@ -16,18 +16,18 @@ import { stopServiceRemote, updateRedisById, } from "@dokploy/server"; +import { db } from "@dokploy/server/db"; import { addNewService, checkServiceAccess, checkServicePermissionAndAccess, findMemberByUserId, } from "@dokploy/server/services/permission"; -import { db } from "@dokploy/server/db"; import { TRPCError } from "@trpc/server"; import { and, desc, eq, ilike, or, sql } from "drizzle-orm"; import { z } from "zod"; -import { audit } from "@/server/api/utils/audit"; import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; +import { audit } from "@/server/api/utils/audit"; import { apiChangeRedisStatus, apiCreateRedis, @@ -38,9 +38,10 @@ import { apiSaveEnvironmentVariablesRedis, apiSaveExternalPortRedis, apiUpdateRedis, + environments, + projects, redis as redisTable, } from "@/server/db/schema"; -import { environments, projects } from "@/server/db/schema"; export const redisRouter = createTRPCRouter({ create: protectedProcedure .input(apiCreateRedis) diff --git a/apps/dokploy/server/api/routers/registry.ts b/apps/dokploy/server/api/routers/registry.ts index 7e2174419..1b156c069 100644 --- a/apps/dokploy/server/api/routers/registry.ts +++ b/apps/dokploy/server/api/routers/registry.ts @@ -10,6 +10,7 @@ import { import { db } from "@dokploy/server/db"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; +import { audit } from "@/server/api/utils/audit"; import { apiCreateRegistry, apiFindOneRegistry, @@ -19,7 +20,6 @@ import { apiUpdateRegistry, registry, } from "@/server/db/schema"; -import { audit } from "@/server/api/utils/audit"; import { createTRPCRouter, withPermission } from "../trpc"; export const registryRouter = createTRPCRouter({ create: withPermission("registry", "create") diff --git a/apps/dokploy/server/api/routers/schedule.ts b/apps/dokploy/server/api/routers/schedule.ts index 2563fd7ac..40a7202a4 100644 --- a/apps/dokploy/server/api/routers/schedule.ts +++ b/apps/dokploy/server/api/routers/schedule.ts @@ -7,6 +7,7 @@ import { updateScheduleSchema, } from "@dokploy/server/db/schema/schedule"; import { runCommand } from "@dokploy/server/index"; +import { checkServicePermissionAndAccess } from "@dokploy/server/services/permission"; import { createSchedule, deleteSchedule, @@ -18,7 +19,6 @@ import { desc, eq } from "drizzle-orm"; import { z } from "zod"; import { audit } from "@/server/api/utils/audit"; import { removeJob, schedule } from "@/server/utils/backup"; -import { checkServicePermissionAndAccess } from "@dokploy/server/services/permission"; import { createTRPCRouter, protectedProcedure } from "../trpc"; export const scheduleRouter = createTRPCRouter({ create: protectedProcedure diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index bfad8836a..785be19b8 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -21,12 +21,12 @@ import { observable } from "@trpc/server/observable"; import { and, desc, eq, getTableColumns, isNotNull, sql } from "drizzle-orm"; import { z } from "zod"; import { updateServersBasedOnQuantity } from "@/pages/api/stripe/webhook"; -import { audit } from "@/server/api/utils/audit"; import { createTRPCRouter, protectedProcedure, withPermission, } from "@/server/api/trpc"; +import { audit } from "@/server/api/utils/audit"; import { apiCreateServer, apiFindOneServer, diff --git a/apps/dokploy/server/api/routers/ssh-key.ts b/apps/dokploy/server/api/routers/ssh-key.ts index 74aeb5e58..68ab14616 100644 --- a/apps/dokploy/server/api/routers/ssh-key.ts +++ b/apps/dokploy/server/api/routers/ssh-key.ts @@ -8,8 +8,8 @@ import { import { db } from "@dokploy/server/db"; import { TRPCError } from "@trpc/server"; import { desc, eq } from "drizzle-orm"; -import { audit } from "@/server/api/utils/audit"; import { createTRPCRouter, withPermission } from "@/server/api/trpc"; +import { audit } from "@/server/api/utils/audit"; import { apiCreateSshKey, apiFindOneSshKey, diff --git a/apps/dokploy/server/api/utils/audit.ts b/apps/dokploy/server/api/utils/audit.ts index 9f73befbf..64f46dea4 100644 --- a/apps/dokploy/server/api/utils/audit.ts +++ b/apps/dokploy/server/api/utils/audit.ts @@ -1,5 +1,5 @@ -import { createAuditLog } from "@dokploy/server/services/proprietary/audit-log"; import type { AuditAction, AuditResourceType } from "@dokploy/server/db/schema"; +import { createAuditLog } from "@dokploy/server/services/proprietary/audit-log"; interface AuditCtx { user: { id: string; email: string; role: string }; diff --git a/packages/server/auth-schema2.ts b/packages/server/auth-schema2.ts index 9c163c820..cb2202832 100644 --- a/packages/server/auth-schema2.ts +++ b/packages/server/auth-schema2.ts @@ -1,11 +1,11 @@ import { relations } from "drizzle-orm"; import { + boolean, + index, + integer, pgTable, text, timestamp, - boolean, - integer, - index, uniqueIndex, } from "drizzle-orm/pg-core"; diff --git a/packages/server/src/db/schema/index.ts b/packages/server/src/db/schema/index.ts index 7873345ab..a4e613a02 100644 --- a/packages/server/src/db/schema/index.ts +++ b/packages/server/src/db/schema/index.ts @@ -1,7 +1,7 @@ export * from "./account"; export * from "./ai"; -export * from "./audit-log"; export * from "./application"; +export * from "./audit-log"; export * from "./backups"; export * from "./bitbucket"; export * from "./certificate"; diff --git a/packages/server/src/db/schema/volume-backups.ts b/packages/server/src/db/schema/volume-backups.ts index 0a5ecf898..fd3b48253 100644 --- a/packages/server/src/db/schema/volume-backups.ts +++ b/packages/server/src/db/schema/volume-backups.ts @@ -1,6 +1,5 @@ import { relations } from "drizzle-orm"; import { boolean, integer, pgTable, text } from "drizzle-orm/pg-core"; -import { serviceType } from "./mount"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; @@ -11,6 +10,7 @@ import { destinations } from "./destination"; import { libsql } from "./libsql"; import { mariadb } from "./mariadb"; import { mongo } from "./mongo"; +import { serviceType } from "./mount"; import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; diff --git a/packages/server/src/services/deployment.ts b/packages/server/src/services/deployment.ts index 7b6f0c730..a5ff57779 100644 --- a/packages/server/src/services/deployment.ts +++ b/packages/server/src/services/deployment.ts @@ -23,7 +23,7 @@ import { } from "@dokploy/server/utils/process/execAsync"; import { TRPCError } from "@trpc/server"; import { format } from "date-fns"; -import { desc, eq, and, inArray, or, sql } from "drizzle-orm"; +import { and, desc, eq, inArray, or, sql } from "drizzle-orm"; import type { z } from "zod"; import { type Application, diff --git a/packages/server/src/services/proprietary/audit-log.ts b/packages/server/src/services/proprietary/audit-log.ts index 157e75c9b..8cf4e0055 100644 --- a/packages/server/src/services/proprietary/audit-log.ts +++ b/packages/server/src/services/proprietary/audit-log.ts @@ -1,6 +1,6 @@ import { db } from "@dokploy/server/db"; -import { auditLog } from "@dokploy/server/db/schema"; import type { AuditAction, AuditResourceType } from "@dokploy/server/db/schema"; +import { auditLog } from "@dokploy/server/db/schema"; import { hasValidLicense } from "@dokploy/server/services/proprietary/license-key"; import { and, desc, eq, gte, ilike, lte } from "drizzle-orm"; diff --git a/packages/server/src/utils/providers/github.ts b/packages/server/src/utils/providers/github.ts index b32133681..6309cf307 100644 --- a/packages/server/src/utils/providers/github.ts +++ b/packages/server/src/utils/providers/github.ts @@ -5,8 +5,8 @@ import { findGithubById, type Github } from "@dokploy/server/services/github"; import type { InferResultType } from "@dokploy/server/types/with"; import { createAppAuth } from "@octokit/auth-app"; import { TRPCError } from "@trpc/server"; -import type { z } from "zod"; import { Octokit } from "octokit"; +import type { z } from "zod"; export const authGithub = (githubProvider: Github): Octokit => { if (!haveGithubRequirements(githubProvider)) { diff --git a/packages/server/src/utils/providers/gitlab.ts b/packages/server/src/utils/providers/gitlab.ts index e8e4af2a5..df6801a45 100644 --- a/packages/server/src/utils/providers/gitlab.ts +++ b/packages/server/src/utils/providers/gitlab.ts @@ -1,7 +1,6 @@ import { join } from "node:path"; import { paths } from "@dokploy/server/constants"; import type { apiGitlabTestConnection } from "@dokploy/server/db/schema"; -import type { z } from "zod"; import { findGitlabById, type Gitlab, @@ -9,6 +8,7 @@ import { } from "@dokploy/server/services/gitlab"; import type { InferResultType } from "@dokploy/server/types/with"; import { TRPCError } from "@trpc/server"; +import type { z } from "zod"; export const refreshGitlabToken = async (gitlabProviderId: string) => { const gitlabProvider = await findGitlabById(gitlabProviderId); From 4a7e9a200e5f4a45781134daf55211aecba88c5b Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen <86177399+nktnet1@users.noreply.github.com> Date: Mon, 30 Mar 2026 09:52:36 +1100 Subject: [PATCH 5/7] fix: use slug instead of sluggish Update apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../dashboard/settings/git/gitlab/add-gitlab-provider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx index 863d5d0f1..b0ecb7eef 100644 --- a/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx @@ -283,7 +283,7 @@ export const AddGitlabProvider = () => { From dab13a52d6ea5209db09a6bc44d9e46e4be591bf Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen <86177399+nktnet1@users.noreply.github.com> Date: Mon, 30 Mar 2026 09:52:51 +1100 Subject: [PATCH 6/7] fix: use slug instead of sluggish Update apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../dashboard/settings/git/gitlab/edit-gitlab-provider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx index 73c3b4523..27178bff9 100644 --- a/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx @@ -192,7 +192,7 @@ export const EditGitlabProvider = ({ gitlabId }: Props) => { From c4aca74aef98facd8df3f2e0f1338037cf48b61a Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:53:14 +0000 Subject: [PATCH 7/7] [autofix.ci] apply automated fixes --- .../dashboard/settings/git/gitlab/add-gitlab-provider.tsx | 2 +- .../dashboard/settings/git/gitlab/edit-gitlab-provider.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx index b0ecb7eef..b48f8253b 100644 --- a/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/gitlab/add-gitlab-provider.tsx @@ -283,7 +283,7 @@ export const AddGitlabProvider = () => { diff --git a/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx index 27178bff9..43c174055 100644 --- a/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx @@ -192,7 +192,7 @@ export const EditGitlabProvider = ({ gitlabId }: Props) => {