mirror of
https://github.com/supabase/supabase.git
synced 2026-10-19 16:19:10 +03:00
* chore: cleanup packages - Avoid circular imports - Export API-types as types - pg-format without depending on Node internal Buffer (not browser-compatible) - Avoid importing from barrel files in ui dir * chore: avoid barrel file imports in studio (#27771) * chore: avoid barrel file imports - Removes some unused imports - Avoids barrel file import for faster builds + less memory * add eslint rule * type fixes * delete layouts barrel * delete components/grid barrel file * delete components/grid/utils barrel file * delete components/grid/components/common barrel file * delete components/grid/components/editor barrel file * delete components/grid/components/formatter barrel file * delete components/grid/components/grid barrel file * delete components/grid/components/header/filter barrel file * remote components/grid/store barrel file * remove components/interfaces/Auth/Policies barrel file * delete components/interfaces/Settings/Logs barrel file * delete components/ui/CodeEditor barrel file * delete components/ui/Forms barrel file * delete components/ui/Shimmers barrel file * delete data/analytics barrel file * delete hooks barrel file * cleanup lib/common/fetch barrel file * final * barral files cleanup * global react-data-grid styles * remove console.log --------- Co-authored-by: Kevin Grüneberg <k.grueneberg1994@gmail.com> * fix build --------- Co-authored-by: Kevin Grüneberg <k.grueneberg1994@gmail.com>
133 lines
4.2 KiB
TypeScript
133 lines
4.2 KiB
TypeScript
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
|
|
|
import Table from 'components/to-be-cleaned/Table'
|
|
import AlertError from 'components/ui/AlertError'
|
|
import type { User } from 'data/auth/users-query'
|
|
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
|
import { AlertCircle } from 'lucide-react'
|
|
import { useState } from 'react'
|
|
import type { ResponseError } from 'types'
|
|
import UsersSidePanel from './UserSidePanel'
|
|
import UserListItem from './UsersListItem'
|
|
import UsersListItemSkeleton from './UsersListItemSkeleton'
|
|
import UsersPagination from './UsersPagination'
|
|
|
|
interface UsersListProps {
|
|
page: number
|
|
setPage: (page: number) => void
|
|
keywords: string
|
|
total: number
|
|
users: User[]
|
|
isLoading: boolean
|
|
isSuccess: boolean
|
|
isFetchingNextPage: boolean
|
|
error: ResponseError | null
|
|
}
|
|
|
|
const UsersList = ({
|
|
page,
|
|
setPage,
|
|
keywords,
|
|
total,
|
|
users,
|
|
isLoading,
|
|
isSuccess,
|
|
isFetchingNextPage,
|
|
error,
|
|
}: UsersListProps) => {
|
|
const [selectedUser, setSelectedUser] = useState<User | undefined>(undefined)
|
|
const [userSidePanelOpen, setUserSidePanelOpen] = useState(false)
|
|
|
|
// Check once on the top level, rather than checking for every row
|
|
const canSendMagicLink = useCheckPermissions(PermissionAction.AUTH_EXECUTE, 'send_magic_link')
|
|
const canSendRecovery = useCheckPermissions(PermissionAction.AUTH_EXECUTE, 'send_recovery')
|
|
const canSendOtp = useCheckPermissions(PermissionAction.AUTH_EXECUTE, 'send_otp')
|
|
const canRemoveUser = useCheckPermissions(PermissionAction.TENANT_SQL_DELETE, 'auth.users')
|
|
const canRemoveMFAFactors = useCheckPermissions(
|
|
PermissionAction.TENANT_SQL_DELETE,
|
|
'auth.mfa_factors'
|
|
)
|
|
|
|
return (
|
|
<Table
|
|
head={
|
|
<>
|
|
<Table.th>Display Name</Table.th>
|
|
<Table.th>Email</Table.th>
|
|
<Table.th>Phone</Table.th>
|
|
<Table.th className="table-cell">Provider</Table.th>
|
|
<Table.th className="table-cell">Created</Table.th>
|
|
<Table.th className="table-cell">Last Sign In</Table.th>
|
|
<Table.th className="table-cell">User UID</Table.th>
|
|
<Table.th></Table.th>
|
|
</>
|
|
}
|
|
body={
|
|
<>
|
|
{isLoading && (
|
|
<>
|
|
<UsersListItemSkeleton />
|
|
<UsersListItemSkeleton />
|
|
<UsersListItemSkeleton />
|
|
<UsersListItemSkeleton />
|
|
</>
|
|
)}
|
|
{error && <AlertError error={error} subject="Failed to retrieve users" />}
|
|
{isSuccess && users.length === 0 && (
|
|
<Table.tr>
|
|
<Table.td
|
|
colSpan={8}
|
|
className="h-14 whitespace-nowrap border-t p-4 text-sm leading-5 text-gray-300"
|
|
>
|
|
<div className="flex items-center space-x-3 opacity-75">
|
|
<AlertCircle size={16} strokeWidth={2} />
|
|
<p className="text-foreground-light">
|
|
{keywords
|
|
? `No users matched the search query "${keywords}"`
|
|
: 'No users in your project'}
|
|
</p>
|
|
</div>
|
|
</Table.td>
|
|
</Table.tr>
|
|
)}
|
|
{isSuccess &&
|
|
users.length > 0 &&
|
|
users.map((x: any) => (
|
|
<UserListItem
|
|
key={x.id}
|
|
user={x}
|
|
permissions={{
|
|
canRemoveUser,
|
|
canRemoveMFAFactors,
|
|
canSendMagicLink,
|
|
canSendRecovery,
|
|
canSendOtp,
|
|
}}
|
|
setSelectedUser={setSelectedUser}
|
|
setUserSidePanelOpen={setUserSidePanelOpen}
|
|
/>
|
|
))}
|
|
<Table.tr>
|
|
<Table.td colSpan={8}>
|
|
<UsersPagination
|
|
total={total}
|
|
page={page}
|
|
setPage={setPage}
|
|
isFetchingNextPage={isFetchingNextPage}
|
|
/>
|
|
</Table.td>
|
|
</Table.tr>
|
|
|
|
<UsersSidePanel
|
|
selectedUser={selectedUser}
|
|
userSidePanelOpen={userSidePanelOpen}
|
|
setUserSidePanelOpen={setUserSidePanelOpen}
|
|
/>
|
|
</>
|
|
}
|
|
/>
|
|
)
|
|
}
|
|
|
|
export default UsersList
|