Files
Alaister YoungandKevin Grüneberg 70da0f1d1d chore: cleanup packages (#27770)
* 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>
2024-07-04 14:48:10 +08:00

163 lines
5.1 KiB
TypeScript

import { useQueryClient } from '@tanstack/react-query'
import { useState } from 'react'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import APIDocsButton from 'components/ui/APIDocsButton'
import NoPermission from 'components/ui/NoPermission'
import { authKeys } from 'data/auth/keys'
import { useUsersQuery } from 'data/auth/users-query'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { Button, IconRefreshCw, IconSearch, IconX, Input, Listbox } from 'ui'
import AddUserDropdown from './AddUserDropdown'
import UsersList from './UsersList'
const Users = () => {
const queryClient = useQueryClient()
const { project } = useProjectContext()
const { ref: projectRef } = useParams()
const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled()
const [page, setPage] = useState(1)
const [search, setSearch] = useState('')
const [filterKeywords, setFilterKeywords] = useState('')
type Filter = 'verified' | 'unverified' | 'anonymous'
const [filter, setFilter] = useState<Filter>()
const canReadUsers = useCheckPermissions(PermissionAction.TENANT_SQL_SELECT, 'auth.users')
const isPermissionsLoaded = usePermissionsLoaded()
const {
data,
isLoading,
isSuccess,
refetch,
isRefetching,
error,
isPreviousData: isFetchingNextPage,
} = useUsersQuery(
{
projectRef,
page,
keywords: filterKeywords,
filter,
connectionString: project?.connectionString!,
},
{
keepPreviousData: true,
onSuccess(data) {
if (data.users.length <= 0 && data.total > 0) {
queryClient.removeQueries(
authKeys.users(projectRef, { page, keywords: filterKeywords, filter })
)
setPage((prev) => prev - 1)
}
},
}
)
function onVerifiedFilterChange(val: Filter) {
setFilter(val)
}
function clearSearch() {
setSearch('')
setFilterKeywords('')
setFilter(undefined)
}
return (
<div>
<div className="justify-between px-6 pt-6 pb-2 md:flex">
<div className="relative flex space-x-4">
<Input
size="small"
value={search}
onChange={(e) => setSearch(e.target.value)}
onKeyDown={(e) => {
if (e.keyCode == 13) setFilterKeywords(search)
}}
className="min-w-[275px]"
name="email"
id="email"
placeholder="Search by email or phone number"
icon={<IconSearch size="tiny" />}
actions={[
search && (
<Button
size="tiny"
type="text"
icon={<IconX size="tiny" />}
onClick={() => clearSearch()}
/>
),
]}
/>
<Listbox
size="small"
value={filter}
onChange={onVerifiedFilterChange}
name="verified"
id="verified"
className="w-[200px]"
>
<Listbox.Option label="All Users" value="">
All Users
</Listbox.Option>
<Listbox.Option label="Verified Users" value="verified">
Verified Users
</Listbox.Option>
<Listbox.Option label="Un-Verified Users" value="unverified">
Un-Verified Users
</Listbox.Option>
<Listbox.Option label="Anonymous Users" value="anonymous">
Anonymous Users
</Listbox.Option>
</Listbox>
</div>
<div className="mt-4 flex items-center gap-2 md:mt-0">
{isNewAPIDocsEnabled && <APIDocsButton section={['user-management']} />}
<Button
size="tiny"
icon={<IconRefreshCw />}
type="default"
loading={isRefetching && !isFetchingNextPage}
onClick={() => refetch()}
>
Reload
</Button>
<AddUserDropdown projectKpsVersion={project?.kpsVersion} />
</div>
</div>
<section className="thin-scrollbars mt-4 overflow-visible px-6">
<div className="section-block--body relative overflow-x-auto rounded">
<div className="inline-block min-w-full align-middle">
{isPermissionsLoaded && !canReadUsers ? (
<div className="mt-8">
<NoPermission isFullPage resourceText="access your project's users" />
</div>
) : (
<UsersList
page={page}
setPage={setPage}
keywords={filterKeywords}
total={data?.total ?? 0}
users={data?.users ?? []}
isLoading={isLoading}
isSuccess={isSuccess}
isFetchingNextPage={isFetchingNextPage}
error={error}
/>
)}
</div>
</div>
</section>
</div>
)
}
export default Users