General.utils.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import type {
  2. OrganizationRole,
  3. OrganizationRolesResponse,
  4. } from '@/data/organization-members/organization-roles-query'
  5. import type { OrganizationMember } from '@/data/organizations/organization-members-query'
  6. export interface ProjectAccessMember {
  7. id: string
  8. displayName?: string
  9. email: string
  10. role?: string
  11. }
  12. interface SummarizeProjectAccessParams {
  13. organizationMembers: OrganizationMember[]
  14. roles: OrganizationRolesResponse | undefined
  15. projectRef?: string
  16. hasLimitedVisibility: boolean
  17. currentUserId?: string
  18. maxVisibleMembers?: number
  19. }
  20. export interface ProjectAccessSummary {
  21. projectMembers: ProjectAccessMember[]
  22. visibleMembers: ProjectAccessMember[]
  23. hiddenMembersCount: number
  24. projectMemberCount: number
  25. organizationMemberCount: number
  26. shouldShowOrgComparison: boolean
  27. hasOrganizationWideAccess: boolean
  28. }
  29. const getRoleDisplayName = (roleName: string | undefined) => {
  30. if (!roleName) return undefined
  31. return roleName.split('_')[0]
  32. }
  33. const roleAppliesToProject = (role: OrganizationRole | undefined, projectRef?: string) => {
  34. if (!role) return false
  35. if (role.projects.length === 0) return true
  36. if (!projectRef) return false
  37. return role.projects.some((project) => project.ref === projectRef)
  38. }
  39. export const summarizeProjectAccess = ({
  40. organizationMembers,
  41. roles,
  42. projectRef,
  43. hasLimitedVisibility,
  44. currentUserId,
  45. maxVisibleMembers = 12,
  46. }: SummarizeProjectAccessParams): ProjectAccessSummary => {
  47. const allRoles = [...(roles?.org_scoped_roles ?? []), ...(roles?.project_scoped_roles ?? [])]
  48. const rolesById = new Map(allRoles.map((role) => [role.id, role]))
  49. const normalizedMembers = organizationMembers.filter(
  50. (member) => !member.invited_id && typeof member.gotrue_id === 'string' && !!member.primary_email
  51. )
  52. const membersWithProjectAccess = normalizedMembers
  53. .filter((member) =>
  54. member.role_ids.some((roleId) => roleAppliesToProject(rolesById.get(roleId), projectRef))
  55. )
  56. .sort((a, b) => {
  57. const isCurrentUserA = !!currentUserId && a.gotrue_id === currentUserId
  58. const isCurrentUserB = !!currentUserId && b.gotrue_id === currentUserId
  59. if (isCurrentUserA && !isCurrentUserB) return -1
  60. if (!isCurrentUserA && isCurrentUserB) return 1
  61. return (a.primary_email ?? '').localeCompare(b.primary_email ?? '')
  62. })
  63. const projectMembers = membersWithProjectAccess.map((member) => {
  64. const matchingRoleNames = member.role_ids
  65. .map((roleId) => rolesById.get(roleId))
  66. .filter((role) => roleAppliesToProject(role, projectRef))
  67. .map((role) => getRoleDisplayName(role?.name))
  68. .filter((name): name is string => typeof name === 'string' && name.length > 0)
  69. const uniqueRoleNames = [...new Set(matchingRoleNames)]
  70. const hasDisplayName =
  71. typeof member.username === 'string' &&
  72. typeof member.primary_email === 'string' &&
  73. member.username !== member.primary_email
  74. return {
  75. id: member.gotrue_id as string,
  76. displayName: hasDisplayName ? member.username : undefined,
  77. email: member.primary_email as string,
  78. role: uniqueRoleNames.length > 0 ? uniqueRoleNames.join(', ') : undefined,
  79. }
  80. })
  81. const projectMemberCount = projectMembers.length
  82. const organizationMemberCount = normalizedMembers.length
  83. const shouldShowOrgComparison = !hasLimitedVisibility && organizationMemberCount > 0
  84. const hasOrganizationWideAccess =
  85. shouldShowOrgComparison && projectMemberCount === organizationMemberCount
  86. return {
  87. projectMembers,
  88. visibleMembers: projectMembers.slice(0, maxVisibleMembers),
  89. hiddenMembersCount: Math.max(projectMemberCount - maxVisibleMembers, 0),
  90. projectMemberCount,
  91. organizationMemberCount,
  92. shouldShowOrgComparison,
  93. hasOrganizationWideAccess,
  94. }
  95. }