diff --git a/server/routers/olm/peers.ts b/server/routers/olm/peers.ts index 2ef7a772..2708647b 100644 --- a/server/routers/olm/peers.ts +++ b/server/routers/olm/peers.ts @@ -1,8 +1,7 @@ -import { db } from "@server/db"; -import { clients, olms, newts, sites } from "@server/db"; -import { eq } from "drizzle-orm"; import { sendToClient } from "#dynamic/routers/ws"; +import { db, olms } from "@server/db"; import logger from "@server/logger"; +import { eq } from "drizzle-orm"; import { Alias } from "yaml"; export async function addPeer( @@ -102,7 +101,7 @@ export async function updatePeer( .where(eq(olms.clientId, clientId)) .limit(1); if (!olm) { - return + return; } olmId = olm.olmId; } @@ -162,5 +161,7 @@ export async function initPeerAddHandshake( logger.warn(`Error sending message:`, error); }); - logger.info(`Initiated peer add handshake for site ${peer.siteId} to olm ${olmId}`); + logger.info( + `Initiated peer add handshake for site ${peer.siteId} to olm ${olmId}` + ); } diff --git a/server/routers/org/listUserOrgs.ts b/server/routers/org/listUserOrgs.ts index eb500250..09e850f4 100644 --- a/server/routers/org/listUserOrgs.ts +++ b/server/routers/org/listUserOrgs.ts @@ -1,6 +1,6 @@ import { Request, Response, NextFunction } from "express"; import { z } from "zod"; -import { db } from "@server/db"; +import { db, roles } from "@server/db"; import { Org, orgs, userOrgs } from "@server/db"; import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; @@ -40,7 +40,7 @@ const listOrgsSchema = z.object({ // responses: {} // }); -type ResponseOrg = Org & { isOwner?: boolean }; +type ResponseOrg = Org & { isOwner?: boolean; isAdmin?: boolean }; export type ListUserOrgsResponse = { orgs: ResponseOrg[]; @@ -112,6 +112,7 @@ export async function listUserOrgs( userOrgs, and(eq(userOrgs.orgId, orgs.orgId), eq(userOrgs.userId, userId)) ) + .leftJoin(roles, eq(userOrgs.orgId, roles.orgId)) .limit(limit) .offset(offset); @@ -128,6 +129,9 @@ export async function listUserOrgs( if (val.userOrgs && val.userOrgs.isOwner) { res.isOwner = val.userOrgs.isOwner; } + if (val.roles && val.roles.isAdmin) { + res.isAdmin = val.roles.isAdmin; + } return res; }); diff --git a/server/routers/siteResource/createSiteResource.ts b/server/routers/siteResource/createSiteResource.ts index b2e4b0cb..e5719e7f 100644 --- a/server/routers/siteResource/createSiteResource.ts +++ b/server/routers/siteResource/createSiteResource.ts @@ -1,24 +1,26 @@ -import { Request, Response, NextFunction } from "express"; -import { z } from "zod"; import { clientSiteResources, db, newts, roles, roleSiteResources, + SiteResource, + siteResources, + sites, userSiteResources } from "@server/db"; -import { siteResources, sites, SiteResource } from "@server/db"; +import { getUniqueSiteResourceName } from "@server/db/names"; +import { getNextAvailableAliasAddress } from "@server/lib/ip"; +import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations"; import response from "@server/lib/response"; -import HttpCode from "@server/types/HttpCode"; -import createHttpError from "http-errors"; -import { eq, and, is } from "drizzle-orm"; -import { fromError } from "zod-validation-error"; import logger from "@server/logger"; import { OpenAPITags, registry } from "@server/openApi"; -import { getUniqueSiteResourceName } from "@server/db/names"; -import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations"; -import { getNextAvailableAliasAddress } from "@server/lib/ip"; +import HttpCode from "@server/types/HttpCode"; +import { and, eq } from "drizzle-orm"; +import { NextFunction, Request, Response } from "express"; +import createHttpError from "http-errors"; +import { z } from "zod"; +import { fromError } from "zod-validation-error"; const createSiteResourceParamsSchema = z.strictObject({ siteId: z.string().transform(Number).pipe(z.int().positive()), diff --git a/src/components/LayoutSidebar.tsx b/src/components/LayoutSidebar.tsx index 480c8b83..33778995 100644 --- a/src/components/LayoutSidebar.tsx +++ b/src/components/LayoutSidebar.tsx @@ -1,38 +1,30 @@ "use client"; -import React, { useEffect, useState } from "react"; -import { SidebarNav } from "@app/components/SidebarNav"; -import { OrgSelector } from "@app/components/OrgSelector"; -import { cn } from "@app/lib/cn"; -import { ListUserOrgsResponse } from "@server/routers/org"; -import SupporterStatus from "@app/components/SupporterStatus"; -import { - ExternalLink, - Server, - BookOpenText, - Zap, - CreditCard, - FileText, - TicketCheck -} from "lucide-react"; -import { FaDiscord, FaGithub } from "react-icons/fa"; -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import { useUserContext } from "@app/hooks/useUserContext"; -import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext"; -import { useEnvContext } from "@app/hooks/useEnvContext"; -import { useTranslations } from "next-intl"; import type { SidebarNavSection } from "@app/app/navigation"; +import { OrgSelector } from "@app/components/OrgSelector"; +import { SidebarNav } from "@app/components/SidebarNav"; +import SupporterStatus from "@app/components/SupporterStatus"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@app/components/ui/tooltip"; +import { useEnvContext } from "@app/hooks/useEnvContext"; +import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext"; +import { useUserContext } from "@app/hooks/useUserContext"; +import { cn } from "@app/lib/cn"; import { build } from "@server/build"; +import { ListUserOrgsResponse } from "@server/routers/org"; +import { ExternalLink, Server } from "lucide-react"; +import { useTranslations } from "next-intl"; +import dynamic from "next/dynamic"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { useEffect, useState } from "react"; +import { FaGithub } from "react-icons/fa"; import SidebarLicenseButton from "./SidebarLicenseButton"; import { SidebarSupportButton } from "./SidebarSupportButton"; -import dynamic from "next/dynamic"; const ProductUpdates = dynamic(() => import("./ProductUpdates"), { ssr: false @@ -48,7 +40,7 @@ interface LayoutSidebarProps { export function LayoutSidebar({ orgId, - orgs, + orgs = [], navItems, defaultSidebarCollapsed, hasCookiePreference @@ -105,6 +97,10 @@ export function LayoutSidebar({ } } + const currentOrg = orgs.find((org) => org.orgId === orgId); + const canShowProductUpdates = + user.serverAdmin || Boolean(currentOrg?.isOwner || currentOrg?.isAdmin); + return (
-
- -
+ {canShowProductUpdates && ( +
+ +
+ )} {build === "enterprise" && (