From f032c732f1a543f04b982f5ad1182be32cccf1b2 Mon Sep 17 00:00:00 2001 From: YANG QIA <2013xile@gmail.com> Date: Sun, 15 Sep 2024 20:49:18 +0800 Subject: [PATCH] perf(users): optimize performance for rendering the user management table (#5276) * perf(users): optimize render performance of the user management table * fix: bug --- .../src/client/UsersManagement.tsx | 85 +++++++++++-- .../plugin-users/src/client/schemas/users.ts | 114 +++++++++--------- .../plugin-users/src/server/actions/users.ts | 2 +- 3 files changed, 131 insertions(+), 70 deletions(-) diff --git a/packages/plugins/@nocobase/plugin-users/src/client/UsersManagement.tsx b/packages/plugins/@nocobase/plugin-users/src/client/UsersManagement.tsx index c5a3bb5dab..7178d7f3ce 100644 --- a/packages/plugins/@nocobase/plugin-users/src/client/UsersManagement.tsx +++ b/packages/plugins/@nocobase/plugin-users/src/client/UsersManagement.tsx @@ -7,27 +7,88 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import { SchemaComponent, SchemaComponentContext, useSchemaComponentContext } from '@nocobase/client'; -import React from 'react'; +import { + SchemaComponent, + SchemaComponentContext, + useActionContext, + useCollection, + useCollectionRecordData, + useDataBlockRequest, + useDataBlockResource, + useSchemaComponentContext, +} from '@nocobase/client'; +import React, { useEffect, useMemo } from 'react'; import { usersSchema } from './schemas/users'; -import { Card } from 'antd'; -import { UserRolesField } from './UserRolesField'; import { useUsersTranslation } from './locale'; -import { useFilterActionProps } from './hooks'; import { PasswordField } from './PasswordField'; +import { App } from 'antd'; +import { useForm } from '@formily/react'; +import { createForm } from '@formily/core'; + +const useCancelActionProps = () => { + const { setVisible } = useActionContext(); + return { + type: 'default', + onClick() { + setVisible(false); + }, + }; +}; + +const useSubmitActionProps = () => { + const { setVisible } = useActionContext(); + const { message } = App.useApp(); + const form = useForm(); + const resource = useDataBlockResource(); + const { runAsync } = useDataBlockRequest(); + const { t } = useUsersTranslation(); + const collection = useCollection(); + + return { + type: 'primary', + async onClick() { + await form.submit(); + const values = form.values; + console.log('values:', values); + if (values[collection.filterTargetKey]) { + await resource.update({ + values, + filterByTk: values[collection.filterTargetKey], + }); + } else { + await resource.create({ values }); + } + await runAsync(); + message.success(t('Saved successfully')); + setVisible(false); + }, + }; +}; + +const useEditFormProps = () => { + const recordData = useCollectionRecordData(); + const form = useMemo( + () => + createForm({ + initialValues: recordData, + }), + [recordData], + ); + return { + form, + }; +}; export const UsersManagement: React.FC = () => { const { t } = useUsersTranslation(); const scCtx = useSchemaComponentContext(); return ( - - - + ); }; diff --git a/packages/plugins/@nocobase/plugin-users/src/client/schemas/users.ts b/packages/plugins/@nocobase/plugin-users/src/client/schemas/users.ts index 629d9478d2..4f31d6f632 100644 --- a/packages/plugins/@nocobase/plugin-users/src/client/schemas/users.ts +++ b/packages/plugins/@nocobase/plugin-users/src/client/schemas/users.ts @@ -132,26 +132,28 @@ export const usersSchema: ISchema = { properties: { block1: { type: 'void', - 'x-decorator': 'ResourceActionProvider', + 'x-component': 'CardItem', + 'x-component-props': { + heightMode: 'fullHeight', + }, + 'x-decorator': 'TableBlockProvider', 'x-decorator-props': { - collection: userCollection, - resourceName: 'users', - request: { - resource: 'users', - action: 'list', - params: { - pageSize: 50, - appends: [], - }, + dataSource: 'main', + rowKey: 'id', + collection: 'users', + action: 'list', + params: { + pageSize: 20, }, }, + 'x-use-decorator-props': 'useTableBlockDecoratorProps', properties: { actions: { type: 'void', 'x-component': 'ActionBar', 'x-component-props': { style: { - marginBottom: 16, + marginBottom: 'var(--nb-spacing)', }, }, properties: { @@ -166,18 +168,28 @@ export const usersSchema: ISchema = { }, 'x-align': 'left', }, + refresh: { + type: 'void', + title: '{{ t("Refresh") }}', + 'x-action': 'refresh', + 'x-component': 'Action', + 'x-component-props': { + icon: 'ReloadOutlined', + }, + 'x-use-component-props': 'useRefreshActionProps', + }, delete: { type: 'void', title: '{{ t("Delete") }}', 'x-component': 'Action', 'x-component-props': { - useAction: '{{ cm.useBulkDestroyAction }}', confirm: { title: "{{t('Delete users')}}", content: "{{t('Are you sure you want to delete it?')}}", }, icon: 'DeleteOutlined', }, + 'x-use-component-props': 'useBulkDestroyActionProps', }, create: { type: 'void', @@ -191,7 +203,7 @@ export const usersSchema: ISchema = { drawer: { type: 'void', 'x-component': 'Action.Drawer', - 'x-decorator': 'Form', + 'x-decorator': 'FormV2', title: '{{t("Add user")}}', properties: { nickname: { @@ -232,17 +244,15 @@ export const usersSchema: ISchema = { cancel: { title: '{{t("Cancel")}}', 'x-component': 'Action', - 'x-component-props': { - useAction: '{{ cm.useCancelAction }}', - }, + 'x-use-component-props': 'useCancelActionProps', }, submit: { title: '{{t("Submit")}}', 'x-component': 'Action', 'x-component-props': { type: 'primary', - useAction: '{{ cm.useCreateAction }}', }, + 'x-use-component-props': 'useSubmitActionProps', }, }, }, @@ -253,21 +263,21 @@ export const usersSchema: ISchema = { }, }, table: { - type: 'void', + type: 'array', 'x-uid': 'input', - 'x-component': 'Table.Void', + 'x-component': 'TableV2', 'x-component-props': { rowKey: 'id', rowSelection: { type: 'checkbox', }, - useDataSource: '{{ cm.useDataSourceFromRAC }}', }, + 'x-use-component-props': 'useTableBlockProps', properties: { column1: { type: 'void', - 'x-decorator': 'Table.Column.Decorator', - 'x-component': 'Table.Column', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-component': 'TableV2.Column', properties: { nickname: { type: 'number', @@ -278,8 +288,8 @@ export const usersSchema: ISchema = { }, column2: { type: 'void', - 'x-decorator': 'Table.Column.Decorator', - 'x-component': 'Table.Column', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-component': 'TableV2.Column', properties: { username: { type: 'string', @@ -290,8 +300,8 @@ export const usersSchema: ISchema = { }, column3: { type: 'void', - 'x-decorator': 'Table.Column.Decorator', - 'x-component': 'Table.Column', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-component': 'TableV2.Column', properties: { email: { type: 'string', @@ -302,20 +312,28 @@ export const usersSchema: ISchema = { }, column4: { type: 'void', - 'x-decorator': 'Table.Column.Decorator', - 'x-component': 'Table.Column', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-component': 'TableV2.Column', title: '{{t("Roles")}}', properties: { roles: { type: 'array', - 'x-component': 'UserRolesField', + 'x-component': 'CollectionField', + 'x-component-props': { + mode: 'Tag', + enableLink: false, + ellipsis: true, + }, + 'x-read-pretty': true, + 'x-collection-field': 'users.roles', }, }, }, column5: { type: 'void', title: '{{t("Actions")}}', - 'x-component': 'Table.Column', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.ActionBar', properties: { actions: { type: 'void', @@ -337,23 +355,8 @@ export const usersSchema: ISchema = { drawer: { type: 'void', 'x-component': 'Action.Drawer', - 'x-decorator': 'Form', - 'x-decorator-props': { - useValues: (options) => { - const record = useRecord(); - const result = useRequest(() => Promise.resolve({ data: record }), { - ...options, - manual: true, - }); - const ctx = useActionContext(); - useEffect(() => { - if (ctx.visible) { - result.run(); - } - }, [ctx.visible]); - return result; - }, - }, + 'x-decorator': 'FormV2', + 'x-use-decorator-props': 'useEditFormProps', title: '{{t("Edit profile")}}', properties: { nickname: { @@ -389,17 +392,15 @@ export const usersSchema: ISchema = { cancel: { title: '{{t("Cancel")}}', 'x-component': 'Action', - 'x-component-props': { - useAction: '{{ cm.useCancelAction }}', - }, + 'x-use-component-props': 'useCancelActionProps', }, submit: { title: '{{t("Submit")}}', 'x-component': 'Action', 'x-component-props': { type: 'primary', - useAction: '{{ cm.useUpdateAction }}', }, + 'x-use-component-props': 'useSubmitActionProps', }, }, }, @@ -420,7 +421,8 @@ export const usersSchema: ISchema = { drawer: { type: 'void', 'x-component': 'Action.Drawer', - 'x-decorator': 'Form', + 'x-decorator': 'FormV2', + 'x-use-decorator-props': 'useEditFormProps', title: '{{t("Change password")}}', properties: { password: { @@ -438,17 +440,15 @@ export const usersSchema: ISchema = { cancel: { title: '{{t("Cancel")}}', 'x-component': 'Action', - 'x-component-props': { - useAction: '{{ cm.useCancelAction }}', - }, + 'x-use-component-props': 'useCancelActionProps', }, submit: { title: '{{t("Submit")}}', 'x-component': 'Action', 'x-component-props': { type: 'primary', - useAction: '{{ cm.useUpdateAction }}', }, + 'x-use-component-props': 'useSubmitActionProps', }, }, }, @@ -468,8 +468,8 @@ export const usersSchema: ISchema = { title: "{{t('Delete')}}", content: "{{t('Are you sure you want to delete it?')}}", }, - useAction: '{{cm.useDestroyAction}}', }, + 'x-use-component-props': 'useDestroyActionProps', }, }, }, diff --git a/packages/plugins/@nocobase/plugin-users/src/server/actions/users.ts b/packages/plugins/@nocobase/plugin-users/src/server/actions/users.ts index 1c475ba68b..d967b0e37c 100644 --- a/packages/plugins/@nocobase/plugin-users/src/server/actions/users.ts +++ b/packages/plugins/@nocobase/plugin-users/src/server/actions/users.ts @@ -48,7 +48,7 @@ export const listExcludeRole = async (ctx: Context, next: Next) => { const [rows, count] = await repo.findAndCount({ context: ctx, offset: (page - 1) * pageSize, - limit: pageSize, + limit: +pageSize, filter, }); ctx.body = {