From 0d30ac2ddc3516b60ecbcbbac1736ff2cfd4e10f Mon Sep 17 00:00:00 2001 From: Milo Schwartz Date: Sat, 21 Dec 2024 14:11:10 -0500 Subject: [PATCH] org setup wip --- server/routers/org/createOrg.ts | 107 +++--- .../[orgId]/settings/components/Header.tsx | 11 +- src/app/[orgId]/settings/layout.tsx | 18 +- .../components/CreateShareLinkForm.tsx | 2 +- src/app/globals.css | 13 +- src/app/setup/layout.tsx | 6 +- src/app/setup/page.tsx | 336 ++++++++++-------- src/components/ui/command.tsx | 2 +- src/components/ui/dropdown-menu.tsx | 2 +- src/components/ui/popover.tsx | 2 +- src/components/ui/select.tsx | 2 +- 11 files changed, 282 insertions(+), 219 deletions(-) diff --git a/server/routers/org/createOrg.ts b/server/routers/org/createOrg.ts index 07ee2240ece50b1ea8c4f13f3b6778ad349c17ee..b8567442903c931ba5a009a6ddcd937a03a2711e 100644 --- a/server/routers/org/createOrg.ts +++ b/server/routers/org/createOrg.ts @@ -2,7 +2,7 @@ import { Request, Response, NextFunction } from "express"; import { z } from "zod"; import { db } from "@server/db"; import { eq } from "drizzle-orm"; -import { orgs, roleActions, roles, userOrgs } from "@server/db/schema"; +import { Org, orgs, roleActions, roles, userOrgs } from "@server/db/schema"; import response from "@server/utils/response"; import HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; @@ -15,7 +15,7 @@ import { defaultRoleAllowedActions } from "../role"; const createOrgSchema = z .object({ orgId: z.string(), - name: z.string().min(1).max(255), + name: z.string().min(1).max(255) // domain: z.string().min(1).max(255).optional(), }) .strict(); @@ -66,65 +66,82 @@ export async function createOrg( ); } - // create a url from config.app.base_url and get the hostname - const domain = new URL(config.app.base_url).hostname; + let error = ""; + let org: Org | null = null; - const newOrg = await db - .insert(orgs) - .values({ - orgId, - name, - domain, - }) - .returning(); + await db.transaction(async (trx) => { + // create a url from config.app.base_url and get the hostname + const domain = new URL(config.app.base_url).hostname; - const roleId = await createAdminRole(newOrg[0].orgId); + const newOrg = await trx + .insert(orgs) + .values({ + orgId, + name, + domain + }) + .returning(); - if (!roleId) { - return next( - createHttpError( - HttpCode.INTERNAL_SERVER_ERROR, - `Error creating Admin role` - ) - ); - } + if (newOrg.length === 0) { + error = "Failed to create organization"; + trx.rollback(); + return; + } + + org = newOrg[0]; + + const roleId = await createAdminRole(newOrg[0].orgId); - await db - .insert(userOrgs) - .values({ + if (!roleId) { + error = "Failed to create Admin role"; + trx.rollback(); + return; + } + + await trx.insert(userOrgs).values({ userId: req.user!.userId, orgId: newOrg[0].orgId, roleId: roleId, - isOwner: true, - }) - .execute(); - - const memberRole = await db - .insert(roles) - .values({ - name: "Member", - description: "Members can only view resources", - orgId, - }) - .returning(); - - await db - .insert(roleActions) - .values( + isOwner: true + }); + + const memberRole = await trx + .insert(roles) + .values({ + name: "Member", + description: "Members can only view resources", + orgId + }) + .returning(); + + await trx.insert(roleActions).values( defaultRoleAllowedActions.map((action) => ({ roleId: memberRole[0].roleId, actionId: action, - orgId, + orgId })) - ) - .execute(); + ); + }); + + if (!org) { + return next( + createHttpError( + HttpCode.INTERNAL_SERVER_ERROR, + "Failed to createo org" + ) + ); + } + + if (error) { + return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, error)); + } return response(res, { - data: newOrg[0], + data: org, success: true, error: false, message: "Organization created successfully", - status: HttpCode.CREATED, + status: HttpCode.CREATED }); } catch (error) { logger.error(error); diff --git a/src/app/[orgId]/settings/components/Header.tsx b/src/app/[orgId]/settings/components/Header.tsx index 11fc68f10d85d668e8b78fe5ad367429c6922d74..9cc7a2f4fef18dda963a5d0a3457736f35493216 100644 --- a/src/app/[orgId]/settings/components/Header.tsx +++ b/src/app/[orgId]/settings/components/Header.tsx @@ -37,7 +37,7 @@ import { useEnvContext } from "@app/hooks/useEnvContext"; import { useToast } from "@app/hooks/useToast"; import { cn, formatAxiosError } from "@app/lib/utils"; import { ListOrgsResponse } from "@server/routers/org"; -import { Check, ChevronsUpDown } from "lucide-react"; +import { Check, ChevronsUpDown, Plus } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState } from "react"; @@ -180,6 +180,15 @@ export default function Header({ email, orgId, name, orgs }: HeaderProps) { + { + router.push("/setup"); + }} + > + + New Organization + {orgs.map((org) => ( -
-
-
+
+
+
+
+
-
{children}
+
{children}