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 (
+
+
+
+ Generate Domain
+
+
+
+
+
+
+ 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
-
+
) : (
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),