From 7027f39c486aca8424ea3a7d0e74835347a5c5c5 Mon Sep 17 00:00:00 2001 From: Vincent Young Date: Sat, 28 Sep 2024 15:06:20 -0400 Subject: [PATCH 01/12] feat: add update option --- apps/website/public/install.sh | 192 ++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 87 deletions(-) diff --git a/apps/website/public/install.sh b/apps/website/public/install.sh index e68a59fd..f5b318f2 100644 --- a/apps/website/public/install.sh +++ b/apps/website/public/install.sh @@ -1,112 +1,130 @@ #!/bin/bash +install_dokploy() { + if [ "$(id -u)" != "0" ]; then + echo "This script must be run as root" >&2 + exit 1 + fi -if [ "$(id -u)" != "0" ]; then - echo "This script must be run as root" >&2 - exit 1 -fi + # check if is Mac OS + if [ "$(uname)" = "Darwin" ]; then + echo "This script must be run on Linux" >&2 + exit 1 + fi -# check if is Mac OS -if [ "$(uname)" = "Darwin" ]; then - echo "This script must be run on Linux" >&2 - exit 1 -fi + # check if is running inside a container + if [ -f /.dockerenv ]; then + echo "This script must be run on Linux" >&2 + exit 1 + fi + # check if something is running on port 80 + if ss -tulnp | grep ':80 ' >/dev/null; then + echo "Error: something is already running on port 80" >&2 + exit 1 + fi -# check if is running inside a container -if [ -f /.dockerenv ]; then - echo "This script must be run on Linux" >&2 - exit 1 -fi + # check if something is running on port 443 + if ss -tulnp | grep ':443 ' >/dev/null; then + echo "Error: something is already running on port 443" >&2 + exit 1 + fi -# check if something is running on port 80 -if ss -tulnp | grep ':80 ' >/dev/null; then - echo "Error: something is already running on port 80" >&2 - exit 1 -fi + command_exists() { + command -v "$@" > /dev/null 2>&1 + } -# check if something is running on port 443 -if ss -tulnp | grep ':443 ' >/dev/null; then - echo "Error: something is already running on port 443" >&2 - exit 1 -fi + if command_exists docker; then + echo "Docker already installed" + else + curl -sSL https://get.docker.com | sh + fi -command_exists() { - command -v "$@" > /dev/null 2>&1 -} + docker swarm leave --force 2>/dev/null -if command_exists docker; then - echo "Docker already installed" -else - curl -sSL https://get.docker.com | sh -fi + get_ip() { + # Try to get IPv4 + local ipv4=$(curl -4s https://ifconfig.io 2>/dev/null) -docker swarm leave --force 2>/dev/null + if [ -n "$ipv4" ]; then + echo "$ipv4" + else + # Try to get IPv6 + local ipv6=$(curl -6s https://ifconfig.io 2>/dev/null) + if [ -n "$ipv6" ]; then + echo "$ipv6" + fi + fi + } -get_ip() { - # Try to get IPv4 - local ipv4=$(curl -4s https://ifconfig.io 2>/dev/null) + advertise_addr=$(get_ip) - if [ -n "$ipv4" ]; then - echo "$ipv4" - else - # Try to get IPv6 - local ipv6=$(curl -6s https://ifconfig.io 2>/dev/null) - if [ -n "$ipv6" ]; then - echo "$ipv6" - fi - fi -} + docker swarm init --advertise-addr $advertise_addr + + echo "Swarm initialized" -advertise_addr=$(get_ip) + docker network rm -f dokploy-network 2>/dev/null + docker network create --driver overlay --attachable dokploy-network -docker swarm init --advertise-addr $advertise_addr + echo "Network created" -echo "Swarm initialized" + mkdir -p /etc/dokploy -docker network rm -f dokploy-network 2>/dev/null -docker network create --driver overlay --attachable dokploy-network + chmod 777 /etc/dokploy -echo "Network created" + docker pull dokploy/dokploy:latest -mkdir -p /etc/dokploy + # Installation + docker service create \ + --name dokploy \ + --replicas 1 \ + --network dokploy-network \ + --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ + --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ + --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ + --publish published=3000,target=3000,mode=host \ + --update-parallelism 1 \ + --update-order stop-first \ + --constraint 'node.role == manager' \ + dokploy/dokploy:latest -chmod 777 /etc/dokploy + GREEN="\033[0;32m" + YELLOW="\033[1;33m" + BLUE="\033[0;34m" + NC="\033[0m" # No Color -docker pull dokploy/dokploy:latest + format_ip_for_url() { + local ip="$1" + if echo "$ip" | grep -q ':'; then + # IPv6 + echo "[${ip}]" + else + # IPv4 + echo "${ip}" + fi + } -# Installation -docker service create \ - --name dokploy \ - --replicas 1 \ - --network dokploy-network \ - --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ - --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ - --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ - --publish published=3000,target=3000,mode=host \ - --update-parallelism 1 \ - --update-order stop-first \ - --constraint 'node.role == manager' \ - dokploy/dokploy:latest + formatted_addr=$(format_ip_for_url "$advertise_addr") + echo "" + printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n" + printf "${BLUE}Wait 15 seconds for the server to start${NC}\n" + printf "${YELLOW}Please go to http://${formatted_addr}:3000${NC}\n\n" +} -GREEN="\033[0;32m" -YELLOW="\033[1;33m" -BLUE="\033[0;34m" -NC="\033[0m" # No Color +update_dokploy() { + echo "Updating Dokploy..." + + # Pull the latest image + docker pull dokploy/dokploy:latest -format_ip_for_url() { - local ip="$1" - if echo "$ip" | grep -q ':'; then - # IPv6 - echo "[${ip}]" - else - # IPv4 - echo "${ip}" - fi + # Update the service + docker service update --image dokploy/dokploy:latest dokploy + + echo "Dokploy has been updated to the latest version." } -formatted_addr=$(format_ip_for_url "$advertise_addr") -echo "" -printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n" -printf "${BLUE}Wait 15 seconds for the server to start${NC}\n" -printf "${YELLOW}Please go to http://${formatted_addr}:3000${NC}\n\n" -echo "" +# Main script execution +if [ "$1" = "update" ]; then + update_dokploy +else + install_dokploy +fi From 18b4b23f79a9a76d1832b3ac7ef27719e0e17f5c Mon Sep 17 00:00:00 2001 From: Vincent Yang Date: Sun, 29 Sep 2024 22:45:39 -0400 Subject: [PATCH 02/12] feat: add update option for canary and feature tag --- apps/website/public/canary.sh | 203 ++++++++++++++++++--------------- apps/website/public/feature.sh | 186 ++++++++++++++++-------------- 2 files changed, 214 insertions(+), 175 deletions(-) diff --git a/apps/website/public/canary.sh b/apps/website/public/canary.sh index 3a9102b0..32f95bff 100644 --- a/apps/website/public/canary.sh +++ b/apps/website/public/canary.sh @@ -1,114 +1,133 @@ #!/bin/bash +install_dokploy() { + if [ "$(id -u)" != "0" ]; then + echo "This script must be run as root" >&2 + exit 1 + fi -if [ "$(id -u)" != "0" ]; then - echo "This script must be run as root" >&2 - exit 1 -fi - -# check if is Mac OS -if [ "$(uname)" = "Darwin" ]; then - echo "This script must be run on Linux" >&2 - exit 1 -fi - - -# check if is running inside a container -if [ -f /.dockerenv ]; then - echo "This script must be run on Linux" >&2 - exit 1 -fi - -# check if something is running on port 80 -if ss -tulnp | grep ':80 ' >/dev/null; then - echo "Error: something is already running on port 80" >&2 - exit 1 -fi - -# check if something is running on port 443 -if ss -tulnp | grep ':443 ' >/dev/null; then - echo "Error: something is already running on port 443" >&2 - exit 1 -fi - -command_exists() { - command -v "$@" > /dev/null 2>&1 -} + # check if is Mac OS + if [ "$(uname)" = "Darwin" ]; then + echo "This script must be run on Linux" >&2 + exit 1 + fi -if command_exists docker; then - echo "Docker already installed" -else - curl -sSL https://get.docker.com | sh -fi -docker swarm leave --force 2>/dev/null + # check if is running inside a container + if [ -f /.dockerenv ]; then + echo "This script must be run on Linux" >&2 + exit 1 + fi -get_ip() { - # Try to get IPv4 - local ipv4=$(curl -4s https://ifconfig.io 2>/dev/null) + # check if something is running on port 80 + if ss -tulnp | grep ':80 ' >/dev/null; then + echo "Error: something is already running on port 80" >&2 + exit 1 + fi - if [ -n "$ipv4" ]; then - echo "$ipv4" + # check if something is running on port 443 + if ss -tulnp | grep ':443 ' >/dev/null; then + echo "Error: something is already running on port 443" >&2 + exit 1 + fi + + command_exists() { + command -v "$@" > /dev/null 2>&1 + } + + if command_exists docker; then + echo "Docker already installed" else - # Try to get IPv6 - local ipv6=$(curl -6s https://ifconfig.io 2>/dev/null) - if [ -n "$ipv6" ]; then - echo "$ipv6" - fi + curl -sSL https://get.docker.com | sh fi -} -advertise_addr=$(get_ip) + docker swarm leave --force 2>/dev/null -docker swarm init --advertise-addr $advertise_addr + get_ip() { + # Try to get IPv4 + local ipv4=$(curl -4s https://ifconfig.io 2>/dev/null) -echo "Swarm initialized" + if [ -n "$ipv4" ]; then + echo "$ipv4" + else + # Try to get IPv6 + local ipv6=$(curl -6s https://ifconfig.io 2>/dev/null) + if [ -n "$ipv6" ]; then + echo "$ipv6" + fi + fi + } -docker network rm -f dokploy-network 2>/dev/null -docker network create --driver overlay --attachable dokploy-network + advertise_addr=$(get_ip) -echo "Network created" + docker swarm init --advertise-addr $advertise_addr -mkdir -p /etc/dokploy + echo "Swarm initialized" -chmod 777 /etc/dokploy + docker network rm -f dokploy-network 2>/dev/null + docker network create --driver overlay --attachable dokploy-network -docker pull dokploy/dokploy:canary + echo "Network created" -# Installation -docker service create \ - --name dokploy \ - --replicas 1 \ - --network dokploy-network \ - --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ - --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ - --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ - --publish published=3000,target=3000,mode=host \ - --update-parallelism 1 \ - --update-order stop-first \ - --constraint 'node.role == manager' \ - -e RELEASE_TAG=canary \ - dokploy/dokploy:canary + mkdir -p /etc/dokploy -GREEN="\033[0;32m" -YELLOW="\033[1;33m" -BLUE="\033[0;34m" -NC="\033[0m" # No Color + chmod 777 /etc/dokploy -format_ip_for_url() { - local ip="$1" - if echo "$ip" | grep -q ':'; then - # IPv6 - echo "[${ip}]" - else - # IPv4 - echo "${ip}" - fi + docker pull dokploy/dokploy:canary + + # Installation + docker service create \ + --name dokploy \ + --replicas 1 \ + --network dokploy-network \ + --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ + --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ + --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ + --publish published=3000,target=3000,mode=host \ + --update-parallelism 1 \ + --update-order stop-first \ + --constraint 'node.role == manager' \ + -e RELEASE_TAG=canary \ + dokploy/dokploy:canary + + GREEN="\033[0;32m" + YELLOW="\033[1;33m" + BLUE="\033[0;34m" + NC="\033[0m" # No Color + + format_ip_for_url() { + local ip="$1" + if echo "$ip" | grep -q ':'; then + # IPv6 + echo "[${ip}]" + else + # IPv4 + echo "${ip}" + fi + } + + formatted_addr=$(format_ip_for_url "$advertise_addr") + echo "" + printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n" + printf "${BLUE}Wait 15 seconds for the server to start${NC}\n" + printf "${YELLOW}Please go to http://${formatted_addr}:3000${NC}\n\n" + echo "" } -formatted_addr=$(format_ip_for_url "$advertise_addr") -echo "" -printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n" -printf "${BLUE}Wait 15 seconds for the server to start${NC}\n" -printf "${YELLOW}Please go to http://${formatted_addr}:3000${NC}\n\n" -echo "" +update_dokploy() { + echo "Updating Dokploy..." + + # Pull the latest canary image + docker pull dokploy/dokploy:canary + + # Update the service + docker service update --image dokploy/dokploy:canary dokploy + echo "Dokploy has been updated to the latest canary version." +} + +# Main script execution +if [ "$1" = "update" ]; then + update_dokploy +else + install_dokploy +fi \ No newline at end of file diff --git a/apps/website/public/feature.sh b/apps/website/public/feature.sh index 453da012..fca4fccd 100644 --- a/apps/website/public/feature.sh +++ b/apps/website/public/feature.sh @@ -1,97 +1,117 @@ #!/bin/bash +install_dokploy() { + if [ "$(id -u)" != "0" ]; then + echo "This script must be run as root" >&2 + exit 1 + fi -if [ "$(id -u)" != "0" ]; then - echo "This script must be run as root" >&2 - exit 1 -fi - -# check if is Mac OS -if [ "$(uname)" = "Darwin" ]; then - echo "This script must be run on Linux" >&2 - exit 1 -fi - - -# check if is running inside a container -if [ -f /.dockerenv ]; then - echo "This script must be run on Linux" >&2 - exit 1 -fi - -# check if something is running on port 80 -if ss -tulnp | grep ':80 ' >/dev/null; then - echo "Error: something is already running on port 80" >&2 - exit 1 -fi - -# check if something is running on port 443 -if ss -tulnp | grep ':443 ' >/dev/null; then - echo "Error: something is already running on port 443" >&2 - exit 1 -fi - -command_exists() { - command -v "$@" > /dev/null 2>&1 -} - -if command_exists docker; then - echo "Docker already installed" -else - curl -sSL https://get.docker.com | sh -fi - -docker swarm leave --force 2>/dev/null -advertise_addr=$(curl -s ifconfig.me) + # check if is Mac OS + if [ "$(uname)" = "Darwin" ]; then + echo "This script must be run on Linux" >&2 + exit 1 + fi -docker swarm init --advertise-addr $advertise_addr -echo "Swarm initialized" + # check if is running inside a container + if [ -f /.dockerenv ]; then + echo "This script must be run on Linux" >&2 + exit 1 + fi -docker network rm -f dokploy-network 2>/dev/null -docker network create --driver overlay --attachable dokploy-network + # check if something is running on port 80 + if ss -tulnp | grep ':80 ' >/dev/null; then + echo "Error: something is already running on port 80" >&2 + exit 1 + fi -echo "Network created" + # check if something is running on port 443 + if ss -tulnp | grep ':443 ' >/dev/null; then + echo "Error: something is already running on port 443" >&2 + exit 1 + fi -mkdir -p /etc/dokploy + command_exists() { + command -v "$@" > /dev/null 2>&1 + } -chmod 777 /etc/dokploy + if command_exists docker; then + echo "Docker already installed" + else + curl -sSL https://get.docker.com | sh + fi -docker pull dokploy/dokploy:feature + docker swarm leave --force 2>/dev/null + advertise_addr=$(curl -s ifconfig.me) + + docker swarm init --advertise-addr $advertise_addr + + echo "Swarm initialized" + + docker network rm -f dokploy-network 2>/dev/null + docker network create --driver overlay --attachable dokploy-network + + echo "Network created" + + mkdir -p /etc/dokploy + + chmod 777 /etc/dokploy + + docker pull dokploy/dokploy:feature + + # Installation + docker service create \ + --name dokploy \ + --replicas 1 \ + --network dokploy-network \ + --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ + --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ + --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ + --publish published=3000,target=3000,mode=host \ + --update-parallelism 1 \ + --update-order stop-first \ + --constraint 'node.role == manager' \ + -e RELEASE_TAG=feature \ + dokploy/dokploy:feature + + GREEN="\033[0;32m" + YELLOW="\033[1;33m" + BLUE="\033[0;34m" + NC="\033[0m" # No Color + + format_ip_for_url() { + local ip="$1" + if echo "$ip" | grep -q ':'; then + # IPv6 + echo "[${ip}]" + else + # IPv4 + echo "${ip}" + fi + } + + formatted_addr=$(format_ip_for_url "$advertise_addr") + echo "" + printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n" + printf "${BLUE}Wait 15 seconds for the server to start${NC}\n" + printf "${YELLOW}Please go to http://${formatted_addr}:3000${NC}\n\n" + echo "" +} -# Installation -docker service create \ - --name dokploy \ - --replicas 1 \ - --network dokploy-network \ - --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ - --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ - --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ - --publish published=3000,target=3000,mode=host \ - --update-parallelism 1 \ - --update-order stop-first \ - --constraint 'node.role == manager' \ - -e RELEASE_TAG=feature \ - dokploy/dokploy:feature +update_dokploy() { + echo "Updating Dokploy..." + + # Pull the latest feature image + docker pull dokploy/dokploy:feature -GREEN="\033[0;32m" -YELLOW="\033[1;33m" -BLUE="\033[0;34m" -NC="\033[0m" # No Color + # Update the service + docker service update --image dokploy/dokploy:feature dokploy -format_ip_for_url() { - local ip="$1" - if echo "$ip" | grep -q ':'; then - # IPv6 - echo "[${ip}]" - else - # IPv4 - echo "${ip}" - fi + echo "Dokploy has been updated to the latest feature version." } -formatted_addr=$(format_ip_for_url "$advertise_addr") -echo "" -printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n" -printf "${BLUE}Wait 15 seconds for the server to start${NC}\n" -printf "${YELLOW}Please go to http://${formatted_addr}:3000${NC}\n\n" -echo "" +# Main script execution +if [ "$1" = "update" ]; then + update_dokploy +else + install_dokploy +fi \ No newline at end of file From c1c5fc978b5be43067c3bae28d13afaaeacb9ac5 Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Mon, 30 Sep 2024 08:35:49 +0000 Subject: [PATCH 03/12] fix: fix number convert when string empty --- .../advanced/ports/update-port.tsx | 20 ++--------- .../application/domains/add-domain.tsx | 7 ++-- .../dashboard/compose/domains/add-domain.tsx | 7 ++-- apps/dokploy/components/ui/input.tsx | 35 ++++++++++++++++++- 4 files changed, 41 insertions(+), 28 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx b/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx index a068ce18..5ad25ed7 100644 --- a/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx @@ -17,7 +17,7 @@ import { FormLabel, FormMessage, } from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; +import { Input, NumberInput } from "@/components/ui/input"; import { Select, SelectContent, @@ -125,7 +125,7 @@ export const UpdatePort = ({ portId }: Props) => { Published Port - { if (value === "") { field.onChange(0); } else { - const number = Number.parseInt(value, 10); - if (!Number.isNaN(number)) { - field.onChange(number); - } + field.onChange(parseInt(value, 10)); } }} /> @@ -158,17 +155,6 @@ export const UpdatePort = ({ portId }: Props) => { placeholder="1-65535" {...field} value={field.value?.toString() || ""} - onChange={(e) => { - const value = e.target.value; - if (value === "") { - field.onChange(0); - } else { - const number = Number.parseInt(value, 10); - if (!Number.isNaN(number)) { - field.onChange(number); - } - } - }} /> diff --git a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx index 7ab67a29..79c54715 100644 --- a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx +++ b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx @@ -18,7 +18,7 @@ import { FormLabel, FormMessage, } from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; +import { Input, NumberInput } from "@/components/ui/input"; import { Select, SelectContent, @@ -228,12 +228,9 @@ export const AddDomain = ({ Container Port - { - field.onChange(Number.parseInt(e.target.value)); - }} /> diff --git a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx index 91f211d1..e3526db5 100644 --- a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx +++ b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx @@ -18,7 +18,7 @@ import { FormLabel, FormMessage, } from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; +import { Input, NumberInput } from "@/components/ui/input"; import { Select, SelectContent, @@ -364,12 +364,9 @@ export const AddDomainCompose = ({ Container Port - { - field.onChange(Number.parseInt(e.target.value)); - }} /> diff --git a/apps/dokploy/components/ui/input.tsx b/apps/dokploy/components/ui/input.tsx index 55b46e6d..d8b94c79 100644 --- a/apps/dokploy/components/ui/input.tsx +++ b/apps/dokploy/components/ui/input.tsx @@ -31,4 +31,37 @@ const Input = React.forwardRef( ); Input.displayName = "Input"; -export { Input }; +const NumberInput = React.forwardRef( + ({ className, errorMessage, ...props }, ref) => { + return ( + { + const value = e.target.value; + if (value === "") { + props.onChange?.(e); + } else { + const number = Number.parseInt(value, 10); + if (!Number.isNaN(number)) { + const syntheticEvent = { + ...e, + target: { + ...e.target, + value: number.toString(), + }, + }; + props.onChange?.(syntheticEvent as React.ChangeEvent); + } + } + }} + /> + ); + } +); +NumberInput.displayName = "NumberInput"; + + +export { Input, NumberInput }; From 5c225c8d42c5f6e62fa487d888e77d0f3e6d7ee1 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:00:01 -0600 Subject: [PATCH 04/12] fix(modal): close the modal after the creation #509 --- apps/dokploy/components/dashboard/project/add-compose.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/project/add-compose.tsx b/apps/dokploy/components/dashboard/project/add-compose.tsx index 658bf0ae..91dba943 100644 --- a/apps/dokploy/components/dashboard/project/add-compose.tsx +++ b/apps/dokploy/components/dashboard/project/add-compose.tsx @@ -39,7 +39,7 @@ import { slugify } from "@/lib/slug"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { CircuitBoard, HelpCircle } from "lucide-react"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; @@ -71,6 +71,7 @@ interface Props { export const AddCompose = ({ projectId, projectName }: Props) => { const utils = api.useUtils(); + const [visible, setVisible] = useState(false); const slug = slugify(projectName); const { data: servers } = api.server.withSSHKey.useQuery(); const { mutateAsync, isLoading, error, isError } = @@ -101,6 +102,7 @@ export const AddCompose = ({ projectId, projectName }: Props) => { }) .then(async () => { toast.success("Compose Created"); + setVisible(false); await utils.project.one.invalidate({ projectId, }); @@ -111,7 +113,7 @@ export const AddCompose = ({ projectId, projectName }: Props) => { }; return ( - + Date: Mon, 30 Sep 2024 15:00:32 -0600 Subject: [PATCH 05/12] fix(multi-server): show the servers ip instead of the main ip #502 --- .../mariadb/general/show-external-mariadb-credentials.tsx | 5 +++-- .../mongo/general/show-external-mongo-credentials.tsx | 6 +++--- .../mysql/general/show-external-mysql-credentials.tsx | 6 +++--- .../postgres/general/show-external-postgres-credentials.tsx | 6 +++--- .../redis/general/show-external-redis-credentials.tsx | 5 +++-- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/dokploy/components/dashboard/mariadb/general/show-external-mariadb-credentials.tsx b/apps/dokploy/components/dashboard/mariadb/general/show-external-mariadb-credentials.tsx index a908de07..c06cacaa 100644 --- a/apps/dokploy/components/dashboard/mariadb/general/show-external-mariadb-credentials.tsx +++ b/apps/dokploy/components/dashboard/mariadb/general/show-external-mariadb-credentials.tsx @@ -48,6 +48,7 @@ export const ShowExternalMariadbCredentials = ({ mariadbId }: Props) => { const { data, refetch } = api.mariadb.one.useQuery({ mariadbId }); const { mutateAsync, isLoading } = api.mariadb.saveExternalPort.useMutation(); const [connectionUrl, setConnectionUrl] = useState(""); + const getIp = data?.server?.ipAddress || ip; const form = useForm({ defaultValues: {}, resolver: zodResolver(DockerProviderSchema), @@ -79,7 +80,7 @@ export const ShowExternalMariadbCredentials = ({ mariadbId }: Props) => { const buildConnectionUrl = () => { const port = form.watch("externalPort") || data?.externalPort; - return `mariadb://${data?.databaseUser}:${data?.databasePassword}@${ip}:${port}/${data?.databaseName}`; + return `mariadb://${data?.databaseUser}:${data?.databasePassword}@${getIp}:${port}/${data?.databaseName}`; }; setConnectionUrl(buildConnectionUrl()); @@ -90,7 +91,7 @@ export const ShowExternalMariadbCredentials = ({ mariadbId }: Props) => { form, data?.databaseName, data?.databaseUser, - ip, + getIp, ]); return ( <> diff --git a/apps/dokploy/components/dashboard/mongo/general/show-external-mongo-credentials.tsx b/apps/dokploy/components/dashboard/mongo/general/show-external-mongo-credentials.tsx index 36d04c9c..7cfab289 100644 --- a/apps/dokploy/components/dashboard/mongo/general/show-external-mongo-credentials.tsx +++ b/apps/dokploy/components/dashboard/mongo/general/show-external-mongo-credentials.tsx @@ -48,7 +48,7 @@ export const ShowExternalMongoCredentials = ({ mongoId }: Props) => { const { data, refetch } = api.mongo.one.useQuery({ mongoId }); const { mutateAsync, isLoading } = api.mongo.saveExternalPort.useMutation(); const [connectionUrl, setConnectionUrl] = useState(""); - + const getIp = data?.server?.ipAddress || ip; const form = useForm({ defaultValues: {}, resolver: zodResolver(DockerProviderSchema), @@ -80,7 +80,7 @@ export const ShowExternalMongoCredentials = ({ mongoId }: Props) => { const buildConnectionUrl = () => { const port = form.watch("externalPort") || data?.externalPort; - return `mongodb://${data?.databaseUser}:${data?.databasePassword}@${ip}:${port}`; + return `mongodb://${data?.databaseUser}:${data?.databasePassword}@${getIp}:${port}`; }; setConnectionUrl(buildConnectionUrl()); @@ -90,7 +90,7 @@ export const ShowExternalMongoCredentials = ({ mongoId }: Props) => { data?.databasePassword, form, data?.databaseUser, - ip, + getIp, ]); return ( diff --git a/apps/dokploy/components/dashboard/mysql/general/show-external-mysql-credentials.tsx b/apps/dokploy/components/dashboard/mysql/general/show-external-mysql-credentials.tsx index 18c1adaf..009c8c3a 100644 --- a/apps/dokploy/components/dashboard/mysql/general/show-external-mysql-credentials.tsx +++ b/apps/dokploy/components/dashboard/mysql/general/show-external-mysql-credentials.tsx @@ -48,7 +48,7 @@ export const ShowExternalMysqlCredentials = ({ mysqlId }: Props) => { const { data, refetch } = api.mysql.one.useQuery({ mysqlId }); const { mutateAsync, isLoading } = api.mysql.saveExternalPort.useMutation(); const [connectionUrl, setConnectionUrl] = useState(""); - + const getIp = data?.server?.ipAddress || ip; const form = useForm({ defaultValues: {}, resolver: zodResolver(DockerProviderSchema), @@ -80,7 +80,7 @@ export const ShowExternalMysqlCredentials = ({ mysqlId }: Props) => { const buildConnectionUrl = () => { const port = form.watch("externalPort") || data?.externalPort; - return `mysql://${data?.databaseUser}:${data?.databasePassword}@${ip}:${port}/${data?.databaseName}`; + return `mysql://${data?.databaseUser}:${data?.databasePassword}@${getIp}:${port}/${data?.databaseName}`; }; setConnectionUrl(buildConnectionUrl()); @@ -91,7 +91,7 @@ export const ShowExternalMysqlCredentials = ({ mysqlId }: Props) => { data?.databaseName, data?.databaseUser, form, - ip, + getIp, ]); return ( <> diff --git a/apps/dokploy/components/dashboard/postgres/general/show-external-postgres-credentials.tsx b/apps/dokploy/components/dashboard/postgres/general/show-external-postgres-credentials.tsx index 28a96eb2..e1b4369a 100644 --- a/apps/dokploy/components/dashboard/postgres/general/show-external-postgres-credentials.tsx +++ b/apps/dokploy/components/dashboard/postgres/general/show-external-postgres-credentials.tsx @@ -48,6 +48,7 @@ export const ShowExternalPostgresCredentials = ({ postgresId }: Props) => { const { data, refetch } = api.postgres.one.useQuery({ postgresId }); const { mutateAsync, isLoading } = api.postgres.saveExternalPort.useMutation(); + const getIp = data?.server?.ipAddress || ip; const [connectionUrl, setConnectionUrl] = useState(""); const form = useForm({ @@ -79,10 +80,9 @@ export const ShowExternalPostgresCredentials = ({ postgresId }: Props) => { useEffect(() => { const buildConnectionUrl = () => { - const hostname = window.location.hostname; const port = form.watch("externalPort") || data?.externalPort; - return `postgresql://${data?.databaseUser}:${data?.databasePassword}@${ip}:${port}/${data?.databaseName}`; + return `postgresql://${data?.databaseUser}:${data?.databasePassword}@${getIp}:${port}/${data?.databaseName}`; }; setConnectionUrl(buildConnectionUrl()); @@ -92,7 +92,7 @@ export const ShowExternalPostgresCredentials = ({ postgresId }: Props) => { data?.databasePassword, form, data?.databaseName, - ip, + getIp, ]); return ( diff --git a/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx b/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx index b8832841..bcb26267 100644 --- a/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx +++ b/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx @@ -48,6 +48,7 @@ export const ShowExternalRedisCredentials = ({ redisId }: Props) => { const { data, refetch } = api.redis.one.useQuery({ redisId }); const { mutateAsync, isLoading } = api.redis.saveExternalPort.useMutation(); const [connectionUrl, setConnectionUrl] = useState(""); + const getIp = data?.server?.ipAddress || ip; const form = useForm({ defaultValues: {}, @@ -81,11 +82,11 @@ export const ShowExternalRedisCredentials = ({ redisId }: Props) => { const hostname = window.location.hostname; const port = form.watch("externalPort") || data?.externalPort; - return `redis://default:${data?.databasePassword}@${ip}:${port}`; + return `redis://default:${data?.databasePassword}@${getIp}:${port}`; }; setConnectionUrl(buildConnectionUrl()); - }, [data?.appName, data?.externalPort, data?.databasePassword, form, ip]); + }, [data?.appName, data?.externalPort, data?.databasePassword, form, getIp]); return ( <>
From fc38a425878ea5fe686c7989fcd7fa1bce46fd05 Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Tue, 1 Oct 2024 14:36:45 +0000 Subject: [PATCH 06/12] fix: convert final value --- apps/dokploy/components/ui/input.tsx | 39 +++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/dokploy/components/ui/input.tsx b/apps/dokploy/components/ui/input.tsx index d8b94c79..4a537cef 100644 --- a/apps/dokploy/components/ui/input.tsx +++ b/apps/dokploy/components/ui/input.tsx @@ -39,24 +39,27 @@ const NumberInput = React.forwardRef( className={cn("text-left", className)} ref={ref} {...props} - onChange={(e) => { - const value = e.target.value; - if (value === "") { - props.onChange?.(e); - } else { - const number = Number.parseInt(value, 10); - if (!Number.isNaN(number)) { - const syntheticEvent = { - ...e, - target: { - ...e.target, - value: number.toString(), - }, - }; - props.onChange?.(syntheticEvent as React.ChangeEvent); - } - } - }} + value={props.value === undefined ? undefined : String(props.value)} + onChange={(e) => { + const value = e.target.value; + if (value === "") { + props.onChange?.(e); + } else { + const number = Number.parseInt(value, 10); + if (!Number.isNaN(number)) { + const syntheticEvent = { + ...e, + target: { + ...e.target, + value: number, + }, + }; + props.onChange?.( + syntheticEvent as unknown as React.ChangeEvent + ); + } + } + }} /> ); } From 73bf5274f52f6bc16d207039be03753b5da68ba3 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:28:11 -0600 Subject: [PATCH 07/12] chore(version): bump version --- apps/dokploy/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index bb79865e..031e6728 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -1,6 +1,6 @@ { "name": "dokploy", - "version": "v0.9.3", + "version": "v0.9.4", "private": true, "license": "Apache-2.0", "type": "module", From dfd6764320cc1ebe6937fac4a3b0745028822349 Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Wed, 2 Oct 2024 18:22:21 +0000 Subject: [PATCH 08/12] styles: format code with prettier --- .../advanced/ports/update-port.tsx | 2 +- .../application/domains/add-domain.tsx | 5 +-- .../dashboard/compose/domains/add-domain.tsx | 5 +-- apps/dokploy/components/ui/input.tsx | 43 +++++++++---------- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx b/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx index 5ad25ed7..bd8135cb 100644 --- a/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx @@ -134,7 +134,7 @@ export const UpdatePort = ({ portId }: Props) => { if (value === "") { field.onChange(0); } else { - field.onChange(parseInt(value, 10)); + field.onChange(Number.parseInt(value, 10)); } }} /> diff --git a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx index 79c54715..4b5d4e09 100644 --- a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx +++ b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx @@ -228,10 +228,7 @@ export const AddDomain = ({ Container Port - + diff --git a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx index e3526db5..9f586467 100644 --- a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx +++ b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx @@ -364,10 +364,7 @@ export const AddDomainCompose = ({ Container Port - + diff --git a/apps/dokploy/components/ui/input.tsx b/apps/dokploy/components/ui/input.tsx index 4a537cef..8fe7ab28 100644 --- a/apps/dokploy/components/ui/input.tsx +++ b/apps/dokploy/components/ui/input.tsx @@ -40,31 +40,30 @@ const NumberInput = React.forwardRef( ref={ref} {...props} value={props.value === undefined ? undefined : String(props.value)} - onChange={(e) => { - const value = e.target.value; - if (value === "") { - props.onChange?.(e); - } else { - const number = Number.parseInt(value, 10); - if (!Number.isNaN(number)) { - const syntheticEvent = { - ...e, - target: { - ...e.target, - value: number, - }, - }; - props.onChange?.( - syntheticEvent as unknown as React.ChangeEvent - ); - } - } - }} + onChange={(e) => { + const value = e.target.value; + if (value === "") { + props.onChange?.(e); + } else { + const number = Number.parseInt(value, 10); + if (!Number.isNaN(number)) { + const syntheticEvent = { + ...e, + target: { + ...e.target, + value: number, + }, + }; + props.onChange?.( + syntheticEvent as unknown as React.ChangeEvent, + ); + } + } + }} /> ); - } + }, ); NumberInput.displayName = "NumberInput"; - export { Input, NumberInput }; From ecfca9419a5de78eec28fa23f17eeea6b1a96712 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:02:20 -0600 Subject: [PATCH 09/12] refactor: remove innecessary conversion --- .../advanced/ports/update-port.tsx | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx b/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx index bd8135cb..0ed9d2e2 100644 --- a/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/ports/update-port.tsx @@ -125,25 +125,14 @@ export const UpdatePort = ({ portId }: Props) => { Published Port - { - const value = e.target.value; - if (value === "") { - field.onChange(0); - } else { - field.onChange(Number.parseInt(value, 10)); - } - }} - /> + )} /> + { Target Port - + From 9745d12ac873f2eb0ea6c4411bc6bda8fb819f20 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 3 Oct 2024 00:48:00 -0600 Subject: [PATCH 10/12] fix(destinations): change admin to protected procedure --- apps/dokploy/server/api/routers/destination.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/server/api/routers/destination.ts b/apps/dokploy/server/api/routers/destination.ts index 6fcfa99b..b7bc9906 100644 --- a/apps/dokploy/server/api/routers/destination.ts +++ b/apps/dokploy/server/api/routers/destination.ts @@ -68,7 +68,7 @@ export const destinationRouter = createTRPCRouter({ const destination = await findDestinationById(input.destinationId); return destination; }), - all: adminProcedure.query(async () => { + all: protectedProcedure.query(async () => { return await db.query.destinations.findMany({}); }), remove: adminProcedure From a5eb4b0a7251f4fae6ea7a46e56e2f6d6a834dd8 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 3 Oct 2024 01:00:35 -0600 Subject: [PATCH 11/12] fix(compose): delete content when is remote server --- apps/dokploy/server/utils/providers/bitbucket.ts | 10 +++++----- apps/dokploy/server/utils/providers/github.ts | 10 +++++----- apps/dokploy/server/utils/providers/gitlab.ts | 10 +++++----- apps/dokploy/server/utils/providers/raw.ts | 1 + 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/apps/dokploy/server/utils/providers/bitbucket.ts b/apps/dokploy/server/utils/providers/bitbucket.ts index c6eb0bbd..3cbb4125 100644 --- a/apps/dokploy/server/utils/providers/bitbucket.ts +++ b/apps/dokploy/server/utils/providers/bitbucket.ts @@ -147,15 +147,15 @@ export const cloneRawBitbucketRepositoryRemote = async (compose: Compose) => { const bitbucketProvider = await findBitbucketById(bitbucketId); const basePath = COMPOSE_PATH; const outputPath = join(basePath, appName, "code"); - await recreateDirectory(outputPath); const repoclone = `bitbucket.org/${bitbucketOwner}/${bitbucketRepository}.git`; const cloneUrl = `https://${bitbucketProvider?.bitbucketUsername}:${bitbucketProvider?.appPassword}@${repoclone}`; try { - await execAsyncRemote( - serverId, - `git clone --branch ${bitbucketBranch} --depth 1 ${cloneUrl} ${outputPath}`, - ); + const command = ` + rm -rf ${outputPath}; + git clone --branch ${bitbucketBranch} --depth 1 ${cloneUrl} ${outputPath} + `; + await execAsyncRemote(serverId, command); } catch (error) { throw error; } diff --git a/apps/dokploy/server/utils/providers/github.ts b/apps/dokploy/server/utils/providers/github.ts index 68a401b2..e828d010 100644 --- a/apps/dokploy/server/utils/providers/github.ts +++ b/apps/dokploy/server/utils/providers/github.ts @@ -271,13 +271,13 @@ export const cloneRawGithubRepositoryRemote = async (compose: Compose) => { const octokit = authGithub(githubProvider); const token = await getGithubToken(octokit); const repoclone = `github.com/${owner}/${repository}.git`; - await recreateDirectory(outputPath); const cloneUrl = `https://oauth2:${token}@${repoclone}`; try { - await execAsyncRemote( - serverId, - `git clone --branch ${branch} --depth 1 ${cloneUrl} ${outputPath}`, - ); + const command = ` + rm -rf ${outputPath}; + git clone --branch ${branch} --depth 1 ${cloneUrl} ${outputPath} + `; + await execAsyncRemote(serverId, command); } catch (error) { throw error; } diff --git a/apps/dokploy/server/utils/providers/gitlab.ts b/apps/dokploy/server/utils/providers/gitlab.ts index 95649f5d..43f868d4 100644 --- a/apps/dokploy/server/utils/providers/gitlab.ts +++ b/apps/dokploy/server/utils/providers/gitlab.ts @@ -390,14 +390,14 @@ export const cloneRawGitlabRepositoryRemote = async (compose: Compose) => { await refreshGitlabToken(gitlabId); const basePath = COMPOSE_PATH; const outputPath = join(basePath, appName, "code"); - await recreateDirectory(outputPath); const repoclone = `gitlab.com/${gitlabPathNamespace}.git`; const cloneUrl = `https://oauth2:${gitlabProvider?.accessToken}@${repoclone}`; try { - await execAsyncRemote( - serverId, - `git clone --branch ${branch} --depth 1 ${cloneUrl} ${outputPath}`, - ); + const command = ` + rm -rf ${outputPath}; + git clone --branch ${branch} --depth 1 ${cloneUrl} ${outputPath} + `; + await execAsyncRemote(serverId, command); } catch (error) { throw error; } diff --git a/apps/dokploy/server/utils/providers/raw.ts b/apps/dokploy/server/utils/providers/raw.ts index f0fdcb5c..238216fa 100644 --- a/apps/dokploy/server/utils/providers/raw.ts +++ b/apps/dokploy/server/utils/providers/raw.ts @@ -70,6 +70,7 @@ export const createComposeFileRawRemote = async (compose: Compose) => { try { const encodedContent = encodeBase64(composeFile); const command = ` + rm -rf ${outputPath}; mkdir -p ${outputPath}; echo "${encodedContent}" | base64 -d > "${filePath}"; `; From 9b401059b031787ca5f776de44e1ee169244d865 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 3 Oct 2024 01:56:50 -0600 Subject: [PATCH 12/12] fix(registry): add option to login the registry in the remote server --- .../cluster/registry/add-docker-registry.tsx | 118 +- .../registry/update-docker-registry.tsx | 75 +- apps/dokploy/drizzle/0038_rapid_landau.sql | 1 + apps/dokploy/drizzle/meta/0038_snapshot.json | 3824 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + apps/dokploy/server/api/routers/registry.ts | 25 +- apps/dokploy/server/api/services/registry.ts | 18 +- apps/dokploy/server/db/schema/registry.ts | 11 +- 8 files changed, 4025 insertions(+), 54 deletions(-) create mode 100644 apps/dokploy/drizzle/0038_rapid_landau.sql create mode 100644 apps/dokploy/drizzle/meta/0038_snapshot.json diff --git a/apps/dokploy/components/dashboard/settings/cluster/registry/add-docker-registry.tsx b/apps/dokploy/components/dashboard/settings/cluster/registry/add-docker-registry.tsx index 193bf672..0a1ee614 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/registry/add-docker-registry.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/registry/add-docker-registry.tsx @@ -17,10 +17,18 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { AlertTriangle, Container } from "lucide-react"; -import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; @@ -36,10 +44,9 @@ const AddRegistrySchema = z.object({ password: z.string().min(1, { message: "Password is required", }), - registryUrl: z.string().min(1, { - message: "Registry URL is required", - }), + registryUrl: z.string(), imagePrefix: z.string(), + serverId: z.string().optional(), }); type AddRegistry = z.infer; @@ -48,9 +55,9 @@ export const AddRegistry = () => { const utils = api.useUtils(); const [isOpen, setIsOpen] = useState(false); const { mutateAsync, error, isError } = api.registry.create.useMutation(); + const { data: servers } = api.server.withSSHKey.useQuery(); const { mutateAsync: testRegistry, isLoading } = api.registry.testRegistry.useMutation(); - const router = useRouter(); const form = useForm({ defaultValues: { username: "", @@ -58,6 +65,7 @@ export const AddRegistry = () => { registryUrl: "", imagePrefix: "", registryName: "", + serverId: "", }, resolver: zodResolver(AddRegistrySchema), }); @@ -67,6 +75,7 @@ export const AddRegistry = () => { const registryUrl = form.watch("registryUrl"); const registryName = form.watch("registryName"); const imagePrefix = form.watch("imagePrefix"); + const serverId = form.watch("serverId"); useEffect(() => { form.reset({ @@ -74,6 +83,7 @@ export const AddRegistry = () => { password: "", registryUrl: "", imagePrefix: "", + serverId: "", }); }, [form, form.reset, form.formState.isSubmitSuccessful]); @@ -85,6 +95,7 @@ export const AddRegistry = () => { registryUrl: data.registryUrl, registryType: "cloud", imagePrefix: data.imagePrefix, + serverId: data.serverId, }) .then(async (data) => { await utils.registry.all.invalidate(); @@ -211,34 +222,77 @@ export const AddRegistry = () => { )} />
- - + .then((data) => { + if (data) { + toast.success("Registry Tested Successfully"); + } else { + toast.error("Registry Test Failed"); + } + }) + .catch(() => { + toast.error("Error to test the registry"); + }); + }} + > + Test Registry + + + diff --git a/apps/dokploy/components/dashboard/settings/cluster/registry/update-docker-registry.tsx b/apps/dokploy/components/dashboard/settings/cluster/registry/update-docker-registry.tsx index c84c019a..9c5f281e 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/registry/update-docker-registry.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/registry/update-docker-registry.tsx @@ -17,6 +17,15 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -34,10 +43,9 @@ const updateRegistry = z.object({ message: "Username is required", }), password: z.string(), - registryUrl: z.string().min(1, { - message: "Registry URL is required", - }), + registryUrl: z.string(), imagePrefix: z.string(), + serverId: z.string().optional(), }); type UpdateRegistry = z.infer; @@ -48,6 +56,8 @@ interface Props { export const UpdateDockerRegistry = ({ registryId }: Props) => { const utils = api.useUtils(); + const { data: servers } = api.server.withSSHKey.useQuery(); + const { mutateAsync: testRegistry, isLoading } = api.registry.testRegistry.useMutation(); const { data, refetch } = api.registry.one.useQuery( @@ -69,15 +79,19 @@ export const UpdateDockerRegistry = ({ registryId }: Props) => { username: "", password: "", registryUrl: "", + serverId: "", }, resolver: zodResolver(updateRegistry), }); + console.log(form.formState.errors); + const password = form.watch("password"); const username = form.watch("username"); const registryUrl = form.watch("registryUrl"); const registryName = form.watch("registryName"); const imagePrefix = form.watch("imagePrefix"); + const serverId = form.watch("serverId"); useEffect(() => { if (data) { @@ -87,6 +101,7 @@ export const UpdateDockerRegistry = ({ registryId }: Props) => { username: data.username || "", password: "", registryUrl: data.registryUrl || "", + serverId: "", }); } }, [form, form.reset, data]); @@ -99,6 +114,7 @@ export const UpdateDockerRegistry = ({ registryId }: Props) => { username: data.username, registryUrl: data.registryUrl, imagePrefix: data.imagePrefix, + serverId: data.serverId, }) .then(async (data) => { toast.success("Registry Updated"); @@ -224,13 +240,47 @@ export const UpdateDockerRegistry = ({ registryId }: Props) => { - - {isCloud && ( + +
+ + Select a server to test the registry. If you don't have a server + choose the default one. + + ( + + Server (Optional) + + + + + + + )} + /> - )} +
diff --git a/apps/dokploy/drizzle/0038_rapid_landau.sql b/apps/dokploy/drizzle/0038_rapid_landau.sql new file mode 100644 index 00000000..4f756c7c --- /dev/null +++ b/apps/dokploy/drizzle/0038_rapid_landau.sql @@ -0,0 +1 @@ +ALTER TABLE "registry" ALTER COLUMN "registryUrl" SET DEFAULT ''; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0038_snapshot.json b/apps/dokploy/drizzle/meta/0038_snapshot.json new file mode 100644 index 00000000..4eb2b5ec --- /dev/null +++ b/apps/dokploy/drizzle/meta/0038_snapshot.json @@ -0,0 +1,3824 @@ +{ + "id": "8ffdfaff-f166-42dc-ac77-4fd9309d736a", + "prevId": "19a70a39-f719-400b-b61e-6ddf1bcc6ac5", + "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 + }, + "buildArgs": { + "name": "buildArgs", + "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 + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "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 + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "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'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "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" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "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 + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "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" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "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 + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "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 + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "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 + }, + "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 + }, + "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 + }, + "enableLogRotation": { + "name": "enableLogRotation", + "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": 3000 + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domainType": { + "name": "domainType", + "type": "domainType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'application'" + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "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 + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "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" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "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 + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "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" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "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 + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "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" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "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 + }, + "serverId": { + "name": "serverId", + "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" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "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 + }, + "filePath": { + "name": "filePath", + "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 + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "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" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "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 + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "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'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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 + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "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, + "default": "''" + }, + "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": {} + }, + "public.discord": { + "name": "discord", + "schema": "", + "columns": { + "discordId": { + "name": "discordId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.email": { + "name": "email", + "schema": "", + "columns": { + "emailId": { + "name": "emailId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "smtpServer": { + "name": "smtpServer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "smtpPort": { + "name": "smtpPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fromAddress": { + "name": "fromAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "toAddress": { + "name": "toAddress", + "type": "text[]", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.notification": { + "name": "notification", + "schema": "", + "columns": { + "notificationId": { + "name": "notificationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appDeploy": { + "name": "appDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "appBuildError": { + "name": "appBuildError", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "databaseBackup": { + "name": "databaseBackup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dokployRestart": { + "name": "dokployRestart", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dockerCleanup": { + "name": "dockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "notificationType": { + "name": "notificationType", + "type": "notificationType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slackId": { + "name": "slackId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discordId": { + "name": "discordId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "emailId": { + "name": "emailId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "notification_slackId_slack_slackId_fk": { + "name": "notification_slackId_slack_slackId_fk", + "tableFrom": "notification", + "tableTo": "slack", + "columnsFrom": [ + "slackId" + ], + "columnsTo": [ + "slackId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_telegramId_telegram_telegramId_fk": { + "name": "notification_telegramId_telegram_telegramId_fk", + "tableFrom": "notification", + "tableTo": "telegram", + "columnsFrom": [ + "telegramId" + ], + "columnsTo": [ + "telegramId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_discordId_discord_discordId_fk": { + "name": "notification_discordId_discord_discordId_fk", + "tableFrom": "notification", + "tableTo": "discord", + "columnsFrom": [ + "discordId" + ], + "columnsTo": [ + "discordId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_emailId_email_emailId_fk": { + "name": "notification_emailId_email_emailId_fk", + "tableFrom": "notification", + "tableTo": "email", + "columnsFrom": [ + "emailId" + ], + "columnsTo": [ + "emailId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.slack": { + "name": "slack", + "schema": "", + "columns": { + "slackId": { + "name": "slackId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.telegram": { + "name": "telegram", + "schema": "", + "columns": { + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "botToken": { + "name": "botToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chatId": { + "name": "chatId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.ssh-key": { + "name": "ssh-key", + "schema": "", + "columns": { + "sshKeyId": { + "name": "sshKeyId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publicKey": { + "name": "publicKey", + "type": "text", + "primaryKey": false, + "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 + }, + "lastUsedAt": { + "name": "lastUsedAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.git_provider": { + "name": "git_provider", + "schema": "", + "columns": { + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerType": { + "name": "providerType", + "type": "gitProviderType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "git_provider_authId_auth_id_fk": { + "name": "git_provider_authId_auth_id_fk", + "tableFrom": "git_provider", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.bitbucket": { + "name": "bitbucket", + "schema": "", + "columns": { + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "bitbucketUsername": { + "name": "bitbucketUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "appPassword": { + "name": "appPassword", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketWorkspaceName": { + "name": "bitbucketWorkspaceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bitbucket_gitProviderId_git_provider_gitProviderId_fk": { + "name": "bitbucket_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "bitbucket", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.github": { + "name": "github", + "schema": "", + "columns": { + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "githubAppName": { + "name": "githubAppName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubAppId": { + "name": "githubAppId", + "type": "integer", + "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 + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "github_gitProviderId_git_provider_gitProviderId_fk": { + "name": "github_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "github", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.gitlab": { + "name": "gitlab", + "schema": "", + "columns": { + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "application_id": { + "name": "application_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_name": { + "name": "group_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "gitlab_gitProviderId_git_provider_gitProviderId_fk": { + "name": "gitlab_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "gitlab", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.server": { + "name": "server", + "schema": "", + "columns": { + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'root'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sshKeyId": { + "name": "sshKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "server_adminId_admin_adminId_fk": { + "name": "server_adminId_admin_adminId_fk", + "tableFrom": "server", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "server_sshKeyId_ssh-key_sshKeyId_fk": { + "name": "server_sshKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "server", + "tableTo": "ssh-key", + "columnsFrom": [ + "sshKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application" + ] + }, + "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", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + } + }, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 0592acd4..5a84e0b1 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -267,6 +267,13 @@ "when": 1726988289562, "tag": "0037_legal_namor", "breakpoints": true + }, + { + "idx": 38, + "version": "6", + "when": 1727942090102, + "tag": "0038_rapid_landau", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/server/api/routers/registry.ts b/apps/dokploy/server/api/routers/registry.ts index 8fd8d2ce..ca132966 100644 --- a/apps/dokploy/server/api/routers/registry.ts +++ b/apps/dokploy/server/api/routers/registry.ts @@ -7,7 +7,7 @@ import { apiUpdateRegistry, } from "@/server/db/schema"; import { initializeRegistry } from "@/server/setup/registry-setup"; -import { execAsync } from "@/server/utils/process/execAsync"; +import { execAsync, execAsyncRemote } from "@/server/utils/process/execAsync"; import { manageRegistry } from "@/server/utils/traefik/registry"; import { TRPCError } from "@trpc/server"; import { @@ -58,7 +58,13 @@ export const registryRouter = createTRPCRouter({ .mutation(async ({ input }) => { try { const loginCommand = `echo ${input.password} | docker login ${input.registryUrl} --username ${input.username} --password-stdin`; - await execAsync(loginCommand); + + if (input.serverId && input.serverId !== "none") { + await execAsyncRemote(input.serverId, loginCommand); + } else { + await execAsync(loginCommand); + } + return true; } catch (error) { console.log("Error Registry:", error); @@ -78,6 +84,7 @@ export const registryRouter = createTRPCRouter({ ? input.registryUrl : "dokploy-registry.docker.localhost", imagePrefix: null, + serverId: undefined, }); await manageRegistry(selfHostedRegistry); @@ -86,3 +93,17 @@ export const registryRouter = createTRPCRouter({ return selfHostedRegistry; }), }); + +const shellEscape = (str: string) => { + const ret = []; + let s = str; + if (/[^A-Za-z0-9_\/:=-]/.test(s)) { + s = `'${s.replace(/'/g, "'\\''")}'`; + s = s + .replace(/^(?:'')+/g, "") // unduplicate single-quote at the beginning + .replace(/\\'''/g, "\\'"); // remove non-escaped single-quote if there are enclosed between 2 escaped + } + ret.push(s); + + return ret.join(" "); +}; diff --git a/apps/dokploy/server/api/services/registry.ts b/apps/dokploy/server/api/services/registry.ts index 83dcc2a2..f7c20af6 100644 --- a/apps/dokploy/server/api/services/registry.ts +++ b/apps/dokploy/server/api/services/registry.ts @@ -2,7 +2,7 @@ import { db } from "@/server/db"; import { type apiCreateRegistry, registry } from "@/server/db/schema"; import { initializeRegistry } from "@/server/setup/registry-setup"; import { removeService } from "@/server/utils/docker/utils"; -import { execAsync } from "@/server/utils/process/execAsync"; +import { execAsync, execAsyncRemote } from "@/server/utils/process/execAsync"; import { manageRegistry, removeSelfHostedRegistry, @@ -32,9 +32,10 @@ export const createRegistry = async (input: typeof apiCreateRegistry._type) => { message: "Error input: Inserting registry", }); } - - if (newRegistry.registryType === "cloud") { - const loginCommand = `echo ${input.password} | docker login ${input.registryUrl} --username ${input.username} --password-stdin`; + const loginCommand = `echo ${input.password} | docker login ${input.registryUrl} --username ${input.username} --password-stdin`; + if (input.serverId && input.serverId !== "none") { + await execAsyncRemote(input.serverId, loginCommand); + } else if (newRegistry.registryType === "cloud") { await execAsync(loginCommand); } @@ -76,7 +77,7 @@ export const removeRegistry = async (registryId: string) => { export const updateRegistry = async ( registryId: string, - registryData: Partial, + registryData: Partial & { serverId?: string | null }, ) => { try { const response = await db @@ -92,6 +93,13 @@ export const updateRegistry = async ( await manageRegistry(response); await initializeRegistry(response.username, response.password); } + const loginCommand = `echo ${response?.password} | docker login ${response?.registryUrl} --username ${response?.username} --password-stdin`; + + if (registryData?.serverId && registryData?.serverId !== "none") { + await execAsyncRemote(registryData.serverId, loginCommand); + } else if (response?.registryType === "cloud") { + await execAsync(loginCommand); + } return response; } catch (error) { diff --git a/apps/dokploy/server/db/schema/registry.ts b/apps/dokploy/server/db/schema/registry.ts index 832de9b1..ee1bab94 100644 --- a/apps/dokploy/server/db/schema/registry.ts +++ b/apps/dokploy/server/db/schema/registry.ts @@ -23,7 +23,7 @@ export const registry = pgTable("registry", { imagePrefix: text("imagePrefix"), username: text("username").notNull(), password: text("password").notNull(), - registryUrl: text("registryUrl").notNull(), + registryUrl: text("registryUrl").notNull().default(""), createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), @@ -45,7 +45,7 @@ const createSchema = createInsertSchema(registry, { registryName: z.string().min(1), username: z.string().min(1), password: z.string().min(1), - registryUrl: z.string().min(1), + registryUrl: z.string(), adminId: z.string().min(1), registryId: z.string().min(1), registryType: z.enum(["selfHosted", "cloud"]), @@ -62,7 +62,10 @@ export const apiCreateRegistry = createSchema registryType: z.enum(["selfHosted", "cloud"]), imagePrefix: z.string().nullable().optional(), }) - .required(); + .required() + .extend({ + serverId: z.string().optional(), + }); export const apiTestRegistry = createSchema.pick({}).extend({ registryName: z.string().min(1), @@ -71,6 +74,7 @@ export const apiTestRegistry = createSchema.pick({}).extend({ registryUrl: z.string(), registryType: z.enum(["selfHosted", "cloud"]), imagePrefix: z.string().nullable().optional(), + serverId: z.string().optional(), }); export const apiRemoveRegistry = createSchema @@ -87,6 +91,7 @@ export const apiFindOneRegistry = createSchema export const apiUpdateRegistry = createSchema.partial().extend({ registryId: z.string().min(1), + serverId: z.string().optional(), }); export const apiEnableSelfHostedRegistry = createSchema