mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-18 06:47:02 +08:00
fix(admin): user count is out of sync and search results are not cached in account management (#11980)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Improved user management table with dynamic row count updates and enhanced synchronization of memoized user lists. - **Bug Fixes** - User count and displayed data now update immediately after user creation, deletion, or import, ensuring accurate and consistent information. - **Chores** - Enhanced internal state management for better responsiveness and reliability in the accounts section. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -4,8 +4,8 @@ import { useQuery } from '@affine/admin/use-query';
|
||||
import { getUserByEmailQuery } from '@affine/graphql';
|
||||
import { ExportIcon, ImportIcon, PlusIcon } from '@blocksuite/icons/rc';
|
||||
import type { Table } from '@tanstack/react-table';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import {
|
||||
type SetStateAction,
|
||||
startTransition,
|
||||
useCallback,
|
||||
useEffect,
|
||||
@@ -22,8 +22,11 @@ import { CreateUserForm } from './user-form';
|
||||
|
||||
interface DataTableToolbarProps<TData> {
|
||||
data: TData[];
|
||||
setDataTable: (data: TData[]) => void;
|
||||
usersCount: number;
|
||||
selectedUsers: UserType[];
|
||||
setDataTable: (data: TData[]) => void;
|
||||
setRowCount: (rowCount: number) => void;
|
||||
setMemoUsers: Dispatch<SetStateAction<UserType[]>>;
|
||||
table?: Table<TData>;
|
||||
}
|
||||
|
||||
@@ -60,8 +63,11 @@ function useDebouncedValue<T>(value: T, delay: number): T {
|
||||
|
||||
export function DataTableToolbar<TData>({
|
||||
data,
|
||||
usersCount,
|
||||
selectedUsers,
|
||||
setDataTable,
|
||||
setRowCount,
|
||||
setMemoUsers,
|
||||
table,
|
||||
}: DataTableToolbarProps<TData>) {
|
||||
const [value, setValue] = useState('');
|
||||
@@ -90,13 +96,25 @@ export function DataTableToolbar<TData>({
|
||||
startTransition(() => {
|
||||
if (!debouncedValue) {
|
||||
setDataTable(data);
|
||||
setRowCount(usersCount);
|
||||
} else if (result) {
|
||||
setMemoUsers(prev => [...new Set([...prev, result])]);
|
||||
setDataTable([result as TData]);
|
||||
setRowCount(1);
|
||||
} else {
|
||||
setDataTable([]);
|
||||
setRowCount(0);
|
||||
}
|
||||
});
|
||||
}, [data, debouncedValue, result, setDataTable]);
|
||||
}, [
|
||||
data,
|
||||
debouncedValue,
|
||||
result,
|
||||
setDataTable,
|
||||
setMemoUsers,
|
||||
setRowCount,
|
||||
usersCount,
|
||||
]);
|
||||
|
||||
const onValueChange = useCallback(
|
||||
(e: { currentTarget: { value: SetStateAction<string> } }) => {
|
||||
|
||||
@@ -21,13 +21,14 @@ import { type Dispatch, type SetStateAction, useEffect, useState } from 'react';
|
||||
import type { UserType } from '../schema';
|
||||
import { DataTablePagination } from './data-table-pagination';
|
||||
import { DataTableToolbar } from './data-table-toolbar';
|
||||
import { useUserCount } from './use-user-management';
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
pagination: PaginationState;
|
||||
usersCount: number;
|
||||
selectedUsers: UserType[];
|
||||
setMemoUsers: Dispatch<SetStateAction<UserType[]>>;
|
||||
onPaginationChange: Dispatch<
|
||||
SetStateAction<{
|
||||
pageIndex: number;
|
||||
@@ -40,22 +41,23 @@ export function DataTable<TData extends { id: string }, TValue>({
|
||||
columns,
|
||||
data,
|
||||
pagination,
|
||||
usersCount,
|
||||
selectedUsers,
|
||||
setMemoUsers,
|
||||
onPaginationChange,
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
const usersCount = useUserCount();
|
||||
|
||||
const [rowSelection, setRowSelection] = useState({});
|
||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
|
||||
|
||||
const [tableData, setTableData] = useState(data);
|
||||
const [rowCount, setRowCount] = useState(usersCount);
|
||||
const table = useReactTable({
|
||||
data: tableData,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getRowId: row => row.id,
|
||||
manualPagination: true,
|
||||
rowCount: usersCount,
|
||||
rowCount: rowCount,
|
||||
enableFilters: true,
|
||||
onPaginationChange: onPaginationChange,
|
||||
enableRowSelection: true,
|
||||
@@ -72,13 +74,20 @@ export function DataTable<TData extends { id: string }, TValue>({
|
||||
setTableData(data);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
setRowCount(usersCount);
|
||||
}, [usersCount]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4 py-5 px-6 h-full overflow-auto">
|
||||
<DataTableToolbar
|
||||
setDataTable={setTableData}
|
||||
data={data}
|
||||
usersCount={usersCount}
|
||||
table={table}
|
||||
selectedUsers={selectedUsers}
|
||||
setRowCount={setRowCount}
|
||||
setMemoUsers={setMemoUsers}
|
||||
/>
|
||||
<div className="rounded-md border h-full flex flex-col overflow-auto">
|
||||
<Table>
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
useMutateQueryResource,
|
||||
useMutation,
|
||||
} from '@affine/admin/use-mutation';
|
||||
import { useQuery } from '@affine/admin/use-query';
|
||||
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
||||
import {
|
||||
createChangePasswordUrlMutation,
|
||||
@@ -10,7 +9,6 @@ import {
|
||||
deleteUserMutation,
|
||||
disableUserMutation,
|
||||
enableUserMutation,
|
||||
getUsersCountQuery,
|
||||
type ImportUsersInput,
|
||||
type ImportUsersMutation,
|
||||
importUsersMutation,
|
||||
@@ -225,15 +223,6 @@ export const useDisableUser = () => {
|
||||
return disableById;
|
||||
};
|
||||
|
||||
export const useUserCount = () => {
|
||||
const {
|
||||
data: { usersCount },
|
||||
} = useQuery({
|
||||
query: getUsersCountQuery,
|
||||
});
|
||||
return usersCount;
|
||||
};
|
||||
|
||||
export const useImportUsers = () => {
|
||||
const { trigger: importUsers } = useMutation({
|
||||
mutation: importUsersMutation,
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { UserType } from './schema';
|
||||
import { useUserList } from './use-user-list';
|
||||
|
||||
export function AccountPage() {
|
||||
const { users, pagination, setPagination } = useUserList();
|
||||
const { users, pagination, setPagination, usersCount } = useUserList();
|
||||
// Remember the user temporarily, because userList is paginated on the server side,can't get all users at once.
|
||||
const [memoUsers, setMemoUsers] = useState<UserType[]>([]);
|
||||
|
||||
@@ -32,8 +32,10 @@ export function AccountPage() {
|
||||
data={users}
|
||||
columns={columns}
|
||||
pagination={pagination}
|
||||
usersCount={usersCount}
|
||||
onPaginationChange={setPagination}
|
||||
selectedUsers={selectedUsers}
|
||||
setMemoUsers={setMemoUsers}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ export const useUserList = () => {
|
||||
pageSize: 10,
|
||||
});
|
||||
const {
|
||||
data: { users },
|
||||
data: { users, usersCount },
|
||||
} = useQuery({
|
||||
query: listUsersQuery,
|
||||
variables: {
|
||||
@@ -23,5 +23,6 @@ export const useUserList = () => {
|
||||
users,
|
||||
pagination,
|
||||
setPagination,
|
||||
usersCount,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user