Skip to content

Commit 7d6f183

Browse files
joshenlimalaister
andauthored
Show all projects which role applies to, and link project from hover card (supabase#29502)
* Show all projects which role applies to, and link project from hover card * Feex * Update apps/studio/components/interfaces/Organization/TeamSettings/MemberRow.tsx Co-authored-by: Alaister Young <alaister@users.noreply.github.com> --------- Co-authored-by: Alaister Young <alaister@users.noreply.github.com>
1 parent 62959ab commit 7d6f183

File tree

1 file changed

+47
-25
lines changed
  • apps/studio/components/interfaces/Organization/TeamSettings

1 file changed

+47
-25
lines changed

apps/studio/components/interfaces/Organization/TeamSettings/MemberRow.tsx

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
1-
import { Check, Minus, User, X } from 'lucide-react'
1+
import { ArrowRight, Check, Minus, User, X } from 'lucide-react'
22
import Image from 'next/legacy/image'
33
import { useState } from 'react'
44

55
import { useParams } from 'common'
66
import Table from 'components/to-be-cleaned/Table'
7+
import PartnerIcon from 'components/ui/PartnerIcon'
78
import { useOrganizationRolesV2Query } from 'data/organization-members/organization-roles-query'
89
import { OrganizationMember } from 'data/organizations/organization-members-query'
910
import { useProjectsQuery } from 'data/projects/projects-query'
1011
import { useHasAccessToProjectLevelPermissions } from 'data/subscriptions/org-subscription-query'
1112
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
1213
import { useProfile } from 'lib/profile'
13-
import { Badge, TooltipContent_Shadcn_, TooltipTrigger_Shadcn_, Tooltip_Shadcn_ } from 'ui'
14+
import {
15+
Badge,
16+
HoverCardContent_Shadcn_,
17+
HoverCardTrigger_Shadcn_,
18+
HoverCard_Shadcn_,
19+
ScrollArea,
20+
cn,
21+
} from 'ui'
1422
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
1523
import { getUserDisplayName, isInviteExpired } from '../Organization.utils'
1624
import { MemberActions } from './MemberActions'
17-
import PartnerIcon from 'components/ui/PartnerIcon'
25+
import Link from 'next/link'
1826

1927
interface MemberRowProps {
2028
member: OrganizationMember
@@ -25,17 +33,16 @@ const MEMBER_ORIGIN_TO_MANAGED_BY = {
2533
} as const
2634

2735
export const MemberRow = ({ member }: MemberRowProps) => {
28-
const { slug } = useParams()
2936
const { profile } = useProfile()
30-
const { data: projects } = useProjectsQuery()
3137
const selectedOrganization = useSelectedOrganization()
3238
const [hasInvalidImg, setHasInvalidImg] = useState(false)
33-
const isOptedIntoProjectLevelPermissions = useHasAccessToProjectLevelPermissions(slug as string)
3439

40+
const { data: projects } = useProjectsQuery()
3541
const { data: roles, isLoading: isLoadingRoles } = useOrganizationRolesV2Query({
3642
slug: selectedOrganization?.slug,
3743
})
3844

45+
const orgProjects = projects?.filter((p) => p.organization_id === selectedOrganization?.id)
3946
const hasProjectScopedRoles = (roles?.project_scoped_roles ?? []).length > 0
4047
const memberIsUser = member.gotrue_id == profile?.gotrue_id
4148
const isInvitedUser = Boolean(member.invited_id)
@@ -139,10 +146,10 @@ export const MemberRow = ({ member }: MemberRowProps) => {
139146
const roleName = (role?.name ?? '').split('_')[0]
140147
const projectsApplied =
141148
role?.project_ids === null
142-
? projects?.map((p) => p.name) ?? []
149+
? orgProjects?.map((p) => p.name) ?? []
143150
: (role?.project_ids ?? [])
144151
.map((id) => {
145-
return projects?.find((p) => p.id === id)?.name ?? ''
152+
return orgProjects?.find((p) => p.id === id)?.name ?? ''
146153
})
147154
.filter((x) => x.length > 0)
148155

@@ -157,28 +164,43 @@ export const MemberRow = ({ member }: MemberRowProps) => {
157164
{projectsApplied[0]}
158165
</span>
159166
) : (
160-
<Tooltip_Shadcn_>
161-
<TooltipTrigger_Shadcn_ asChild>
167+
<HoverCard_Shadcn_ openDelay={200}>
168+
<HoverCardTrigger_Shadcn_ asChild>
162169
<span className="text-foreground">
163170
{role?.project_ids === null
164171
? 'Organization'
165172
: `${projectsApplied.length} project${projectsApplied.length > 1 ? 's' : ''}`}
166173
</span>
167-
</TooltipTrigger_Shadcn_>
168-
{role?.project_ids !== null && projectsApplied.length > 1 && (
169-
<TooltipContent_Shadcn_ side="bottom" className="flex flex-col gap-y-1">
170-
{projectsApplied
171-
?.slice(0, 2)
172-
.map((name) => <span key={name}>{name}</span>)}
173-
{projectsApplied.length > 2 && (
174-
<span>
175-
And {projectsApplied.length - 2} other project
176-
{projectsApplied.length > 4 ? 's' : ''}
177-
</span>
178-
)}
179-
</TooltipContent_Shadcn_>
180-
)}
181-
</Tooltip_Shadcn_>
174+
</HoverCardTrigger_Shadcn_>
175+
<HoverCardContent_Shadcn_ className="p-0">
176+
<p className="p-2 text-xs">
177+
{roleName} role applies to {projectsApplied.length} project
178+
{projectsApplied.length > 1 ? 's' : ''}
179+
</p>
180+
<div className="border-t flex flex-col py-1">
181+
<ScrollArea
182+
className={cn(projectsApplied.length > 5 ? 'h-[130px]' : '')}
183+
>
184+
{projectsApplied.map((name) => {
185+
const ref = orgProjects?.find((p) => p.name === name)?.ref
186+
return (
187+
<Link
188+
key={name}
189+
href={`/project/${ref}`}
190+
className="px-2 py-1 group hover:bg-surface-300 hover:text-foreground transition flex items-center justify-between"
191+
>
192+
<span className="text-xs truncate max-w-[60%]">{name}</span>
193+
<span className="text-xs text-foreground flex items-center gap-x-1 opacity-0 group-hover:opacity-100 transition">
194+
Go to project
195+
<ArrowRight size={14} />
196+
</span>
197+
</Link>
198+
)
199+
})}
200+
</ScrollArea>
201+
</div>
202+
</HoverCardContent_Shadcn_>
203+
</HoverCard_Shadcn_>
182204
)}
183205
</>
184206
)}

0 commit comments

Comments
 (0)