@@ -16,6 +16,7 @@ import {
16
16
RectangleStackIcon ,
17
17
ServerStackIcon ,
18
18
Squares2X2Icon ,
19
+ UsersIcon ,
19
20
} from "@heroicons/react/20/solid" ;
20
21
import { useLocation , useNavigation } from "@remix-run/react" ;
21
22
import { useEffect , useRef , useState , type ReactNode } from "react" ;
@@ -28,12 +29,14 @@ import { Avatar } from "~/components/primitives/Avatar";
28
29
import { type MatchedEnvironment } from "~/hooks/useEnvironment" ;
29
30
import { type MatchedOrganization } from "~/hooks/useOrganizations" ;
30
31
import { type MatchedProject } from "~/hooks/useProject" ;
32
+ import { useHasAdminAccess } from "~/hooks/useUser" ;
31
33
import { type User } from "~/models/user.server" ;
32
34
import { useCurrentPlan } from "~/routes/_app.orgs.$organizationSlug/route" ;
33
35
import { type FeedbackType } from "~/routes/resources.feedback" ;
34
36
import { cn } from "~/utils/cn" ;
35
37
import {
36
38
accountPath ,
39
+ adminPath ,
37
40
logoutPath ,
38
41
newOrganizationPath ,
39
42
newProjectPath ,
@@ -110,6 +113,7 @@ export function SideMenu({
110
113
const currentPlan = useCurrentPlan ( ) ;
111
114
const { isConnected } = useDevPresence ( ) ;
112
115
const isFreeUser = currentPlan ?. v3Subscription ?. isPaying === false ;
116
+ const isAdmin = useHasAdminAccess ( ) ;
113
117
114
118
useEffect ( ( ) => {
115
119
const handleScroll = ( ) => {
@@ -143,6 +147,20 @@ export function SideMenu({
143
147
project = { project }
144
148
user = { user }
145
149
/>
150
+ { isAdmin && ! user . isImpersonating ? (
151
+ < TooltipProvider disableHoverableContent = { true } >
152
+ < Tooltip >
153
+ < TooltipTrigger >
154
+ < LinkButton variant = "minimal/medium" to = { adminPath ( ) } TrailingIcon = { UsersIcon } />
155
+ </ TooltipTrigger >
156
+ < TooltipContent side = "bottom" className = { "text-xs" } >
157
+ Admin dashboard
158
+ </ TooltipContent >
159
+ </ Tooltip >
160
+ </ TooltipProvider >
161
+ ) : isAdmin && user . isImpersonating ? (
162
+ < ImpersonationBanner />
163
+ ) : null }
146
164
</ div >
147
165
< div
148
166
className = "overflow-hidden overflow-y-auto pt-2 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600"
@@ -325,10 +343,7 @@ function ProjectSelector({
325
343
< PopoverArrowTrigger
326
344
isOpen = { isOrgMenuOpen }
327
345
overflowHidden
328
- className = { cn (
329
- "h-8 w-full justify-between py-1 pl-1.5" ,
330
- user . isImpersonating && "border border-dashed border-amber-400"
331
- ) }
346
+ className = "h-8 w-full justify-between py-1 pl-1.5"
332
347
>
333
348
< span className = "flex items-center gap-1.5 overflow-hidden" >
334
349
< Avatar avatar = { organization . avatar } size = { 1.25 } orgName = { organization . title } />
@@ -412,19 +427,24 @@ function ProjectSelector({
412
427
< PopoverMenuItem to = { newProjectPath ( organization ) } title = "New project" icon = { PlusIcon } />
413
428
</ div >
414
429
< div className = "border-t border-charcoal-700 p-1" >
415
- < SwitchOrganizations organizations = { organizations } organization = { organization } />
430
+ { organizations . length > 1 ? (
431
+ < SwitchOrganizations organizations = { organizations } organization = { organization } />
432
+ ) : (
433
+ < PopoverMenuItem
434
+ to = { newOrganizationPath ( ) }
435
+ title = "New organization"
436
+ icon = { PlusIcon }
437
+ leadingIconClassName = "text-text-dimmed"
438
+ />
439
+ ) }
416
440
</ div >
417
441
< div className = "border-t border-charcoal-700 p-1" >
418
442
< PopoverMenuItem
419
443
to = { accountPath ( ) }
420
444
title = "Account"
421
445
icon = { UserProfilePhoto }
422
- leadingIconClassName = { cn (
423
- "text-text-dimmed rounded-full border border-transparent" ,
424
- user . isImpersonating && "rounded-full border-yellow-500"
425
- ) }
446
+ leadingIconClassName = "text-text-dimmed rounded-full border border-transparent"
426
447
/>
427
- { user . isImpersonating && < ImpersonationBanner /> }
428
448
</ div >
429
449
< div className = "border-t border-charcoal-700 p-1" >
430
450
< PopoverMenuItem
@@ -519,7 +539,7 @@ function SwitchOrganizations({
519
539
< div className = "border-t border-charcoal-700 p-1" >
520
540
< PopoverMenuItem
521
541
to = { newOrganizationPath ( ) }
522
- title = "New Organization "
542
+ title = "New organization "
523
543
icon = { PlusIcon }
524
544
leadingIconClassName = "text-text-dimmed"
525
545
/>
0 commit comments