Files
1127c4ba88 Project Level Permissions (#27347)
* fix: update Permission params

* fix: upgrade check permission hook to support project level role

* fix: usePermissionsLoaded

* fix: Permission params can be undefined

* Scaffold new access management UI

* Add validation

* Update roles view

* Add tooltip

* Add button to apply role to all projects

* Update UI to select projects first instead of roles

* Merge master update UI

* Midway trying to implementation project level perms API

* First pass implementating updating project level permissions

* Add client side validation for assigning/removing roles

* Midway implementing new invites

* Integrate most of the project level permissions functionality

* fix: filter out org-level permissions before checking

* Add relevant UI guards in org level pages for project role POV

* Minor refactors

* Small refactors

* More fixes

* Moar refactors

* More fixes

* More fixes

* Refactor update role logic and smack some test cases on it

* Fixes

* Fix type issue

* Fix type

* more fixes, refactors, adding checks...

* MORE fixes

* Add perms checking for replicas

* Add ButtonTooltip component and use them to prevent repetition of pointer events auto for buttons with tooltips

* Convert all buttons with tooltips to use ButtonTooltip

* refactor

* PRettier

* Small fix

* Remove commented out code in organization-invitation-accept-mutation

* fix: switch to use the platform oauth authorizations routes

* Add perms checking for org audit logs and org oauth apps

* PRettier

* Fix incorrect URL for oauth app flow

* Fix incorrect URL for oauth app flow

* Fix

* Add perms checking for warehouse related UI

* Update roles helper icon

* remove unused lib

* Update package lock... again

* Update package lock... again

* Smalllll update

* Update some checks

* Add gate for project level permissions

* Last fix

* update codegen

* Update warehouse endpoint routes

* Fix

---------

Co-authored-by: phamhieu <phamhieu1998@gmail.com>
Co-authored-by: Alaister Young <a@alaisteryoung.com>
2024-07-01 17:59:54 +08:00

139 lines
4.8 KiB
TypeScript

import { AlertCircle, HelpCircle } from 'lucide-react'
import { useParams } from 'common'
import Table from 'components/to-be-cleaned/Table'
import AlertError from 'components/ui/AlertError'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useOrganizationRolesV2Query } from 'data/organization-members/organization-roles-query'
import { useOrganizationMembersQuery } from 'data/organizations/organization-members-query'
import { useProfile } from 'lib/profile'
import {
Button,
Loading,
TooltipContent_Shadcn_,
TooltipTrigger_Shadcn_,
Tooltip_Shadcn_,
} from 'ui'
import { MemberRow } from './MemberRow'
export interface MembersViewProps {
searchString: string
}
const MembersView = ({ searchString }: MembersViewProps) => {
const { slug } = useParams()
const { profile } = useProfile()
const {
data: members,
error: membersError,
isLoading: isLoadingMembers,
isError: isErrorMembers,
isSuccess: isSuccessMembers,
} = useOrganizationMembersQuery({ slug })
const { error: rolesError, isError: isErrorRoles } = useOrganizationRolesV2Query({
slug,
})
const allMembers = members ?? []
const filteredMembers = (
!searchString
? allMembers
: allMembers.filter((member) => {
if (member.invited_at) {
return member.primary_email?.includes(searchString)
}
if (member.gotrue_id) {
return (
member.username.includes(searchString) || member.primary_email?.includes(searchString)
)
}
})
)
.slice()
.sort((a, b) => {
// [Joshen] Have own account show up top
if (a.primary_email === profile?.primary_email) return -1
return a.username.localeCompare(b.username)
})
return (
<>
{isLoadingMembers && <GenericSkeletonLoader />}
{isErrorMembers && (
<AlertError error={membersError} subject="Failed to retrieve organization members" />
)}
{isErrorRoles && (
<AlertError error={rolesError} subject="Failed to retrieve organization roles" />
)}
{isSuccessMembers && (
<div className="rounded w-full">
<Loading active={!filteredMembers}>
<Table
head={[
<Table.th key="header-user">User</Table.th>,
<Table.th key="header-status" className="w-24" />,
<Table.th key="header-mfa" className="text-center w-32">
Enabled MFA
</Table.th>,
<Table.th key="header-role" className="flex items-center space-x-1">
<span>Role</span>
<Tooltip_Shadcn_>
<TooltipTrigger_Shadcn_ asChild>
<Button asChild type="text" className="px-1">
<a
target="_blank"
rel="noreferrer"
href="https://supabase.com/docs/guides/platform/access-control"
>
<HelpCircle size={14} className="text-foreground-light" />
</a>
</Button>
</TooltipTrigger_Shadcn_>
<TooltipContent_Shadcn_ side="bottom">
How to configure access control?
</TooltipContent_Shadcn_>
</Tooltip_Shadcn_>
</Table.th>,
<Table.th key="header-action" />,
]}
body={[
...filteredMembers.map((member) => (
<MemberRow key={member.gotrue_id} member={member} />
)),
...(searchString.length > 0 && filteredMembers.length === 0
? [
<Table.tr key="no-results" className="bg-panel-secondary-light">
<Table.td colSpan={12}>
<div className="flex items-center space-x-3 opacity-75">
<AlertCircle size={16} strokeWidth={2} />
<p className="text-foreground-light">
No users matched the search query "{searchString}"
</p>
</div>
</Table.td>
</Table.tr>,
]
: []),
<Table.tr key="footer" className="bg-panel-secondary-light">
<Table.td colSpan={12}>
<p className="text-foreground-light">
{searchString ? `${filteredMembers.length} of ` : ''}
{allMembers.length || '0'} {allMembers.length == 1 ? 'user' : 'users'}
</p>
</Table.td>
</Table.tr>,
]}
/>
</Loading>
</div>
)}
</>
)
}
export default MembersView