diff --git a/apps/webapp/app/components/ImpersonationBanner.tsx b/apps/webapp/app/components/ImpersonationBanner.tsx index 367f31dfd3..1ef5bff641 100644 --- a/apps/webapp/app/components/ImpersonationBanner.tsx +++ b/apps/webapp/app/components/ImpersonationBanner.tsx @@ -1,21 +1,29 @@ import { UserMinusIcon } from "@heroicons/react/20/solid"; import { Form } from "@remix-run/react"; import { Button } from "./primitives/Buttons"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./primitives/Tooltip"; export function ImpersonationBanner() { return ( -
-
- +
+ + + + +
); diff --git a/apps/webapp/app/components/navigation/SideMenu.tsx b/apps/webapp/app/components/navigation/SideMenu.tsx index 6a56281873..9ce9b13475 100644 --- a/apps/webapp/app/components/navigation/SideMenu.tsx +++ b/apps/webapp/app/components/navigation/SideMenu.tsx @@ -16,6 +16,7 @@ import { RectangleStackIcon, ServerStackIcon, Squares2X2Icon, + UsersIcon, } from "@heroicons/react/20/solid"; import { useNavigation } from "@remix-run/react"; import { useEffect, useRef, useState, type ReactNode } from "react"; @@ -27,12 +28,14 @@ import { Avatar } from "~/components/primitives/Avatar"; import { type MatchedEnvironment } from "~/hooks/useEnvironment"; import { type MatchedOrganization } from "~/hooks/useOrganizations"; import { type MatchedProject } from "~/hooks/useProject"; +import { useHasAdminAccess } from "~/hooks/useUser"; import { type User } from "~/models/user.server"; import { useCurrentPlan } from "~/routes/_app.orgs.$organizationSlug/route"; import { type FeedbackType } from "~/routes/resources.feedback"; import { cn } from "~/utils/cn"; import { accountPath, + adminPath, logoutPath, newOrganizationPath, newProjectPath, @@ -106,6 +109,7 @@ export function SideMenu({ const currentPlan = useCurrentPlan(); const { isConnected } = useDevPresence(); const isFreeUser = currentPlan?.v3Subscription?.isPaying === false; + const isAdmin = useHasAdminAccess(); useEffect(() => { const handleScroll = () => { @@ -139,6 +143,20 @@ export function SideMenu({ project={project} user={user} /> + {isAdmin && !user.isImpersonating ? ( + + + + + + + Admin dashboard + + + + ) : isAdmin && user.isImpersonating ? ( + + ) : null}
@@ -406,19 +421,24 @@ function ProjectSelector({
- + {organizations.length > 1 ? ( + + ) : ( + + )}
- {user.isImpersonating && }
diff --git a/apps/webapp/app/utils/pathBuilder.ts b/apps/webapp/app/utils/pathBuilder.ts index 6996eff9d7..c4d48c3438 100644 --- a/apps/webapp/app/utils/pathBuilder.ts +++ b/apps/webapp/app/utils/pathBuilder.ts @@ -430,3 +430,7 @@ export function docsPath(path: string) { export function docsTroubleshootingPath(path: string) { return `${docsRoot()}/v3/troubleshooting`; } + +export function adminPath() { + return `/@`; +}