mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-23 21:38:44 +08:00
feat(admin): add import and export users to admin panel (#10810)
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import { Button } from '@affine/admin/components/ui/button';
|
||||
import { Input } from '@affine/admin/components/ui/input';
|
||||
import { useQuery } from '@affine/admin/use-query';
|
||||
import { getUserByEmailQuery } from '@affine/graphql';
|
||||
import { PlusIcon } from 'lucide-react';
|
||||
import type { SetStateAction } from 'react';
|
||||
import { getUserByEmailQuery, type UserType } from '@affine/graphql';
|
||||
import { ExportIcon, ImportIcon, PlusIcon } from '@blocksuite/icons/rc';
|
||||
import type { Table } from '@tanstack/react-table';
|
||||
import {
|
||||
type SetStateAction,
|
||||
startTransition,
|
||||
useCallback,
|
||||
useEffect,
|
||||
@@ -14,11 +15,14 @@ import {
|
||||
|
||||
import { useRightPanel } from '../../panel/context';
|
||||
import { DiscardChanges } from './discard-changes';
|
||||
import { ExportUsersDialog } from './export-users-dialog';
|
||||
import { ImportUsersDialog } from './import-users-dialog';
|
||||
import { CreateUserForm } from './user-form';
|
||||
|
||||
interface DataTableToolbarProps<TData> {
|
||||
data: TData[];
|
||||
setDataTable: (data: TData[]) => void;
|
||||
table?: Table<TData>;
|
||||
}
|
||||
|
||||
const useSearch = () => {
|
||||
@@ -55,9 +59,12 @@ function useDebouncedValue<T>(value: T, delay: number): T {
|
||||
export function DataTableToolbar<TData>({
|
||||
data,
|
||||
setDataTable,
|
||||
table,
|
||||
}: DataTableToolbarProps<TData>) {
|
||||
const [value, setValue] = useState('');
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [exportDialogOpen, setExportDialogOpen] = useState(false);
|
||||
const [importDialogOpen, setImportDialogOpen] = useState(false);
|
||||
const debouncedValue = useDebouncedValue(value, 1000);
|
||||
const { setPanelContent, openPanel, closePanel, isOpen } = useRightPanel();
|
||||
const { result, query } = useSearch();
|
||||
@@ -106,22 +113,82 @@ export function DataTableToolbar<TData>({
|
||||
return handleConfirm();
|
||||
}, [handleConfirm, isOpen]);
|
||||
|
||||
const handleExportUsers = useCallback(() => {
|
||||
if (!table) return;
|
||||
|
||||
const selectedRows = table.getFilteredSelectedRowModel().rows;
|
||||
|
||||
if (selectedRows.length === 0) {
|
||||
alert('Please select at least one user to export');
|
||||
return;
|
||||
}
|
||||
|
||||
setExportDialogOpen(true);
|
||||
}, [table]);
|
||||
|
||||
const handleImportUsers = useCallback(() => {
|
||||
setImportDialogOpen(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-1 items-center space-x-2">
|
||||
<Input
|
||||
placeholder="Search Email"
|
||||
value={value}
|
||||
onChange={onValueChange}
|
||||
className="h-10 w-full mr-[10px]"
|
||||
<div className="flex items-center justify-between gap-y-2 gap-x-4">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-8 px-2 lg:px-3"
|
||||
onClick={handleImportUsers}
|
||||
>
|
||||
<ImportIcon fontSize={20} />
|
||||
<span className="ml-2 hidden md:inline-block">Import</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-8 px-2 lg:px-3"
|
||||
onClick={handleExportUsers}
|
||||
disabled={
|
||||
!table || table.getFilteredSelectedRowModel().rows.length === 0
|
||||
}
|
||||
>
|
||||
<ExportIcon fontSize={20} />
|
||||
<span className="ml-2 hidden md:inline-block">Export</span>
|
||||
</Button>
|
||||
|
||||
{table && (
|
||||
<ExportUsersDialog
|
||||
users={table
|
||||
.getFilteredSelectedRowModel()
|
||||
.rows.map(row => row.original as UserType)}
|
||||
open={exportDialogOpen}
|
||||
onOpenChange={setExportDialogOpen}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ImportUsersDialog
|
||||
open={importDialogOpen}
|
||||
onOpenChange={setImportDialogOpen}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="px-4 py-2 space-x-[10px] text-sm font-medium"
|
||||
onClick={handleOpenConfirm}
|
||||
>
|
||||
<PlusIcon size={20} /> <span>Add User</span>
|
||||
</Button>
|
||||
|
||||
<div className="flex items-center gap-y-2 flex-wrap justify-end gap-2">
|
||||
<div className="flex">
|
||||
<Input
|
||||
placeholder="Search Email"
|
||||
value={value}
|
||||
onChange={onValueChange}
|
||||
className="h-8 w-[150px] lg:w-[250px]"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="h-8 px-2 lg:px-3 space-x-[6px] text-sm font-medium"
|
||||
onClick={handleOpenConfirm}
|
||||
>
|
||||
<PlusIcon fontSize={20} /> <span>Add User</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<DiscardChanges
|
||||
open={dialogOpen}
|
||||
onOpenChange={setDialogOpen}
|
||||
|
||||
Reference in New Issue
Block a user