From f230bda1f77cbb6da4d660b769ee4007e7572a39 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 24 Jun 2024 00:47:40 -0600 Subject: [PATCH] feat(#40): add domain generation by traefik.me --- .../application/domains/generate-domain.tsx | 69 +++++++++++++++++++ .../application/domains/show-domains.tsx | 30 +++++--- server/api/routers/domain.ts | 6 ++ server/api/services/domain.ts | 28 +++++++- 4 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 components/dashboard/application/domains/generate-domain.tsx diff --git a/components/dashboard/application/domains/generate-domain.tsx b/components/dashboard/application/domains/generate-domain.tsx new file mode 100644 index 00000000..483d2ec0 --- /dev/null +++ b/components/dashboard/application/domains/generate-domain.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog"; +import { Button } from "@/components/ui/button"; +import { api } from "@/utils/api"; +import { RefreshCcw, TrashIcon } from "lucide-react"; +import { toast } from "sonner"; + +interface Props { + applicationId: string; +} +export const GenerateDomain = ({ applicationId }: Props) => { + const { mutateAsync, isLoading } = api.domain.generateDomain.useMutation(); + const utils = api.useUtils(); + return ( + + + + + + + + Are you sure to generate a new domain? + + + This will generate a new domain and will be used to access to the + application + + + + Cancel + { + await mutateAsync({ + applicationId, + }) + .then((data) => { + utils.domain.byApplicationId.invalidate({ + applicationId: applicationId, + }); + utils.application.readTraefikConfig.invalidate({ + applicationId: applicationId, + }); + toast.success("Generated Domain succesfully"); + }) + .catch(() => { + toast.error("Error to generate Domain"); + }); + }} + > + Confirm + + + + + ); +}; diff --git a/components/dashboard/application/domains/show-domains.tsx b/components/dashboard/application/domains/show-domains.tsx index c12d9140..d4df0366 100644 --- a/components/dashboard/application/domains/show-domains.tsx +++ b/components/dashboard/application/domains/show-domains.tsx @@ -6,7 +6,7 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; -import { ExternalLink, GlobeIcon } from "lucide-react"; +import { ExternalLink, GlobeIcon, RefreshCcw } from "lucide-react"; import { Button } from "@/components/ui/button"; import { api } from "@/utils/api"; import { Input } from "@/components/ui/input"; @@ -14,6 +14,7 @@ import { DeleteDomain } from "./delete-domain"; import Link from "next/link"; import { AddDomain } from "./add-domain"; import { UpdateDomain } from "./update-domain"; +import { GenerateDomain } from "./generate-domain"; interface Props { applicationId: string; @@ -31,7 +32,7 @@ export const ShowDomains = ({ applicationId }: Props) => { return (
- +
Domains @@ -39,11 +40,16 @@ export const ShowDomains = ({ applicationId }: Props) => {
- {data && data?.length > 0 && ( - - Add Domain - - )} +
+ {data && data?.length > 0 && ( + + Add Domain + + )} + {data && data?.length > 0 && ( + + )} +
{data?.length === 0 ? ( @@ -53,9 +59,13 @@ export const ShowDomains = ({ applicationId }: Props) => { To access to the application is required to set at least 1 domain - - Add Domain - +
+ + Add Domain + + + +
) : (
diff --git a/server/api/routers/domain.ts b/server/api/routers/domain.ts index ace938c0..31c9028e 100644 --- a/server/api/routers/domain.ts +++ b/server/api/routers/domain.ts @@ -12,6 +12,7 @@ import { createDomain, findDomainById, findDomainsByApplicationId, + generateDomain, removeDomainById, updateDomainById, } from "../services/domain"; @@ -35,6 +36,11 @@ export const domainRouter = createTRPCRouter({ .query(async ({ input }) => { return await findDomainsByApplicationId(input.applicationId); }), + generateDomain: protectedProcedure + .input(apiFindDomainByApplication) + .mutation(async ({ input }) => { + return generateDomain(input); + }), update: protectedProcedure .input(apiUpdateDomain) .mutation(async ({ input }) => { diff --git a/server/api/services/domain.ts b/server/api/services/domain.ts index 05a1cfa6..3553bbe9 100644 --- a/server/api/services/domain.ts +++ b/server/api/services/domain.ts @@ -1,9 +1,15 @@ import { db } from "@/server/db"; -import { type apiCreateDomain, domains } from "@/server/db/schema"; +import { + type apiCreateDomain, + type apiFindDomainByApplication, + domains, +} from "@/server/db/schema"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { findApplicationById } from "./application"; import { manageDomain } from "@/server/utils/traefik/domain"; +import { findAdmin } from "./admin"; +import { generateRandomDomain } from "@/templates/utils"; export type Domain = typeof domains.$inferSelect; @@ -29,6 +35,26 @@ export const createDomain = async (input: typeof apiCreateDomain._type) => { await manageDomain(application, domain); }); }; + +export const generateDomain = async ( + input: typeof apiFindDomainByApplication._type, +) => { + const application = await findApplicationById(input.applicationId); + const admin = await findAdmin(); + const domain = await createDomain({ + applicationId: application.applicationId, + host: generateRandomDomain({ + serverIp: admin.serverIp || "", + projectName: application.appName, + }), + port: process.env.NODE_ENV === "development" ? 3000 : 80, + certificateType: "none", + https: false, + path: "/", + }); + + return domain; +}; export const findDomainById = async (domainId: string) => { const domain = await db.query.domains.findFirst({ where: eq(domains.domainId, domainId),