diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..958b26c9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +.git +.gitignore +*.md +dist \ No newline at end of file diff --git a/.env.production.example b/.env.production.example new file mode 100644 index 00000000..41e934c3 --- /dev/null +++ b/.env.production.example @@ -0,0 +1,3 @@ +DATABASE_URL="postgres://dokploy:amukds4wi9001583845717ad2@dokploy-postgres:5432/dokploy" +PORT=3000 +NODE_ENV=production \ No newline at end of file diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index d906938e..51e36ede 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -3,8 +3,15 @@ on: pull_request: branches: - main + - canary + + push: + branches: + - main + - canary jobs: - build: + build-app: + if: github.event_name == 'pull_request' runs-on: ubuntu-20.04 strategy: matrix: @@ -22,4 +29,53 @@ jobs: - name: Install dependencies run: pnpm install - name: Run Build - run: pnpm build \ No newline at end of file + run: pnpm build + + + build-docker-on-pr: + if: github.event_name == 'pull_request' + needs: build-app + runs-on: ubuntu-latest + steps: + - name: Check out the code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Prepare .env file + run: | + cp .env.production.example .env.production + + - name: Run custom Docker build script + run: | + chmod +x ./docker/build.sh + echo "Building Docker image for ${{ github.base_ref }}" + ./docker/build.sh ${{ github.base_ref == 'canary' && 'canary' || '' }} + + build-and-push-docker-on-push: + if: github.event_name == 'push' + runs-on: ubuntu-latest + steps: + - name: Check out the code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Prepare .env file + run: | + cp .env.production.example .env.production + + - name: Build and push Docker image using custom script + run: | + chmod +x ./docker/build.sh + chmod +x ./docker/push.sh + ./docker/build.sh ${{ github.ref_name == 'canary' && 'canary' || '' }} + ./docker/push.sh ${{ github.ref_name == 'canary' && 'canary' || '' }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 71a3816e..bfbda236 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ .pnp.js /redis-data traefik.yml +.docker +.env.production # testing /coverage diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8d0a2d44..bbda3053 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,12 +49,16 @@ feat: add new feature ``` + + ## Setup +Before you start, please make the clone based on the `canary` branch, since the `main` branch is the source of truth and should always reflect the latest stable release, also the PRs will be merged to the `canary` branch. + ```bash git clone https://github.com/dokploy/dokploy.git cd dokploy -npm install +pnpm install cp .env.example .env ``` @@ -62,28 +66,40 @@ cp .env.example .env Is required to have **Docker** installed on your machine. + +### Setup + +Run the command that will spin up all the required services and files. + ```bash -npm run dev +pnpm run setup ``` +Now run the development server. + +```bash +pnpm run dev +``` + + Go to http://localhost:3000 to see the development server ## Build ```bash -npm run build +pnpm run build ``` ## Docker To build the docker image ```bash -npm run docker:build +pnpm run docker:build ``` To push the docker image ```bash -npm run docker:push +pnpm run docker:push ``` ## Password Reset diff --git a/components/auth/login-2fa.tsx b/components/auth/login-2fa.tsx index 46d82cbe..17b2d483 100644 --- a/components/auth/login-2fa.tsx +++ b/components/auth/login-2fa.tsx @@ -65,7 +65,7 @@ export const Login2FA = ({ authId }: Props) => { duration: 2000, }); - push("/dashboard"); + push("/dashboard/projects"); }) .catch(() => { toast.error("Signin failed", { diff --git a/components/dashboard/application/enviroment/show.tsx b/components/dashboard/application/environment/show.tsx similarity index 73% rename from components/dashboard/application/enviroment/show.tsx rename to components/dashboard/application/environment/show.tsx index 063f7b1a..efd218e2 100644 --- a/components/dashboard/application/enviroment/show.tsx +++ b/components/dashboard/application/environment/show.tsx @@ -21,19 +21,19 @@ import { api } from "@/utils/api"; import { toast } from "sonner"; import { Textarea } from "@/components/ui/textarea"; -const addEnviromentSchema = z.object({ - enviroment: z.string(), +const addEnvironmentSchema = z.object({ + environment: z.string(), }); -type EnviromentSchema = z.infer; +type EnvironmentSchema = z.infer; interface Props { applicationId: string; } -export const ShowEnviroment = ({ applicationId }: Props) => { +export const ShowEnvironment = ({ applicationId }: Props) => { const { mutateAsync, isLoading } = - api.application.saveEnviroment.useMutation(); + api.application.saveEnvironment.useMutation(); const { data, refetch } = api.application.one.useQuery( { @@ -43,32 +43,32 @@ export const ShowEnviroment = ({ applicationId }: Props) => { enabled: !!applicationId, }, ); - const form = useForm({ + const form = useForm({ defaultValues: { - enviroment: "", + environment: "", }, - resolver: zodResolver(addEnviromentSchema), + resolver: zodResolver(addEnvironmentSchema), }); useEffect(() => { if (data) { form.reset({ - enviroment: data.env || "", + environment: data.env || "", }); } }, [form.reset, data, form]); - const onSubmit = async (data: EnviromentSchema) => { + const onSubmit = async (data: EnvironmentSchema) => { mutateAsync({ - env: data.enviroment, + env: data.environment, applicationId, }) .then(async () => { - toast.success("Enviroments Added"); + toast.success("Environments Added"); await refetch(); }) .catch(() => { - toast.error("Error to add enviroment"); + toast.error("Error to add environment"); }); }; @@ -76,9 +76,9 @@ export const ShowEnviroment = ({ applicationId }: Props) => {
- Enviroment Settings + Environment Settings - You can add enviroment variables to your resource. + You can add environment variables to your resource. @@ -90,7 +90,7 @@ export const ShowEnviroment = ({ applicationId }: Props) => { > ( diff --git a/components/dashboard/mariadb/enviroment/show-mariadb-enviroment.tsx b/components/dashboard/mariadb/environment/show-mariadb-environment.tsx similarity index 72% rename from components/dashboard/mariadb/enviroment/show-mariadb-enviroment.tsx rename to components/dashboard/mariadb/environment/show-mariadb-environment.tsx index 4e4708e2..cfc89271 100644 --- a/components/dashboard/mariadb/enviroment/show-mariadb-enviroment.tsx +++ b/components/dashboard/mariadb/environment/show-mariadb-environment.tsx @@ -21,18 +21,18 @@ import { api } from "@/utils/api"; import { toast } from "sonner"; import { Textarea } from "@/components/ui/textarea"; -const addEnviromentSchema = z.object({ - enviroment: z.string(), +const addEnvironmentSchema = z.object({ + environment: z.string(), }); -type EnviromentSchema = z.infer; +type EnvironmentSchema = z.infer; interface Props { mariadbId: string; } -export const ShowMariadbEnviroment = ({ mariadbId }: Props) => { - const { mutateAsync, isLoading } = api.mariadb.saveEnviroment.useMutation(); +export const ShowMariadbEnvironment = ({ mariadbId }: Props) => { + const { mutateAsync, isLoading } = api.mariadb.saveEnvironment.useMutation(); const { data, refetch } = api.mariadb.one.useQuery( { @@ -42,32 +42,32 @@ export const ShowMariadbEnviroment = ({ mariadbId }: Props) => { enabled: !!mariadbId, }, ); - const form = useForm({ + const form = useForm({ defaultValues: { - enviroment: "", + environment: "", }, - resolver: zodResolver(addEnviromentSchema), + resolver: zodResolver(addEnvironmentSchema), }); useEffect(() => { if (data) { form.reset({ - enviroment: data.env || "", + environment: data.env || "", }); } }, [form.reset, data, form]); - const onSubmit = async (data: EnviromentSchema) => { + const onSubmit = async (data: EnvironmentSchema) => { mutateAsync({ - env: data.enviroment, + env: data.environment, mariadbId, }) .then(async () => { - toast.success("Enviroments Added"); + toast.success("Environments Added"); await refetch(); }) .catch(() => { - toast.error("Error to add enviroment"); + toast.error("Error to add environment"); }); }; @@ -75,9 +75,9 @@ export const ShowMariadbEnviroment = ({ mariadbId }: Props) => {
- Enviroment Settings + Environment Settings - You can add enviroment variables to your database. + You can add environment variables to your database. @@ -89,7 +89,7 @@ export const ShowMariadbEnviroment = ({ mariadbId }: Props) => { > ( diff --git a/components/dashboard/mongo/enviroment/show-mongo-enviroment.tsx b/components/dashboard/mongo/environment/show-mongo-environment.tsx similarity index 72% rename from components/dashboard/mongo/enviroment/show-mongo-enviroment.tsx rename to components/dashboard/mongo/environment/show-mongo-environment.tsx index 24080adf..0c99cede 100644 --- a/components/dashboard/mongo/enviroment/show-mongo-enviroment.tsx +++ b/components/dashboard/mongo/environment/show-mongo-environment.tsx @@ -21,18 +21,18 @@ import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; -const addEnviromentSchema = z.object({ - enviroment: z.string(), +const addEnvironmentSchema = z.object({ + environment: z.string(), }); -type EnviromentSchema = z.infer; +type EnvironmentSchema = z.infer; interface Props { mongoId: string; } -export const ShowMongoEnviroment = ({ mongoId }: Props) => { - const { mutateAsync, isLoading } = api.mongo.saveEnviroment.useMutation(); +export const ShowMongoEnvironment = ({ mongoId }: Props) => { + const { mutateAsync, isLoading } = api.mongo.saveEnvironment.useMutation(); const { data, refetch } = api.mongo.one.useQuery( { @@ -42,32 +42,32 @@ export const ShowMongoEnviroment = ({ mongoId }: Props) => { enabled: !!mongoId, }, ); - const form = useForm({ + const form = useForm({ defaultValues: { - enviroment: "", + environment: "", }, - resolver: zodResolver(addEnviromentSchema), + resolver: zodResolver(addEnvironmentSchema), }); useEffect(() => { if (data) { form.reset({ - enviroment: data.env || "", + environment: data.env || "", }); } }, [form.reset, data, form]); - const onSubmit = async (data: EnviromentSchema) => { + const onSubmit = async (data: EnvironmentSchema) => { mutateAsync({ - env: data.enviroment, + env: data.environment, mongoId, }) .then(async () => { - toast.success("Enviroments Added"); + toast.success("Environments Added"); await refetch(); }) .catch(() => { - toast.error("Error to add enviroment"); + toast.error("Error to add environment"); }); }; @@ -75,9 +75,9 @@ export const ShowMongoEnviroment = ({ mongoId }: Props) => {
- Enviroment Settings + Environment Settings - You can add enviroment variables to your database. + You can add environment variables to your database. @@ -89,7 +89,7 @@ export const ShowMongoEnviroment = ({ mongoId }: Props) => { > ( diff --git a/components/dashboard/mysql/enviroment/show-mysql-enviroment.tsx b/components/dashboard/mysql/environment/show-mysql-environment.tsx similarity index 72% rename from components/dashboard/mysql/enviroment/show-mysql-enviroment.tsx rename to components/dashboard/mysql/environment/show-mysql-environment.tsx index a3da6f05..2135d708 100644 --- a/components/dashboard/mysql/enviroment/show-mysql-enviroment.tsx +++ b/components/dashboard/mysql/environment/show-mysql-environment.tsx @@ -21,18 +21,18 @@ import { api } from "@/utils/api"; import { toast } from "sonner"; import { Textarea } from "@/components/ui/textarea"; -const addEnviromentSchema = z.object({ - enviroment: z.string(), +const addEnvironmentSchema = z.object({ + environment: z.string(), }); -type EnviromentSchema = z.infer; +type EnvironmentSchema = z.infer; interface Props { mysqlId: string; } -export const ShowMysqlEnviroment = ({ mysqlId }: Props) => { - const { mutateAsync, isLoading } = api.mysql.saveEnviroment.useMutation(); +export const ShowMysqlEnvironment = ({ mysqlId }: Props) => { + const { mutateAsync, isLoading } = api.mysql.saveEnvironment.useMutation(); const { data, refetch } = api.mysql.one.useQuery( { @@ -42,32 +42,32 @@ export const ShowMysqlEnviroment = ({ mysqlId }: Props) => { enabled: !!mysqlId, }, ); - const form = useForm({ + const form = useForm({ defaultValues: { - enviroment: "", + environment: "", }, - resolver: zodResolver(addEnviromentSchema), + resolver: zodResolver(addEnvironmentSchema), }); useEffect(() => { if (data) { form.reset({ - enviroment: data.env || "", + environment: data.env || "", }); } }, [form.reset, data, form]); - const onSubmit = async (data: EnviromentSchema) => { + const onSubmit = async (data: EnvironmentSchema) => { mutateAsync({ - env: data.enviroment, + env: data.environment, mysqlId, }) .then(async () => { - toast.success("Enviroments Added"); + toast.success("Environments Added"); await refetch(); }) .catch(() => { - toast.error("Error to add enviroment"); + toast.error("Error to add environment"); }); }; @@ -75,9 +75,9 @@ export const ShowMysqlEnviroment = ({ mysqlId }: Props) => {
- Enviroment Settings + Environment Settings - You can add enviroment variables to your database. + You can add environment variables to your database. @@ -89,7 +89,7 @@ export const ShowMysqlEnviroment = ({ mysqlId }: Props) => { > ( diff --git a/components/dashboard/postgres/enviroment/show-postgres-enviroment.tsx b/components/dashboard/postgres/environment/show-postgres-environment.tsx similarity index 72% rename from components/dashboard/postgres/enviroment/show-postgres-enviroment.tsx rename to components/dashboard/postgres/environment/show-postgres-environment.tsx index 3e9e470a..8a8b792d 100644 --- a/components/dashboard/postgres/enviroment/show-postgres-enviroment.tsx +++ b/components/dashboard/postgres/environment/show-postgres-environment.tsx @@ -21,18 +21,18 @@ import { api } from "@/utils/api"; import { toast } from "sonner"; import { Textarea } from "@/components/ui/textarea"; -const addEnviromentSchema = z.object({ - enviroment: z.string(), +const addEnvironmentSchema = z.object({ + environment: z.string(), }); -type EnviromentSchema = z.infer; +type EnvironmentSchema = z.infer; interface Props { postgresId: string; } -export const ShowPostgresEnviroment = ({ postgresId }: Props) => { - const { mutateAsync, isLoading } = api.postgres.saveEnviroment.useMutation(); +export const ShowPostgresEnvironment = ({ postgresId }: Props) => { + const { mutateAsync, isLoading } = api.postgres.saveEnvironment.useMutation(); const { data, refetch } = api.postgres.one.useQuery( { @@ -42,32 +42,32 @@ export const ShowPostgresEnviroment = ({ postgresId }: Props) => { enabled: !!postgresId, }, ); - const form = useForm({ + const form = useForm({ defaultValues: { - enviroment: "", + environment: "", }, - resolver: zodResolver(addEnviromentSchema), + resolver: zodResolver(addEnvironmentSchema), }); useEffect(() => { if (data) { form.reset({ - enviroment: data.env || "", + environment: data.env || "", }); } }, [form.reset, data, form]); - const onSubmit = async (data: EnviromentSchema) => { + const onSubmit = async (data: EnvironmentSchema) => { mutateAsync({ - env: data.enviroment, + env: data.environment, postgresId, }) .then(async () => { - toast.success("Enviroments Added"); + toast.success("Environments Added"); await refetch(); }) .catch(() => { - toast.error("Error to add enviroment"); + toast.error("Error to add environment"); }); }; @@ -75,9 +75,9 @@ export const ShowPostgresEnviroment = ({ postgresId }: Props) => {
- Enviroment Settings + Environment Settings - You can add enviroment variables to your database. + You can add environment variables to your database. @@ -89,7 +89,7 @@ export const ShowPostgresEnviroment = ({ postgresId }: Props) => { > ( diff --git a/components/dashboard/projects/add.tsx b/components/dashboard/projects/add.tsx index d2b91ce1..a2797539 100644 --- a/components/dashboard/projects/add.tsx +++ b/components/dashboard/projects/add.tsx @@ -21,7 +21,8 @@ import { Textarea } from "@/components/ui/textarea"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { AlertTriangle, PlusIcon } from "lucide-react"; -import { useEffect } from "react"; +import { useRouter } from "next/router"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; @@ -37,10 +38,9 @@ type AddProject = z.infer; export const AddProject = () => { const utils = api.useUtils(); - - const { mutateAsync, isLoading, error, isError } = - api.project.create.useMutation(); - + const [isOpen, setIsOpen] = useState(false); + const { mutateAsync, error, isError } = api.project.create.useMutation(); + const router = useRouter(); const form = useForm({ defaultValues: { description: "", @@ -61,16 +61,19 @@ export const AddProject = () => { name: data.name, description: data.description, }) - .then(async () => { - toast.success("Project Created"); + .then(async (data) => { await utils.project.all.invalidate(); + toast.success("Project Created"); + setIsOpen(false); + router.push(`/dashboard/project/${data.projectId}`); }) .catch(() => { toast.error("Error to create a project"); }); }; + return ( - +