diff --git a/components/dashboard/application/general/deploy-application.tsx b/components/dashboard/application/general/deploy-application.tsx index 47fbb5c0..d8a33384 100644 --- a/components/dashboard/application/general/deploy-application.tsx +++ b/components/dashboard/application/general/deploy-application.tsx @@ -11,7 +11,6 @@ import { } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; import { api } from "@/utils/api"; -import { useEffect, useState } from "react"; import { toast } from "sonner"; interface Props { @@ -26,8 +25,6 @@ export const DeployApplication = ({ applicationId }: Props) => { { enabled: !!applicationId }, ); - const { mutateAsync: markRunning } = - api.application.markRunning.useMutation(); const { mutateAsync: deploy } = api.application.deploy.useMutation(); return ( @@ -48,24 +45,16 @@ export const DeployApplication = ({ applicationId }: Props) => { Cancel { - await markRunning({ + toast.success("Deploying Application...."); + + await refetch(); + await deploy({ applicationId, - }) - .then(async () => { - toast.success("Deploying Application...."); + }).catch(() => { + toast.error("Error to deploy Application"); + }); - await refetch(); - await deploy({ - applicationId, - }).catch(() => { - toast.error("Error to deploy Application"); - }); - - await refetch(); - }) - .catch((e) => { - toast.error(e.message || "Error to deploy Application"); - }); + await refetch(); }} > Confirm diff --git a/components/dashboard/application/rebuild-application.tsx b/components/dashboard/application/rebuild-application.tsx index 92e8bb4e..0284ab8f 100644 --- a/components/dashboard/application/rebuild-application.tsx +++ b/components/dashboard/application/rebuild-application.tsx @@ -25,8 +25,7 @@ export const RedbuildApplication = ({ applicationId }: Props) => { }, { enabled: !!applicationId }, ); - const { mutateAsync: markRunning } = - api.application.markRunning.useMutation(); + const { mutateAsync } = api.application.redeploy.useMutation(); const utils = api.useUtils(); return ( @@ -54,22 +53,14 @@ export const RedbuildApplication = ({ applicationId }: Props) => { Cancel { - await markRunning({ + toast.success("Redeploying Application...."); + await mutateAsync({ applicationId, }) .then(async () => { - await mutateAsync({ + await utils.application.one.invalidate({ applicationId, - }) - .then(async () => { - await utils.application.one.invalidate({ - applicationId, - }); - toast.success("Application rebuild succesfully"); - }) - .catch(() => { - toast.error("Error to rebuild the application"); - }); + }); }) .catch(() => { toast.error("Error to rebuild the application"); diff --git a/components/dashboard/compose/deployments/show-deployments-compose.tsx b/components/dashboard/compose/deployments/show-deployments-compose.tsx index a3688799..b4de30b6 100644 --- a/components/dashboard/compose/deployments/show-deployments-compose.tsx +++ b/components/dashboard/compose/deployments/show-deployments-compose.tsx @@ -9,14 +9,11 @@ import { import { api } from "@/utils/api"; import { RocketIcon } from "lucide-react"; import React, { useEffect, useState } from "react"; -// import { CancelQueues } from "./cancel-queues"; -// import { ShowDeployment } from "./show-deployment-compose"; import { StatusTooltip } from "@/components/shared/status-tooltip"; import { DateTooltip } from "@/components/shared/date-tooltip"; import { ShowDeploymentCompose } from "./show-deployment-compose"; import { RefreshTokenCompose } from "./refresh-token-compose"; import { CancelQueuesCompose } from "./cancel-queues-compose"; -// import { RefreshToken } from "./refresh-token";// interface Props { composeId: string; @@ -90,6 +87,11 @@ export const ShowDeploymentsCompose = ({ composeId }: Props) => { {deployment.title} + {deployment.description && ( + + {deployment.description} + + )}
diff --git a/components/dashboard/compose/general/deploy-compose.tsx b/components/dashboard/compose/general/deploy-compose.tsx index 1617ee7b..e9d5dfc1 100644 --- a/components/dashboard/compose/general/deploy-compose.tsx +++ b/components/dashboard/compose/general/deploy-compose.tsx @@ -25,7 +25,6 @@ export const DeployCompose = ({ composeId }: Props) => { { enabled: !!composeId }, ); - const { mutateAsync: markRunning } = api.compose.update.useMutation(); const { mutateAsync: deploy } = api.compose.deploy.useMutation(); return ( @@ -44,25 +43,16 @@ export const DeployCompose = ({ composeId }: Props) => { Cancel { - await markRunning({ + toast.success("Deploying Compose...."); + + await refetch(); + await deploy({ composeId, - composeStatus: "running", - }) - .then(async () => { - toast.success("Deploying Compose...."); + }).catch(() => { + toast.error("Error to deploy Compose"); + }); - await refetch(); - await deploy({ - composeId, - }).catch(() => { - toast.error("Error to deploy Compose"); - }); - - await refetch(); - }) - .catch((e) => { - toast.error(e.message || "Error to deploy Compose"); - }); + await refetch(); }} > Confirm diff --git a/components/dashboard/compose/general/rebuild-compose.tsx b/components/dashboard/compose/general/rebuild-compose.tsx index 25ad6d07..199d4f93 100644 --- a/components/dashboard/compose/general/rebuild-compose.tsx +++ b/components/dashboard/compose/general/rebuild-compose.tsx @@ -25,7 +25,6 @@ export const RedbuildCompose = ({ composeId }: Props) => { }, { enabled: !!composeId }, ); - const { mutateAsync: markRunning } = api.compose.update.useMutation(); const { mutateAsync } = api.compose.redeploy.useMutation(); const utils = api.useUtils(); return ( @@ -53,23 +52,14 @@ export const RedbuildCompose = ({ composeId }: Props) => { Cancel { - await markRunning({ + toast.success("Redeploying Compose...."); + await mutateAsync({ composeId, - composeStatus: "running", }) .then(async () => { - await mutateAsync({ + await utils.compose.one.invalidate({ composeId, - }) - .then(async () => { - await utils.compose.one.invalidate({ - composeId, - }); - toast.success("Compose rebuild succesfully"); - }) - .catch(() => { - toast.error("Error to rebuild the compose"); - }); + }); }) .catch(() => { toast.error("Error to rebuild the compose"); diff --git a/components/dashboard/compose/general/stop-compose.tsx b/components/dashboard/compose/general/stop-compose.tsx index 029cce11..2bb3cdeb 100644 --- a/components/dashboard/compose/general/stop-compose.tsx +++ b/components/dashboard/compose/general/stop-compose.tsx @@ -25,7 +25,6 @@ export const StopCompose = ({ composeId }: Props) => { }, { enabled: !!composeId }, ); - const { mutateAsync: markRunning } = api.compose.update.useMutation(); const { mutateAsync, isLoading } = api.compose.stop.useMutation(); const utils = api.useUtils(); return ( @@ -47,23 +46,14 @@ export const StopCompose = ({ composeId }: Props) => { Cancel { - await markRunning({ + await mutateAsync({ composeId, - composeStatus: "running", }) .then(async () => { - await mutateAsync({ + await utils.compose.one.invalidate({ composeId, - }) - .then(async () => { - await utils.compose.one.invalidate({ - composeId, - }); - toast.success("Compose rebuild succesfully"); - }) - .catch(() => { - toast.error("Error to stop the compose"); - }); + }); + toast.success("Compose stopped succesfully"); }) .catch(() => { toast.error("Error to stop the compose"); diff --git a/components/dashboard/project/add-template.tsx b/components/dashboard/project/add-template.tsx index 9e0fc085..80774207 100644 --- a/components/dashboard/project/add-template.tsx +++ b/components/dashboard/project/add-template.tsx @@ -54,7 +54,7 @@ export const AddTemplate = ({ projectId }: Props) => { -
+
Create Template diff --git a/components/dashboard/settings/github/github-setup.tsx b/components/dashboard/settings/github/github-setup.tsx index 1e78d001..99f71e6d 100644 --- a/components/dashboard/settings/github/github-setup.tsx +++ b/components/dashboard/settings/github/github-setup.tsx @@ -48,6 +48,7 @@ export const GithubSetup = () => { const [organizationName, setOrganization] = useState(""); const { data } = api.admin.one.useQuery(); useEffect(() => { + const url = document.location.origin; const manifest = JSON.stringify( { redirect_url: `${origin}/api/redirect?authId=${data?.authId}`, @@ -55,7 +56,7 @@ export const GithubSetup = () => { url: origin, hook_attributes: { // JUST FOR TESTING - url: "https://webhook.site/b6a167c0-ceb5-4f0c-a257-97c0fd163977", + url: `${url}/api/deploy/github`, // url: `${origin}/api/webhook`, // Aquí especificas la URL del endpoint de tu webhook }, callback_urls: [`${origin}/api/redirect`], // Los URLs de callback para procesos de autenticación @@ -92,8 +93,18 @@ export const GithubSetup = () => {
-
+
+ {/* + Manage Github App + */}
) : ( diff --git a/components/dashboard/settings/github/remove-github-app.tsx b/components/dashboard/settings/github/remove-github-app.tsx index ec1aa538..8ab7ea79 100644 --- a/components/dashboard/settings/github/remove-github-app.tsx +++ b/components/dashboard/settings/github/remove-github-app.tsx @@ -13,6 +13,13 @@ import { } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; import { toast } from "sonner"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, + TooltipProvider, +} from "@/components/ui/tooltip"; +import { InfoIcon } from "lucide-react"; export const RemoveGithubApp = () => { const { refetch } = api.auth.get.useQuery(); @@ -22,7 +29,20 @@ export const RemoveGithubApp = () => { return ( - + diff --git a/drizzle/0018_careful_killmonger.sql b/drizzle/0018_careful_killmonger.sql new file mode 100644 index 00000000..b5f7cc98 --- /dev/null +++ b/drizzle/0018_careful_killmonger.sql @@ -0,0 +1 @@ +ALTER TABLE "admin" ADD COLUMN "githubWebhookSecret" text; \ No newline at end of file diff --git a/drizzle/meta/0018_snapshot.json b/drizzle/meta/0018_snapshot.json new file mode 100644 index 00000000..220684c0 --- /dev/null +++ b/drizzle/meta/0018_snapshot.json @@ -0,0 +1,2632 @@ +{ + "id": "3d47456f-03b7-4b45-87f2-057df7e9cb0b", + "prevId": "ec852f38-886a-43b4-9295-73984ed8ef45", + "version": "6", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKey": { + "name": "customGitSSHKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + } + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + } + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "githubAppId": { + "name": "githubAppId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "githubAppName": { + "name": "githubAppName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubClientId": { + "name": "githubClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubClientSecret": { + "name": "githubClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubInstallationId": { + "name": "githubInstallationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubPrivateKey": { + "name": "githubPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubWebhookSecret": { + "name": "githubWebhookSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "project_adminId_admin_adminId_fk": { + "name": "project_adminId_admin_adminId_fk", + "tableFrom": "project", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.domain": { + "name": "domain", + "schema": "", + "columns": { + "domainId": { + "name": "domainId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "https": { + "name": "https", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 80 + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + } + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + } + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + } + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_adminId_admin_adminId_fk": { + "name": "destination_adminId_admin_adminId_fk", + "tableFrom": "destination", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.deployment": { + "name": "deployment", + "schema": "", + "columns": { + "deploymentId": { + "name": "deploymentId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "deploymentStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'running'" + }, + "logPath": { + "name": "logPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "certificate_certificatePath_unique": { + "name": "certificate_certificatePath_unique", + "nullsNotDistinct": false, + "columns": [ + "certificatePath" + ] + } + } + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "tableTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.security": { + "name": "security", + "schema": "", + "columns": { + "securityId": { + "name": "securityId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "security_applicationId_application_applicationId_fk": { + "name": "security_applicationId_application_applicationId_fk", + "tableFrom": "security", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "nullsNotDistinct": false, + "columns": [ + "username", + "applicationId" + ] + } + } + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + } + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKey": { + "name": "customGitSSHKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_adminId_admin_adminId_fk": { + "name": "registry_adminId_admin_adminId_fk", + "tableFrom": "registry", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + } + }, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 7a8a186f..93f4cadf 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -127,6 +127,13 @@ "when": 1719547174326, "tag": "0017_minor_post", "breakpoints": true + }, + { + "idx": 18, + "version": "6", + "when": 1719928377858, + "tag": "0018_careful_killmonger", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package.json b/package.json index b91e3b97..5883df66 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dokploy", - "version": "v0.3.0", + "version": "v0.3.1", "private": true, "license": "Apache-2.0", "type": "module", @@ -36,10 +36,12 @@ "@codemirror/lang-yaml": "^6.1.1", "@codemirror/language": "^6.10.1", "@codemirror/legacy-modes": "6.4.0", + "@dokploy/trpc-openapi": "0.0.4", "@faker-js/faker": "^8.4.1", "@hookform/resolvers": "^3.3.4", "@lucia-auth/adapter-drizzle": "1.0.7", "@octokit/auth-app": "^6.0.4", + "@octokit/webhooks": "^13.2.7", "@radix-ui/react-accordion": "1.1.2", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-avatar": "^1.0.4", @@ -113,7 +115,6 @@ "tailwind-merge": "^2.2.0", "tailwindcss-animate": "^1.0.7", "tar-fs": "3.0.5", - "@dokploy/trpc-openapi": "0.0.4", "use-resize-observer": "9.1.0", "ws": "8.16.0", "xterm-addon-fit": "^0.8.0", diff --git a/pages/api/deploy/[refreshToken].ts b/pages/api/deploy/[refreshToken].ts index c2aa3f16..d05f7e1e 100644 --- a/pages/api/deploy/[refreshToken].ts +++ b/pages/api/deploy/[refreshToken].ts @@ -1,4 +1,3 @@ -import { updateApplicationStatus } from "@/server/api/services/application"; import { db } from "@/server/db"; import { applications } from "@/server/db/schema"; import type { DeploymentJob } from "@/server/queues/deployments-queue"; @@ -68,11 +67,6 @@ export default async function handler( } try { - await updateApplicationStatus( - application.applicationId as string, - "running", - ); - const jobData: DeploymentJob = { applicationId: application.applicationId as string, titleLog: deploymentTitle, diff --git a/pages/api/deploy/compose/[refreshToken].ts b/pages/api/deploy/compose/[refreshToken].ts index 1c573981..b750ffac 100644 --- a/pages/api/deploy/compose/[refreshToken].ts +++ b/pages/api/deploy/compose/[refreshToken].ts @@ -9,7 +9,6 @@ import { extractCommitMessage, extractHash, } from "../[refreshToken]"; -import { updateCompose } from "@/server/api/services/compose"; export default async function handler( req: NextApiRequest, @@ -56,10 +55,6 @@ export default async function handler( } try { - await updateCompose(composeResult.composeId, { - composeStatus: "running", - }); - const jobData: DeploymentJob = { composeId: composeResult.composeId as string, titleLog: deploymentTitle, diff --git a/pages/api/deploy/github.ts b/pages/api/deploy/github.ts new file mode 100644 index 00000000..15536b01 --- /dev/null +++ b/pages/api/deploy/github.ts @@ -0,0 +1,126 @@ +import { and, eq } from "drizzle-orm"; +import { db } from "@/server/db"; +import { Webhooks } from "@octokit/webhooks"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { applications, compose } from "@/server/db/schema"; +import { extractCommitMessage, extractHash } from "./[refreshToken]"; +import type { DeploymentJob } from "@/server/queues/deployments-queue"; +import { myQueue } from "@/server/queues/queueSetup"; +import { findAdmin } from "@/server/api/services/admin"; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse, +) { + const admin = await findAdmin(); + + if (!admin) { + res.status(200).json({ message: "Could not find admin" }); + return; + } + + if (!admin.githubWebhookSecret) { + res.status(200).json({ message: "Github Webhook Secret not set" }); + return; + } + + const webhooks = new Webhooks({ + secret: admin.githubWebhookSecret, + }); + + const signature = req.headers["x-hub-signature-256"]; + const github = req.body; + + const verified = await webhooks.verify( + JSON.stringify(github), + signature as string, + ); + + if (!verified) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + + if (req.headers["x-github-event"] === "ping") { + res.status(200).json({ message: "Ping received, webhook is active" }); + return; + } + + if (req.headers["x-github-event"] !== "push") { + res.status(400).json({ message: "We only accept push events" }); + return; + } + + try { + const branchName = github?.ref?.replace("refs/heads/", ""); + const repository = github?.repository?.name; + const deploymentTitle = extractCommitMessage(req.headers, req.body); + const deploymentHash = extractHash(req.headers, req.body); + + const apps = await db.query.applications.findMany({ + where: and( + eq(applications.sourceType, "github"), + eq(applications.autoDeploy, true), + eq(applications.branch, branchName), + eq(applications.repository, repository), + ), + }); + + for (const app of apps) { + const jobData: DeploymentJob = { + applicationId: app.applicationId as string, + titleLog: deploymentTitle, + descriptionLog: `Hash: ${deploymentHash}`, + type: "deploy", + applicationType: "application", + }; + await myQueue.add( + "deployments", + { ...jobData }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); + } + + const composeApps = await db.query.compose.findMany({ + where: and( + eq(compose.sourceType, "github"), + eq(compose.autoDeploy, true), + eq(compose.branch, branchName), + eq(compose.repository, repository), + ), + }); + + for (const composeApp of composeApps) { + const jobData: DeploymentJob = { + composeId: composeApp.composeId as string, + titleLog: deploymentTitle, + type: "deploy", + applicationType: "compose", + descriptionLog: `Hash: ${deploymentHash}`, + }; + + await myQueue.add( + "deployments", + { ...jobData }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); + } + + const totalApps = apps.length + composeApps.length; + const emptyApps = totalApps === 0; + + if (emptyApps) { + res.status(200).json({ message: "No apps to deploy" }); + return; + } + res.status(200).json({ message: `Deployed ${totalApps} apps` }); + } catch (error) { + res.status(400).json({ message: "Error To Deploy Application", error }); + } +} diff --git a/pages/api/redirect.ts b/pages/api/redirect.ts index aaeb66b8..112f4bb7 100644 --- a/pages/api/redirect.ts +++ b/pages/api/redirect.ts @@ -38,6 +38,7 @@ export default async function handler( githubAppName: data.name, githubClientId: data.client_id, githubClientSecret: data.client_secret, + githubWebhookSecret: data.webhook_secret, githubPrivateKey: data.pem, }) .where(eq(admins.authId, authId as string)) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd08da38..821ec3f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,9 @@ dependencies: '@octokit/auth-app': specifier: ^6.0.4 version: 6.0.4 + '@octokit/webhooks': + specifier: ^13.2.7 + version: 13.2.7 '@radix-ui/react-accordion': specifier: 1.1.2 version: 1.1.2(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0) @@ -2604,6 +2607,14 @@ packages: resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==} dev: false + /@octokit/openapi-types@22.2.0: + resolution: {integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==} + dev: false + + /@octokit/openapi-webhooks-types@8.2.1: + resolution: {integrity: sha512-msAU1oTSm0ZmvAE0xDemuF4tVs5i0xNnNGtNmr4EuATi+1Rn8cZDetj6NXioSf5LwnxEc209COa/WOSbjuhLUA==} + dev: false + /@octokit/plugin-paginate-graphql@4.0.1(@octokit/core@5.1.0): resolution: {integrity: sha512-R8ZQNmrIKKpHWC6V2gum4x9LG2qF1RxRjo27gjQcG3j+vf2tLsEfE7I/wRWEPzYMaenr1M+qDAtNcwZve1ce1A==} engines: {node: '>= 18'} @@ -2665,6 +2676,13 @@ packages: once: 1.4.0 dev: false + /@octokit/request-error@6.1.1: + resolution: {integrity: sha512-1mw1gqT3fR/WFvnoVpY/zUM2o/XkMs/2AszUUG9I69xn0JFLv6PGkPhNk5lbfvROs79wiS0bqiJNxfCZcRJJdg==} + engines: {node: '>= 18'} + dependencies: + '@octokit/types': 13.5.0 + dev: false + /@octokit/request@8.2.0: resolution: {integrity: sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ==} engines: {node: '>= 18'} @@ -2681,11 +2699,22 @@ packages: '@octokit/openapi-types': 20.0.0 dev: false + /@octokit/types@13.5.0: + resolution: {integrity: sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==} + dependencies: + '@octokit/openapi-types': 22.2.0 + dev: false + /@octokit/webhooks-methods@4.1.0: resolution: {integrity: sha512-zoQyKw8h9STNPqtm28UGOYFE7O6D4Il8VJwhAtMHFt2C4L0VQT1qGKLeefUOqHNs1mNRYSadVv7x0z8U2yyeWQ==} engines: {node: '>= 18'} dev: false + /@octokit/webhooks-methods@5.1.0: + resolution: {integrity: sha512-yFZa3UH11VIxYnnoOYCVoJ3q4ChuSOk2IVBBQ0O3xtKX4x9bmKb/1t+Mxixv2iUhzMdOl1qeWJqEhouXXzB3rQ==} + engines: {node: '>= 18'} + dev: false + /@octokit/webhooks-types@7.3.2: resolution: {integrity: sha512-JWOoOgtWTFnTSAamPXXyjTY5/apttvNxF+vPBnwdSu5cj5snrd7FO0fyw4+wTXy8fHduq626JjhO+TwCyyA6vA==} dev: false @@ -2700,6 +2729,16 @@ packages: aggregate-error: 3.1.0 dev: false + /@octokit/webhooks@13.2.7: + resolution: {integrity: sha512-sPHCyi9uZuCs1gg0yF53FFocM+GsiiBEhQQV/itGzzQ8gjyv2GMJ1YvgdDY4lC0ePZeiV3juEw4GbS6w1VHhRw==} + engines: {node: '>= 18'} + dependencies: + '@octokit/openapi-webhooks-types': 8.2.1 + '@octokit/request-error': 6.1.1 + '@octokit/webhooks-methods': 5.1.0 + aggregate-error: 5.0.0 + dev: false + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -5566,6 +5605,14 @@ packages: indent-string: 5.0.0 dev: false + /aggregate-error@5.0.0: + resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==} + engines: {node: '>=18'} + dependencies: + clean-stack: 5.2.0 + indent-string: 5.0.0 + dev: false + /ajv-formats@2.1.1(ajv@8.14.0): resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -6072,6 +6119,13 @@ packages: escape-string-regexp: 5.0.0 dev: false + /clean-stack@5.2.0: + resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==} + engines: {node: '>=14.16'} + dependencies: + escape-string-regexp: 5.0.0 + dev: false + /cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} diff --git a/public/templates/open-webui.png b/public/templates/open-webui.png new file mode 100644 index 00000000..2b207478 Binary files /dev/null and b/public/templates/open-webui.png differ diff --git a/server/api/services/registry.ts b/server/api/services/registry.ts index 29c421b5..da124c7a 100644 --- a/server/api/services/registry.ts +++ b/server/api/services/registry.ts @@ -33,8 +33,10 @@ export const createRegistry = async (input: typeof apiCreateRegistry._type) => { }); } - const loginCommand = `echo ${input.password} | docker login ${input.registryUrl} --username ${input.username} --password-stdin`; - await execAsync(loginCommand); + if (newRegistry.registryType === "cloud") { + const loginCommand = `echo ${input.password} | docker login ${input.registryUrl} --username ${input.username} --password-stdin`; + await execAsync(loginCommand); + } return newRegistry; }); diff --git a/server/db/schema/admin.ts b/server/db/schema/admin.ts index 5ce3317e..28e3ebd0 100644 --- a/server/db/schema/admin.ts +++ b/server/db/schema/admin.ts @@ -23,6 +23,7 @@ export const admins = pgTable("admin", { githubClientSecret: text("githubClientSecret"), githubInstallationId: text("githubInstallationId"), githubPrivateKey: text("githubPrivateKey"), + githubWebhookSecret: text("githubWebhookSecret"), letsEncryptEmail: text("letsEncryptEmail"), sshPrivateKey: text("sshPrivateKey"), enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), diff --git a/server/queues/deployments-queue.ts b/server/queues/deployments-queue.ts index 54f23073..94a92219 100644 --- a/server/queues/deployments-queue.ts +++ b/server/queues/deployments-queue.ts @@ -2,9 +2,14 @@ import { type Job, Worker } from "bullmq"; import { deployApplication, rebuildApplication, + updateApplicationStatus, } from "../api/services/application"; import { myQueue, redisConfig } from "./queueSetup"; -import { deployCompose, rebuildCompose } from "../api/services/compose"; +import { + deployCompose, + rebuildCompose, + updateCompose, +} from "../api/services/compose"; type DeployJob = | { @@ -29,6 +34,7 @@ export const deploymentWorker = new Worker( async (job: Job) => { try { if (job.data.applicationType === "application") { + await updateApplicationStatus(job.data.applicationId, "running"); if (job.data.type === "redeploy") { await rebuildApplication({ applicationId: job.data.applicationId, @@ -43,6 +49,9 @@ export const deploymentWorker = new Worker( }); } } else if (job.data.applicationType === "compose") { + await updateCompose(job.data.composeId, { + composeStatus: "running", + }); if (job.data.type === "deploy") { await deployCompose({ composeId: job.data.composeId, diff --git a/server/utils/docker/utils.ts b/server/utils/docker/utils.ts index 1bc38893..1747f4ed 100644 --- a/server/utils/docker/utils.ts +++ b/server/utils/docker/utils.ts @@ -64,8 +64,8 @@ export const containerExists = async (containerName: string) => { export const stopService = async (appName: string) => { try { await execAsync(`docker service scale ${appName}=0 `); - console.log("Service stopped ✅"); } catch (error) { + console.error(error); return error; } }; @@ -93,6 +93,7 @@ export const cleanUpUnusedImages = async () => { try { await execAsync("docker image prune --all --force"); } catch (error) { + console.error(error); throw error; } }; @@ -101,6 +102,7 @@ export const cleanStoppedContainers = async () => { try { await execAsync("docker container prune --force"); } catch (error) { + console.error(error); throw error; } }; @@ -109,6 +111,7 @@ export const cleanUpUnusedVolumes = async () => { try { await execAsync("docker volume prune --force"); } catch (error) { + console.error(error); throw error; } }; @@ -142,6 +145,7 @@ export const startService = async (appName: string) => { try { await execAsync(`docker service scale ${appName}=1 `); } catch (error) { + console.error(error); throw error; } }; diff --git a/server/utils/providers/git.ts b/server/utils/providers/git.ts index 9c91ca19..e49867e7 100644 --- a/server/utils/providers/git.ts +++ b/server/utils/providers/git.ts @@ -87,7 +87,6 @@ const addHostToKnownHosts = async (repositoryURL: string) => { throw error; } }; - const sanitizeRepoPathSSH = (input: string) => { const SSH_PATH_RE = new RegExp( [ @@ -113,7 +112,7 @@ const sanitizeRepoPathSSH = (input: string) => { return { user: found.groups?.user ?? "git", domain: found.groups?.domain, - port: Number(found.groups?.port ?? 22), + port: 22, owner: found.groups?.owner ?? "", repo: found.groups?.repo, get repoPath() { diff --git a/templates/nocodb/docker-compose.yml b/templates/nocodb/docker-compose.yml index 221b8941..60ecb57c 100644 --- a/templates/nocodb/docker-compose.yml +++ b/templates/nocodb/docker-compose.yml @@ -1,7 +1,7 @@ version: "3.8" services: nocodb: - image: nocodb/nocodb:0.251.0 + image: nocodb/nocodb:0.251.1 restart: always networks: - dokploy-network diff --git a/templates/open-webui/docker-compose.yml b/templates/open-webui/docker-compose.yml new file mode 100644 index 00000000..457a60bd --- /dev/null +++ b/templates/open-webui/docker-compose.yml @@ -0,0 +1,37 @@ +version: '3.8' +services: + + ollama: + volumes: + - ollama:/root/.ollama + networks: + - dokploy-network + pull_policy: always + tty: true + restart: unless-stopped + image: ollama/ollama:${OLLAMA_DOCKER_TAG-latest} + + open-webui: + image: ghcr.io/open-webui/open-webui:${WEBUI_DOCKER_TAG-main} + networks: + - dokploy-network + volumes: + - open-webui:/app/backend/data + depends_on: + - ollama + environment: + - 'OLLAMA_BASE_URL=http://ollama:11434' + - 'WEBUI_SECRET_KEY=' + restart: unless-stopped + labels: + - "traefik.enable=true" + - "traefik.http.routers.${HASH}.rule=Host(`${OPEN_WEBUI_HOST}`)" + - "traefik.http.services.${HASH}.loadbalancer.server.port=${OPEN_WEBUI_PORT}" + +networks: + dokploy-network: + external: true + +volumes: + ollama: {} + open-webui: {} diff --git a/templates/open-webui/index.ts b/templates/open-webui/index.ts new file mode 100644 index 00000000..79e3b35e --- /dev/null +++ b/templates/open-webui/index.ts @@ -0,0 +1,22 @@ +import { + generateHash, + generateRandomDomain, + type Template, + type Schema, +} from "../utils"; + +export function generate(schema: Schema): Template { + const mainServiceHash = generateHash(schema.projectName); + const randomDomain = generateRandomDomain(schema); + const envs = [ + `OPEN_WEBUI_HOST=${randomDomain}`, + "OPEN_WEBUI_PORT=8080", + `HASH=${mainServiceHash}`, + 'OLLAMA_DOCKER_TAG=0.1.47', + 'WEBUI_DOCKER_TAG=0.3.7' + ]; + + return { + envs, + }; +} diff --git a/templates/templates.ts b/templates/templates.ts index a4b1a995..49bd596c 100644 --- a/templates/templates.ts +++ b/templates/templates.ts @@ -216,7 +216,7 @@ export const templates: TemplateData[] = [ { id: "nocodb", name: "NocoDB", - version: "0.251.0", + version: "0.251.1", description: "NocoDB is an opensource Airtable alternative that turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart spreadsheet.", @@ -318,4 +318,18 @@ export const templates: TemplateData[] = [ tags: ["hosting"], load: () => import("./glitchtip/index").then((m) => m.generate), }, + { + id: 'open-webui', + name: 'Open WebUI', + version: 'v0.3.7', + description: 'Open WebUI is a free and open source chatgpt alternative. Open WebUI is an extensible, feature-rich, and user-friendly self-hosted WebUI designed to operate entirely offline. It supports various LLM runners, including Ollama and OpenAI-compatible APIs. The template include ollama and webui services.', + logo: 'open-webui.png', + links: { + github: 'https://github.com/open-webui/open-webui', + website: 'https://openwebui.com/', + docs: 'https://docs.openwebui.com/', + }, + tags: ['chat'], + load: () => import('./open-webui/index').then((m) => m.generate), + } ];