@@ -11,74 +10,67 @@
Dokploy is a free self-hostable Platform as a Service (PaaS) that simplifies the deployment and management of applications and databases.
-
### Features
Dokploy include multiples features to make your life easier.
-
-* **Applications**: Deploy any type of application (Node.js, PHP, Python, Go, Ruby, etc.).
-* **Databases**: Create and manage databases with support for MySQL, PostgreSQL, MongoDB, MariaDB, Redis.
-* **Backups**: Automate backups for databases to a external storage destination.
-* **Docker Compose**: Native support for Docker Compose to manage complex applications.
-* **Multi Node**: Scale applications to multiples nodes using docker swarm to manage the cluster.
-* **Templates**: Deploy in a single click open source templates (Plausible, Pocketbase, Calcom, etc.).
-* **Traefik Integration**: Automatically integrates with Traefik for routing and load balancing.
-* **Real-time Monitoring**: Monitor CPU, memory, storage, and network usage, for every resource.
-* **Docker Management**: Easily deploy and manage Docker containers.
-* **CLI/API**: Manage your applications and databases using the command line or trought the API.
-* **Self-Hosted**: Self-host Dokploy on your VPS.
-
-
-
+- **Applications**: Deploy any type of application (Node.js, PHP, Python, Go, Ruby, etc.).
+- **Databases**: Create and manage databases with support for MySQL, PostgreSQL, MongoDB, MariaDB, Redis.
+- **Backups**: Automate backups for databases to a external storage destination.
+- **Docker Compose**: Native support for Docker Compose to manage complex applications.
+- **Multi Node**: Scale applications to multiples nodes using docker swarm to manage the cluster.
+- **Templates**: Deploy in a single click open source templates (Plausible, Pocketbase, Calcom, etc.).
+- **Traefik Integration**: Automatically integrates with Traefik for routing and load balancing.
+- **Real-time Monitoring**: Monitor CPU, memory, storage, and network usage, for every resource.
+- **Docker Management**: Easily deploy and manage Docker containers.
+- **CLI/API**: Manage your applications and databases using the command line or trought the API.
+- **Self-Hosted**: Self-host Dokploy on your VPS.
## 🚀 Getting Started
To get started run the following command in a VPS:
-
```bash
curl -sSL https://dokploy.com/install.sh | sh
```
-
## 📄 Documentation
For detailed documentation, visit [docs.dokploy.com](https://docs.dokploy.com).
-
## Video Tutorial
+
-
## Donations
If you like dokploy, and want to support the project to cover the costs of hosting, testing and development new features, you can donate to the project using the following link:
Thanks to all the supporters!
-https://opencollective.com/dokploy
+[Dokploy Open Collective](https://opencollective.com/dokploy)
+Organizations:
+

+
+Individuals:

-
## Contributors
-
-
## Support OS
-- Ubuntu 24.04 LTS
+- Ubuntu 24.04 LTS
- Ubuntu 23.10
-- Ubuntu 22.04 LTS
-- Ubuntu 20.04 LTS
+- Ubuntu 22.04 LTS
+- Ubuntu 20.04 LTS
- Ubuntu 18.04 LTS
- Debian 12
- Debian 11
@@ -86,9 +78,6 @@ https://opencollective.com/dokploy
- Centos 9
- Centos 8
-
-
## Explanation
+
[English](README.md) | [中文](README-zh.md) | [Deutsch](README-de.md) | [Русский Язык](README-ru.md)
-
-
diff --git a/__test__/compose/compose.test.ts b/__test__/compose/compose.test.ts
index 675cb772..1e728b99 100644
--- a/__test__/compose/compose.test.ts
+++ b/__test__/compose/compose.test.ts
@@ -1,7 +1,7 @@
-import { expect, test } from "vitest";
-import { load } from "js-yaml";
import { addPrefixToAllProperties } from "@/server/utils/docker/compose";
import type { ComposeSpecification } from "@/server/utils/docker/types";
+import { load } from "js-yaml";
+import { expect, test } from "vitest";
const composeFile1 = `
version: "3.8"
diff --git a/__test__/compose/network/network-service.test.ts b/__test__/compose/network/network-service.test.ts
index 92df7a73..d592811b 100644
--- a/__test__/compose/network/network-service.test.ts
+++ b/__test__/compose/network/network-service.test.ts
@@ -79,10 +79,11 @@ test("Add prefix to networks in services with aliases", () => {
`frontend-${prefix}`,
);
- const networkConfig =
- actualComposeData?.services?.api?.networks[`frontend-${prefix}`];
- expect(networkConfig).toBeDefined();
- expect(networkConfig?.aliases).toContain("api");
+ const networkConfig = actualComposeData?.services?.api?.networks as {
+ [key: string]: { aliases?: string[] };
+ };
+ expect(networkConfig[`frontend-${prefix}`]).toBeDefined();
+ expect(networkConfig[`frontend-${prefix}`]?.aliases).toContain("api");
expect(actualComposeData.services?.api?.networks).not.toHaveProperty(
"frontend-ash",
@@ -169,7 +170,9 @@ test("Add prefix to networks in services (combined case)", () => {
);
// Caso 2: Objeto con aliases
- const apiNetworks = actualComposeData.services?.api?.networks;
+ const apiNetworks = actualComposeData.services?.api?.networks as {
+ [key: string]: unknown;
+ };
expect(apiNetworks).toHaveProperty(`frontend-${prefix}`);
expect(apiNetworks[`frontend-${prefix}`]).toBeDefined();
expect(apiNetworks).not.toHaveProperty("frontend");
diff --git a/__test__/compose/network/network.test.ts b/__test__/compose/network/network.test.ts
index ae938775..f86cabfd 100644
--- a/__test__/compose/network/network.test.ts
+++ b/__test__/compose/network/network.test.ts
@@ -76,9 +76,11 @@ test("Add prefix to networks in services and root (combined case)", () => {
);
// Caso 2: Objeto con aliases
- const apiNetworks = actualComposeData.services?.api?.networks;
+ const apiNetworks = actualComposeData.services?.api?.networks as {
+ [key: string]: { aliases?: string[] };
+ };
expect(apiNetworks).toHaveProperty(`frontend-${prefix}`);
- expect(apiNetworks[`frontend-${prefix}`]?.aliases).toContain("api");
+ expect(apiNetworks?.[`frontend-${prefix}`]?.aliases).toContain("api");
expect(apiNetworks).not.toHaveProperty("frontend");
// Caso 3: Objeto con redes simples
diff --git a/__test__/compose/secrets/secret-root.test.ts b/__test__/compose/secrets/secret-root.test.ts
index 861343a2..61f9f818 100644
--- a/__test__/compose/secrets/secret-root.test.ts
+++ b/__test__/compose/secrets/secret-root.test.ts
@@ -1,8 +1,8 @@
-import { expect, test } from "vitest";
-import { load, dump } from "js-yaml";
import { generateRandomHash } from "@/server/utils/docker/compose";
-import type { ComposeSpecification } from "@/server/utils/docker/types";
import { addPrefixToSecretsRoot } from "@/server/utils/docker/compose/secrets";
+import type { ComposeSpecification } from "@/server/utils/docker/types";
+import { dump, load } from "js-yaml";
+import { expect, test } from "vitest";
test("Generate random hash with 8 characters", () => {
const hash = generateRandomHash();
diff --git a/__test__/compose/service/service-container-name.test.ts b/__test__/compose/service/service-container-name.test.ts
index 9e3bfa80..9f5fe9ed 100644
--- a/__test__/compose/service/service-container-name.test.ts
+++ b/__test__/compose/service/service-container-name.test.ts
@@ -42,7 +42,7 @@ test("Add prefix to service names with container_name in compose file", () => {
const actualComposeData = { ...composeData, services: updatedComposeData };
// Verificar que el nombre del contenedor ha cambiado correctamente
- expect(actualComposeData.services[`web-${prefix}`].container_name).toBe(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.container_name).toBe(
`web_container-${prefix}`,
);
// Verificar que la nueva clave del servicio tiene el prefijo y la vieja clave no existe
@@ -50,10 +50,10 @@ test("Add prefix to service names with container_name in compose file", () => {
expect(actualComposeData.services).not.toHaveProperty("web");
// Verificar que la configuración de la imagen sigue igual
- expect(actualComposeData.services[`web-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
"nginx:latest",
);
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
});
diff --git a/__test__/compose/service/service-depends-on.test.ts b/__test__/compose/service/service-depends-on.test.ts
index cf4ca132..e339ee65 100644
--- a/__test__/compose/service/service-depends-on.test.ts
+++ b/__test__/compose/service/service-depends-on.test.ts
@@ -51,30 +51,30 @@ test("Add prefix to service names with depends_on (array) in compose file", () =
expect(actualComposeData.services).not.toHaveProperty("web");
// Verificar que la configuración de la imagen sigue igual
- expect(actualComposeData.services[`web-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
"nginx:latest",
);
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
// Verificar que los nombres en depends_on tienen el prefijo
- expect(actualComposeData.services[`web-${prefix}`].depends_on).toContain(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.depends_on).toContain(
`db-${prefix}`,
);
- expect(actualComposeData.services[`web-${prefix}`].depends_on).toContain(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.depends_on).toContain(
`api-${prefix}`,
);
// Verificar que los servicios `db` y `api` también tienen el prefijo
expect(actualComposeData.services).toHaveProperty(`db-${prefix}`);
expect(actualComposeData.services).not.toHaveProperty("db");
- expect(actualComposeData.services[`db-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`db-${prefix}`]?.image).toBe(
"postgres:latest",
);
expect(actualComposeData.services).toHaveProperty(`api-${prefix}`);
expect(actualComposeData.services).not.toHaveProperty("api");
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
});
@@ -121,16 +121,16 @@ test("Add prefix to service names with depends_on (object) in compose file", ()
expect(actualComposeData.services).not.toHaveProperty("web");
// Verificar que la configuración de la imagen sigue igual
- expect(actualComposeData.services[`web-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
"nginx:latest",
);
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
// Verificar que los nombres en depends_on tienen el prefijo
- const webDependsOn = actualComposeData.services[`web-${prefix}`]
- .depends_on as Record
;
+ const webDependsOn = actualComposeData.services?.[`web-${prefix}`]
+ ?.depends_on as Record;
expect(webDependsOn).toHaveProperty(`db-${prefix}`);
expect(webDependsOn).toHaveProperty(`api-${prefix}`);
expect(webDependsOn[`db-${prefix}`].condition).toBe("service_healthy");
@@ -139,12 +139,12 @@ test("Add prefix to service names with depends_on (object) in compose file", ()
// Verificar que los servicios `db` y `api` también tienen el prefijo
expect(actualComposeData.services).toHaveProperty(`db-${prefix}`);
expect(actualComposeData.services).not.toHaveProperty("db");
- expect(actualComposeData.services[`db-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`db-${prefix}`]?.image).toBe(
"postgres:latest",
);
expect(actualComposeData.services).toHaveProperty(`api-${prefix}`);
expect(actualComposeData.services).not.toHaveProperty("api");
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
});
diff --git a/__test__/compose/service/service-extends.test.ts b/__test__/compose/service/service-extends.test.ts
index 6188e4a8..e8f31aab 100644
--- a/__test__/compose/service/service-extends.test.ts
+++ b/__test__/compose/service/service-extends.test.ts
@@ -49,22 +49,22 @@ test("Add prefix to service names with extends (string) in compose file", () =>
expect(actualComposeData.services).not.toHaveProperty("web");
// Verificar que la configuración de la imagen sigue igual
- expect(actualComposeData.services[`web-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
"nginx:latest",
);
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
// Verificar que el nombre en extends tiene el prefijo
- expect(actualComposeData.services[`web-${prefix}`].extends).toBe(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.extends).toBe(
`base_service-${prefix}`,
);
// Verificar que el servicio `base_service` también tiene el prefijo
expect(actualComposeData.services).toHaveProperty(`base_service-${prefix}`);
expect(actualComposeData.services).not.toHaveProperty("base_service");
- expect(actualComposeData.services[`base_service-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`base_service-${prefix}`]?.image).toBe(
"base:latest",
);
});
@@ -109,23 +109,23 @@ test("Add prefix to service names with extends (object) in compose file", () =>
expect(actualComposeData.services).not.toHaveProperty("web");
// Verificar que la configuración de la imagen sigue igual
- expect(actualComposeData.services[`web-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
"nginx:latest",
);
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
// Verificar que el nombre en extends.service tiene el prefijo
- const webExtends = actualComposeData.services[`web-${prefix}`].extends;
+ const webExtends = actualComposeData.services?.[`web-${prefix}`]?.extends;
if (typeof webExtends !== "string") {
- expect(webExtends.service).toBe(`base_service-${prefix}`);
+ expect(webExtends?.service).toBe(`base_service-${prefix}`);
}
// Verificar que el servicio `base_service` también tiene el prefijo
expect(actualComposeData.services).toHaveProperty(`base_service-${prefix}`);
expect(actualComposeData.services).not.toHaveProperty("base_service");
- expect(actualComposeData.services[`base_service-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`base_service-${prefix}`]?.image).toBe(
"base:latest",
);
});
diff --git a/__test__/compose/service/service-links.test.ts b/__test__/compose/service/service-links.test.ts
index b9b22fdf..08252649 100644
--- a/__test__/compose/service/service-links.test.ts
+++ b/__test__/compose/service/service-links.test.ts
@@ -50,27 +50,27 @@ test("Add prefix to service names with links in compose file", () => {
expect(actualComposeData.services).not.toHaveProperty("web");
// Verificar que la configuración de la imagen sigue igual
- expect(actualComposeData.services[`web-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
"nginx:latest",
);
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
// Verificar que los nombres en links tienen el prefijo
- expect(actualComposeData.services[`web-${prefix}`].links).toContain(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.links).toContain(
`db-${prefix}`,
);
// Verificar que los servicios `db` y `api` también tienen el prefijo
expect(actualComposeData.services).toHaveProperty(`db-${prefix}`);
expect(actualComposeData.services).not.toHaveProperty("db");
- expect(actualComposeData.services[`db-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`db-${prefix}`]?.image).toBe(
"postgres:latest",
);
expect(actualComposeData.services).toHaveProperty(`api-${prefix}`);
expect(actualComposeData.services).not.toHaveProperty("api");
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
});
diff --git a/__test__/compose/service/sevice-volumes-from.test.ts b/__test__/compose/service/sevice-volumes-from.test.ts
index 90905a00..00d75fe8 100644
--- a/__test__/compose/service/sevice-volumes-from.test.ts
+++ b/__test__/compose/service/sevice-volumes-from.test.ts
@@ -54,23 +54,25 @@ test("Add prefix to service names with volumes_from in compose file", () => {
expect(actualComposeData.services).not.toHaveProperty("web");
// Verificar que la configuración de la imagen sigue igual
- expect(actualComposeData.services[`web-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
"nginx:latest",
);
- expect(actualComposeData.services[`api-${prefix}`].image).toBe(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
"myapi:latest",
);
// Verificar que los nombres en volumes_from tienen el prefijo
- expect(actualComposeData.services[`web-${prefix}`].volumes_from).toContain(
+ expect(actualComposeData.services?.[`web-${prefix}`]?.volumes_from).toContain(
`shared-${prefix}`,
);
- expect(actualComposeData.services[`api-${prefix}`].volumes_from).toContain(
+ expect(actualComposeData.services?.[`api-${prefix}`]?.volumes_from).toContain(
`shared-${prefix}`,
);
// Verificar que el servicio shared también tiene el prefijo
expect(actualComposeData.services).toHaveProperty(`shared-${prefix}`);
expect(actualComposeData.services).not.toHaveProperty("shared");
- expect(actualComposeData.services[`shared-${prefix}`].image).toBe("busybox");
+ expect(actualComposeData.services?.[`shared-${prefix}`]?.image).toBe(
+ "busybox",
+ );
});
diff --git a/__test__/compose/volume/volume-2.test.ts b/__test__/compose/volume/volume-2.test.ts
index 41581844..57bfb761 100644
--- a/__test__/compose/volume/volume-2.test.ts
+++ b/__test__/compose/volume/volume-2.test.ts
@@ -1,7 +1,7 @@
import { generateRandomHash } from "@/server/utils/docker/compose";
import {
- addPrefixToVolumesRoot,
addPrefixToAllVolumes,
+ addPrefixToVolumesRoot,
} from "@/server/utils/docker/compose/volume";
import type { ComposeSpecification } from "@/server/utils/docker/types";
import { load } from "js-yaml";
diff --git a/__test__/vitest.config.ts b/__test__/vitest.config.ts
index 4127903f..71749b6c 100644
--- a/__test__/vitest.config.ts
+++ b/__test__/vitest.config.ts
@@ -1,5 +1,5 @@
-import { defineConfig } from "vitest/config";
import tsconfigPaths from "vite-tsconfig-paths";
+import { defineConfig } from "vitest/config";
export default defineConfig({
plugins: [
diff --git a/biome.json b/biome.json
index dd7c1eb7..fd2d79a3 100644
--- a/biome.json
+++ b/biome.json
@@ -1,17 +1,34 @@
{
- "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
- "linter":{
- "rules": {
- "correctness":{
- "useExhaustiveDependencies": "off"
- },
- "suspicious":{
- "noArrayIndexKey": "off"
- },
- "a11y":{
- "noSvgWithoutTitle":"off"
- }
- }
- }
-
-}
\ No newline at end of file
+ "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
+ "files": {
+ "ignore": ["node_modules/**", ".next/**", "drizzle/**", ".docker"]
+ },
+ "organizeImports": {
+ "enabled": true
+ },
+ "linter": {
+ "rules": {
+ "complexity": {
+ "noUselessCatch": "off",
+ "noBannedTypes": "off"
+ },
+ "correctness": {
+ "useExhaustiveDependencies": "off",
+ "noUnsafeOptionalChaining": "off"
+ },
+ "style": {
+ "noNonNullAssertion": "off"
+ },
+ "suspicious": {
+ "noArrayIndexKey": "off",
+ "noExplicitAny": "off",
+ "noRedeclare": "off"
+ },
+ "a11y": {
+ "noSvgWithoutTitle": "off",
+ "useKeyWithClickEvents": "off",
+ "useAriaPropsForRole": "off"
+ }
+ }
+ }
+}
diff --git a/components.json b/components.json
index b4baac4f..81104c1e 100644
--- a/components.json
+++ b/components.json
@@ -1,17 +1,17 @@
{
- "$schema": "https://ui.shadcn.com/schema.json",
- "style": "default",
- "rsc": false,
- "tsx": true,
- "tailwind": {
- "config": "tailwind.config.ts",
- "css": "styles/globals.css",
- "baseColor": "zinc",
- "cssVariables": true,
- "prefix": ""
- },
- "aliases": {
- "components": "@/components",
- "utils": "@/lib/utils"
- }
-}
\ No newline at end of file
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "default",
+ "rsc": false,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.ts",
+ "css": "styles/globals.css",
+ "baseColor": "zinc",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils"
+ }
+}
diff --git a/components/auth/login-2fa.tsx b/components/auth/login-2fa.tsx
index 6bf03d0c..7c4915fa 100644
--- a/components/auth/login-2fa.tsx
+++ b/components/auth/login-2fa.tsx
@@ -10,19 +10,19 @@ import {
} from "@/components/ui/form";
import { CardTitle } from "@/components/ui/card";
-import { api } from "@/utils/api";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { AlertTriangle } from "lucide-react";
-import { useEffect } from "react";
-import { useForm } from "react-hook-form";
-import { toast } from "sonner";
-import { z } from "zod";
import {
InputOTP,
InputOTPGroup,
InputOTPSlot,
} from "@/components/ui/input-otp";
+import { api } from "@/utils/api";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { AlertTriangle } from "lucide-react";
import { useRouter } from "next/router";
+import { useEffect } from "react";
+import { useForm } from "react-hook-form";
+import { toast } from "sonner";
+import { z } from "zod";
const Login2FASchema = z.object({
pin: z.string().min(6, {
diff --git a/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx b/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx
index 3e2730c9..fd91703b 100644
--- a/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx
+++ b/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx
@@ -1,3 +1,5 @@
+import { AlertBlock } from "@/components/shared/alert-block";
+import { CodeEditor } from "@/components/shared/code-editor";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -17,21 +19,19 @@ import {
FormLabel,
FormMessage,
} from "@/components/ui/form";
-import { api } from "@/utils/api";
-import { AlertBlock } from "@/components/shared/alert-block";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { useEffect } from "react";
-import { useForm } from "react-hook-form";
-import { toast } from "sonner";
-import { z } from "zod";
-import { HelpCircle, Settings } from "lucide-react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
-import { CodeEditor } from "@/components/shared/code-editor";
+import { api } from "@/utils/api";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { HelpCircle, Settings } from "lucide-react";
+import { useEffect } from "react";
+import { useForm } from "react-hook-form";
+import { toast } from "sonner";
+import { z } from "zod";
const HealthCheckSwarmSchema = z
.object({
diff --git a/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx b/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx
index da69aedb..4078ae4c 100644
--- a/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx
+++ b/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx
@@ -1,4 +1,5 @@
-import React from "react";
+import { AlertBlock } from "@/components/shared/alert-block";
+import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
@@ -6,8 +7,6 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
-import { api } from "@/utils/api";
-import { z } from "zod";
import {
Form,
FormControl,
@@ -16,11 +15,6 @@ import {
FormLabel,
FormMessage,
} from "@/components/ui/form";
-import { toast } from "sonner";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { useForm } from "react-hook-form";
-import { useEffect } from "react";
-import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Select,
@@ -31,10 +25,16 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
-import Link from "next/link";
+import { api } from "@/utils/api";
+import { zodResolver } from "@hookform/resolvers/zod";
import { Server } from "lucide-react";
+import Link from "next/link";
+import React from "react";
+import { useEffect } from "react";
+import { useForm } from "react-hook-form";
+import { toast } from "sonner";
+import { z } from "zod";
import { AddSwarmSettings } from "./modify-swarm-settings";
-import { AlertBlock } from "@/components/shared/alert-block";
interface Props {
applicationId: string;
diff --git a/components/dashboard/application/advanced/general/add-command.tsx b/components/dashboard/application/advanced/general/add-command.tsx
index a898607d..979660bc 100644
--- a/components/dashboard/application/advanced/general/add-command.tsx
+++ b/components/dashboard/application/advanced/general/add-command.tsx
@@ -1,4 +1,4 @@
-import React from "react";
+import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
@@ -6,8 +6,6 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
-import { api } from "@/utils/api";
-import { z } from "zod";
import {
Form,
FormControl,
@@ -16,12 +14,14 @@ import {
FormLabel,
FormMessage,
} from "@/components/ui/form";
-import { toast } from "sonner";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { useForm } from "react-hook-form";
-import { useEffect } from "react";
-import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
+import { api } from "@/utils/api";
+import { zodResolver } from "@hookform/resolvers/zod";
+import React from "react";
+import { useEffect } from "react";
+import { useForm } from "react-hook-form";
+import { toast } from "sonner";
+import { z } from "zod";
interface Props {
applicationId: string;
}
diff --git a/components/dashboard/application/advanced/ports/add-port.tsx b/components/dashboard/application/advanced/ports/add-port.tsx
index 76939d82..873baa67 100644
--- a/components/dashboard/application/advanced/ports/add-port.tsx
+++ b/components/dashboard/application/advanced/ports/add-port.tsx
@@ -1,3 +1,4 @@
+import { AlertBlock } from "@/components/shared/alert-block";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -17,13 +18,6 @@ import {
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
-import { api } from "@/utils/api";
-import { AlertBlock } from "@/components/shared/alert-block";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { useEffect } from "react";
-import { useForm } from "react-hook-form";
-import { toast } from "sonner";
-import { PlusIcon } from "lucide-react";
import {
Select,
SelectContent,
@@ -31,6 +25,12 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
+import { api } from "@/utils/api";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { PlusIcon } from "lucide-react";
+import { useEffect } from "react";
+import { useForm } from "react-hook-form";
+import { toast } from "sonner";
import { z } from "zod";
const AddPortSchema = z.object({
diff --git a/components/dashboard/application/advanced/ports/show-port.tsx b/components/dashboard/application/advanced/ports/show-port.tsx
index ab5f4097..1ab804fb 100644
--- a/components/dashboard/application/advanced/ports/show-port.tsx
+++ b/components/dashboard/application/advanced/ports/show-port.tsx
@@ -1,4 +1,4 @@
-import React from "react";
+import { AlertBlock } from "@/components/shared/alert-block";
import {
Card,
CardContent,
@@ -8,10 +8,10 @@ import {
} from "@/components/ui/card";
import { api } from "@/utils/api";
import { Rss } from "lucide-react";
+import React from "react";
import { AddPort } from "./add-port";
import { DeletePort } from "./delete-port";
import { UpdatePort } from "./update-port";
-import { AlertBlock } from "@/components/shared/alert-block";
interface Props {
applicationId: string;
}
diff --git a/components/dashboard/application/advanced/ports/update-port.tsx b/components/dashboard/application/advanced/ports/update-port.tsx
index 9742964e..8f9d9cd7 100644
--- a/components/dashboard/application/advanced/ports/update-port.tsx
+++ b/components/dashboard/application/advanced/ports/update-port.tsx
@@ -1,3 +1,4 @@
+import { AlertBlock } from "@/components/shared/alert-block";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -17,14 +18,6 @@ import {
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
-import { api } from "@/utils/api";
-import { AlertBlock } from "@/components/shared/alert-block";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { PenBoxIcon, Pencil } from "lucide-react";
-import { useEffect } from "react";
-import { useForm } from "react-hook-form";
-import { toast } from "sonner";
-import { z } from "zod";
import {
Select,
SelectContent,
@@ -32,6 +25,13 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
+import { api } from "@/utils/api";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { PenBoxIcon, Pencil } from "lucide-react";
+import { useEffect } from "react";
+import { useForm } from "react-hook-form";
+import { toast } from "sonner";
+import { z } from "zod";
const UpdatePortSchema = z.object({
publishedPort: z.number().int().min(1).max(65535),
diff --git a/components/dashboard/application/advanced/redirects/add-redirect.tsx b/components/dashboard/application/advanced/redirects/add-redirect.tsx
index 4bcf2c56..661990a9 100644
--- a/components/dashboard/application/advanced/redirects/add-redirect.tsx
+++ b/components/dashboard/application/advanced/redirects/add-redirect.tsx
@@ -1,3 +1,4 @@
+import { AlertBlock } from "@/components/shared/alert-block";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -11,22 +12,21 @@ import {
import {
Form,
FormControl,
+ FormDescription,
FormField,
FormItem,
FormLabel,
- FormDescription,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
+import { Switch } from "@/components/ui/switch";
import { api } from "@/utils/api";
-import { AlertBlock } from "@/components/shared/alert-block";
import { zodResolver } from "@hookform/resolvers/zod";
+import { PlusIcon } from "lucide-react";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
-import { PlusIcon } from "lucide-react";
import { z } from "zod";
-import { Switch } from "@/components/ui/switch";
const AddRedirectchema = z.object({
regex: z.string().min(1, "Regex required"),
diff --git a/components/dashboard/application/advanced/redirects/show-redirects.tsx b/components/dashboard/application/advanced/redirects/show-redirects.tsx
index 2a6e80a2..9a8325fc 100644
--- a/components/dashboard/application/advanced/redirects/show-redirects.tsx
+++ b/components/dashboard/application/advanced/redirects/show-redirects.tsx
@@ -1,4 +1,3 @@
-import React from "react";
import {
Card,
CardContent,
@@ -8,6 +7,7 @@ import {
} from "@/components/ui/card";
import { api } from "@/utils/api";
import { Split } from "lucide-react";
+import React from "react";
import { AddRedirect } from "./add-redirect";
import { DeleteRedirect } from "./delete-redirect";
import { UpdateRedirect } from "./update-redirect";
diff --git a/components/dashboard/application/advanced/redirects/update-redirect.tsx b/components/dashboard/application/advanced/redirects/update-redirect.tsx
index 9643938b..855f5c8c 100644
--- a/components/dashboard/application/advanced/redirects/update-redirect.tsx
+++ b/components/dashboard/application/advanced/redirects/update-redirect.tsx
@@ -1,3 +1,4 @@
+import { AlertBlock } from "@/components/shared/alert-block";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -11,22 +12,21 @@ import {
import {
Form,
FormControl,
+ FormDescription,
FormField,
FormItem,
FormLabel,
- FormDescription,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
+import { Switch } from "@/components/ui/switch";
import { api } from "@/utils/api";
-import { AlertBlock } from "@/components/shared/alert-block";
import { zodResolver } from "@hookform/resolvers/zod";
import { PenBoxIcon, Pencil } from "lucide-react";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
-import { Switch } from "@/components/ui/switch";
const UpdateRedirectSchema = z.object({
regex: z.string().min(1, "Regex required"),
permanent: z.boolean().default(false),
diff --git a/components/dashboard/application/advanced/security/add-security.tsx b/components/dashboard/application/advanced/security/add-security.tsx
index 1f7c0d39..64dfd57a 100644
--- a/components/dashboard/application/advanced/security/add-security.tsx
+++ b/components/dashboard/application/advanced/security/add-security.tsx
@@ -1,3 +1,4 @@
+import { AlertBlock } from "@/components/shared/alert-block";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -18,12 +19,11 @@ import {
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { api } from "@/utils/api";
-import { AlertBlock } from "@/components/shared/alert-block";
import { zodResolver } from "@hookform/resolvers/zod";
+import { PlusIcon } from "lucide-react";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
-import { PlusIcon } from "lucide-react";
import { z } from "zod";
const AddSecuritychema = z.object({
diff --git a/components/dashboard/application/advanced/security/show-security.tsx b/components/dashboard/application/advanced/security/show-security.tsx
index ef51e2c9..5c02bf76 100644
--- a/components/dashboard/application/advanced/security/show-security.tsx
+++ b/components/dashboard/application/advanced/security/show-security.tsx
@@ -1,4 +1,3 @@
-import React from "react";
import {
Card,
CardContent,
@@ -8,6 +7,7 @@ import {
} from "@/components/ui/card";
import { api } from "@/utils/api";
import { LockKeyhole } from "lucide-react";
+import React from "react";
import { AddSecurity } from "./add-security";
import { DeleteSecurity } from "./delete-security";
import { UpdateSecurity } from "./update-security";
diff --git a/components/dashboard/application/advanced/security/update-security.tsx b/components/dashboard/application/advanced/security/update-security.tsx
index 9ff53c2e..bb6e59ae 100644
--- a/components/dashboard/application/advanced/security/update-security.tsx
+++ b/components/dashboard/application/advanced/security/update-security.tsx
@@ -1,3 +1,4 @@
+import { AlertBlock } from "@/components/shared/alert-block";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -18,7 +19,6 @@ import {
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { api } from "@/utils/api";
-import { AlertBlock } from "@/components/shared/alert-block";
import { zodResolver } from "@hookform/resolvers/zod";
import { PenBoxIcon, Pencil } from "lucide-react";
import { useEffect } from "react";
diff --git a/components/dashboard/application/advanced/show-application-advanced-settings.tsx b/components/dashboard/application/advanced/show-application-advanced-settings.tsx
index d0177331..56513465 100644
--- a/components/dashboard/application/advanced/show-application-advanced-settings.tsx
+++ b/components/dashboard/application/advanced/show-application-advanced-settings.tsx
@@ -1,3 +1,4 @@
+import { AlertBlock } from "@/components/shared/alert-block";
import { Button } from "@/components/ui/button";
import {
Card,
@@ -21,7 +22,6 @@ import React, { useEffect } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
-import { AlertBlock } from "@/components/shared/alert-block";
const addResourcesApplication = z.object({
memoryReservation: z.number().nullable().optional(),
diff --git a/components/dashboard/application/advanced/traefik/show-traefik-config.tsx b/components/dashboard/application/advanced/traefik/show-traefik-config.tsx
index 6b541504..28d44264 100644
--- a/components/dashboard/application/advanced/traefik/show-traefik-config.tsx
+++ b/components/dashboard/application/advanced/traefik/show-traefik-config.tsx
@@ -1,4 +1,4 @@
-import React from "react";
+import { CodeEditor } from "@/components/shared/code-editor";
import {
Card,
CardContent,
@@ -8,8 +8,8 @@ import {
} from "@/components/ui/card";
import { api } from "@/utils/api";
import { File } from "lucide-react";
+import React from "react";
import { UpdateTraefikConfig } from "./update-traefik-config";
-import { CodeEditor } from "@/components/shared/code-editor";
interface Props {
applicationId: string;
}
@@ -29,7 +29,7 @@ export const ShowTraefikConfig = ({ applicationId }: Props) => {
Traefik
Modify the traefik config, in rare cases you may need to add
- specific config, becarefull because modifying incorrectly can break
+ specific config, be careful because modifying incorrectly can break
traefik and your application
diff --git a/components/dashboard/application/advanced/traefik/update-traefik-config.tsx b/components/dashboard/application/advanced/traefik/update-traefik-config.tsx
index 659353ec..a185082b 100644
--- a/components/dashboard/application/advanced/traefik/update-traefik-config.tsx
+++ b/components/dashboard/application/advanced/traefik/update-traefik-config.tsx
@@ -1,3 +1,5 @@
+import { AlertBlock } from "@/components/shared/alert-block";
+import { CodeEditor } from "@/components/shared/code-editor";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -17,14 +19,12 @@ import {
FormMessage,
} from "@/components/ui/form";
import { api } from "@/utils/api";
-import { AlertBlock } from "@/components/shared/alert-block";
import { zodResolver } from "@hookform/resolvers/zod";
+import jsyaml from "js-yaml";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
-import jsyaml from "js-yaml";
-import { CodeEditor } from "@/components/shared/code-editor";
const UpdateTraefikConfigSchema = z.object({
traefikConfig: z.string(),
@@ -110,12 +110,15 @@ export const UpdateTraefikConfig = ({ applicationId }: Props) => {
};
return (
-