From e7b9737920ca1c3ff458e4efd5f056712ff9e702 Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Wed, 20 Dec 2023 13:56:24 +0800 Subject: [PATCH] perf: remove lazy load association fields (#3222) * perf: remove lazy load association fields * test: fix error * chore: fix workflows * test: fix error * test: fix errors --- .../__e2e__/lazyLoadAssociationFields.test.ts | 136 +++++++++--------- .../antd/form-item/FormItem.tsx | 2 - .../useLazyLoadAssociationFieldOfForm.ts | 84 ----------- .../form-item/form-edit/basic.test.ts | 26 ++-- 4 files changed, 76 insertions(+), 172 deletions(-) delete mode 100644 packages/core/client/src/schema-component/antd/form-item/hooks/useLazyLoadAssociationFieldOfForm.ts diff --git a/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadAssociationFields.test.ts b/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadAssociationFields.test.ts index da8061b20..2167f158e 100644 --- a/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadAssociationFields.test.ts +++ b/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadAssociationFields.test.ts @@ -49,6 +49,74 @@ test.describe('display association fields', () => { ); }); + // https://nocobase.height.app/T-2615 + test('BUG: should load association data', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(T2615).waitForInit(); + await mockRecord('T2615'); + await nocoPage.goto(); + + // 1. 新增表单中应该显示关系字段的数据 + await page.getByRole('button', { name: 'Add new' }).click(); + await page + .getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o') + .getByTestId('select-object-single') + .click(); + await page.getByRole('option', { name: '1' }).click(); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( + `m2oOfTarget1:1`, + ); + + // 关闭弹窗 + await page.getByLabel('drawer-Action.Container-T2615-Add record-mask').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 2. 编辑表单中应该显示关系字段的数据 + await page.getByLabel('action-Action.Link-Edit record-update-T2615-table-0').click(); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o')).toHaveText(`m2o:1`); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( + `m2oOfTarget1:1`, + ); + + await page.getByLabel('drawer-Action.Container-T2615-Edit record-mask').click(); + + // 3. 详情中应该显示关系字段的数据 + await page.getByLabel('action-Action.Link-View record-view-T2615-table-0').click(); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o')).toHaveText(`m2o:1`); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( + `m2oOfTarget1:1`, + ); + }); + + // https://nocobase.height.app/T-2614 + test('BUG: should load association data in subform', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(T2614).waitForInit(); + await mockRecord('T2614'); + await nocoPage.goto(); + + // 查看详情 + await page.getByLabel('action-Action.Link-View record-view-T2614-table-0').click(); + await expect( + page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1-m2oOfTarget1'), + ).toHaveText(`m2oOfTarget1:1`); + await expect( + page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1.id'), + ).toHaveText(`ID:1`); + + // 关闭弹窗 + await page.getByLabel('drawer-Action.Container-T2614-View record-mask').click(); + + // 编辑详情 + await page.getByLabel('action-Action.Link-Edit record-update-T2614-table-0').click(); + await expect( + page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1-m2oOfTarget1'), + ).toHaveText(`m2oOfTarget1:1`); + await expect( + page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1.id'), + ).toHaveText(`ID:1`); + }); +}); + +test.describe('association fields', () => { test('subform: load association fields', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneTableSubformWithMultiLevelAssociationFields).waitForInit(); const record = await mockRecord('general'); @@ -129,74 +197,6 @@ test.describe('display association fields', () => { } }); - // https://nocobase.height.app/T-2615 - test('BUG: should load association data', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(T2615).waitForInit(); - await mockRecord('T2615'); - await nocoPage.goto(); - - // 1. 新增表单中应该显示关系字段的数据 - await page.getByRole('button', { name: 'Add new' }).click(); - await page - .getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o') - .getByTestId('select-object-single') - .click(); - await page.getByRole('option', { name: '1' }).click(); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( - `m2oOfTarget1:1`, - ); - - // 关闭弹窗 - await page.getByLabel('drawer-Action.Container-T2615-Add record-mask').click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 2. 编辑表单中应该显示关系字段的数据 - await page.getByLabel('action-Action.Link-Edit record-update-T2615-table-0').click(); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o')).toHaveText(`m2o:1`); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( - `m2oOfTarget1:1`, - ); - - await page.getByLabel('drawer-Action.Container-T2615-Edit record-mask').click(); - - // 3. 详情中应该显示关系字段的数据 - await page.getByLabel('action-Action.Link-View record-view-T2615-table-0').click(); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o')).toHaveText(`m2o:1`); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( - `m2oOfTarget1:1`, - ); - }); - - // https://nocobase.height.app/T-2614 - test('BUG: should load association data in subform', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(T2614).waitForInit(); - await mockRecord('T2614'); - await nocoPage.goto(); - - // 查看详情 - await page.getByLabel('action-Action.Link-View record-view-T2614-table-0').click(); - await expect( - page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1-m2oOfTarget1'), - ).toHaveText(`m2oOfTarget1:1`); - await expect( - page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1.id'), - ).toHaveText(`ID:1`); - - // 关闭弹窗 - await page.getByLabel('drawer-Action.Container-T2614-View record-mask').click(); - - // 编辑详情 - await page.getByLabel('action-Action.Link-Edit record-update-T2614-table-0').click(); - await expect( - page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1-m2oOfTarget1'), - ).toHaveText(`m2oOfTarget1:1`); - await expect( - page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1.id'), - ).toHaveText(`ID:1`); - }); -}); - -test.describe('association fields', () => { // fix https://nocobase.height.app/T-2200 test('BUG: should be possible to change the value of the association field normally', async ({ page, mockPage }) => { await mockPage(T2200).goto(); diff --git a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx index ac06c1dfd..53ad5c586 100644 --- a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx +++ b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx @@ -14,7 +14,6 @@ import { BlockItem } from '../block-item'; import { HTMLEncode } from '../input/shared'; import { FilterFormDesigner } from './FormItem.FilterFormDesigner'; import { useEnsureOperatorsValid } from './SchemaSettingOptions'; -import useLazyLoadAssociationFieldOfForm from './hooks/useLazyLoadAssociationFieldOfForm'; import useLazyLoadDisplayAssociationFieldsOfForm from './hooks/useLazyLoadDisplayAssociationFieldsOfForm'; import useParseDefaultValue from './hooks/useParseDefaultValue'; @@ -34,7 +33,6 @@ export const FormItem: any = observer( // 需要放在注冊完变量之后 useParseDefaultValue(); useLazyLoadDisplayAssociationFieldsOfForm(); - useLazyLoadAssociationFieldOfForm(); useEffect(() => { addActiveFieldName?.(schema.name as string); diff --git a/packages/core/client/src/schema-component/antd/form-item/hooks/useLazyLoadAssociationFieldOfForm.ts b/packages/core/client/src/schema-component/antd/form-item/hooks/useLazyLoadAssociationFieldOfForm.ts deleted file mode 100644 index 63e84b894..000000000 --- a/packages/core/client/src/schema-component/antd/form-item/hooks/useLazyLoadAssociationFieldOfForm.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Field } from '@formily/core'; -import { useField, useFieldSchema } from '@formily/react'; -import _ from 'lodash'; -import { useEffect } from 'react'; -import { useFormBlockType, useRecord } from '../../../..'; -import { useCollection, useCollectionManager } from '../../../../collection-manager'; -import { useFlag } from '../../../../flag-provider'; -import { useVariables } from '../../../../variables'; -import { transformVariableValue } from '../../../../variables/utils/transformVariableValue'; -import { isDisplayField, isFieldValueEmpty } from '../utils'; - -/** - * 用于懒加载 Form 区块中正常的关系字段 - * - * - 当 record 中缺少对应的字段值时,通过解析变量的方法去获取关系字段的值 - * - 注意:应该只有在编辑模式下运行,创建模式下直接返回 - */ -const useLazyLoadAssociationFieldOfForm = () => { - const { name } = useCollection(); - const { getCollectionJoinField } = useCollectionManager(); - const record = useRecord(); - const fieldSchema = useFieldSchema(); - const variables = useVariables(); - const field = useField(); - const { isInAssignFieldValues, isInSubForm, isInSubTable } = useFlag() || {}; - const { type: formBlockType } = useFormBlockType(); - - const schemaName = fieldSchema.name.toString(); - - useEffect(() => { - const cloneRecord = { ...record }; - delete cloneRecord['__parent']; - delete cloneRecord['__collectionName']; - - if ( - isInAssignFieldValues || - _.isEmpty(cloneRecord) || - (formBlockType === 'create' && !isInSubForm && !isInSubTable) || - isDisplayField(schemaName) - ) { - return; - } - - const collectionField = getCollectionJoinField(`${name}.${schemaName}`); - - if (!collectionField) { - return; - } - - if (!variables || !isFieldValueEmpty(_.get(record, schemaName), collectionField.targetKey || 'id')) { - return; - } - - // 通过模拟一个 record 变量,用解析变量的方法去获取关系字段的值 - const recordVariable = { - name: '$nRecord', - ctx: cloneRecord, - collectionName: name, - }; - const variableString = `{{ $nRecord.${schemaName} }}`; - - variables - .parseVariable(variableString, recordVariable) - .then((value) => { - // fix https://nocobase.height.app/T-2288 - // 造成这个问题的原因有以下几点: - // 1. 编辑表单自身会请求数据,并在请求数据时,会在 appends 参数中加上所有的关系字段路径(包括子表单中的); - // 2. 而 `变量预加载中` 也会请求对应关系字段的数据,但是请求的数据是不包含子表单中的关系字段的; - // 3. 所以,当 `变量预加载` 的请求晚于编辑表单的请求时,就会造成这个问题; - // 更优的解决方案是:在 `变量预加载` 中也加上子表单中的关系字段路径,并删除编辑表单请求数据的逻辑(因为没必要了)。 - // 但是这样改动较大,可以等之后 e2e 测试较完备后再处理。 - if (!isFieldValueEmpty(field.value, collectionField.targetKey || 'id')) { - return; - } - - field.value = transformVariableValue(value, { targetCollectionField: collectionField }); - }) - .catch((err) => { - console.error(err); - }); - }, [record]); -}; - -export default useLazyLoadAssociationFieldOfForm; diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/basic.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/basic.test.ts index 18a96fd70..b2e99bbcc 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/basic.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/basic.test.ts @@ -86,22 +86,11 @@ test.describe('icon', () => { }, expectReadonly: async () => { // 只读模式下,选择图标按钮会被禁用 - if (record.icon) { - await expect(page.getByRole('button', { name: record.icon })).toBeDisabled(); - } else { - await expect(page.getByRole('button', { name: 'Select icon' })).toBeDisabled(); - } + await expect(page.getByRole('button', { name: 'account-book' })).toBeDisabled(); }, expectEasyReading: async () => { // 按钮会消失,只剩下图标 - if (record.icon) { - await expect(page.getByRole('button', { name: record.icon })).not.toBeVisible(); - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.icon-icon').getByLabel(record.icon), - ).toBeVisible(); - } else { - await expect(page.getByRole('button', { name: 'Select icon' })).not.toBeVisible(); - } + await expect(page.getByRole('button', { name: 'account-book' })).not.toBeVisible(); }, }); }); @@ -298,7 +287,7 @@ test.describe('password', () => { page.getByLabel('block-item-CollectionField-general-form-general.password-password').getByRole('textbox'), ).not.toBeVisible(); await expect(page.getByLabel('block-item-CollectionField-general-form-general.password-password')).toHaveText( - 'password:', + 'password:********', ); }, }); @@ -407,7 +396,7 @@ test.describe('phone', () => { page.getByLabel('block-item-CollectionField-general-form-general.phone-phone').getByRole('textbox'), ).not.toBeVisible(); await expect(page.getByLabel('block-item-CollectionField-general-form-general.phone-phone')).toHaveText( - 'phone:', + 'phone:17777777777', ); }, }); @@ -453,7 +442,7 @@ test.describe('long text', () => { page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), ).not.toBeVisible(); await expect(page.getByLabel('block-item-CollectionField-general-form-general.longText-longText')).toHaveText( - `longText:${record.longText}`.replaceAll('\n', ''), + `longText:test long text`, ); }, }); @@ -496,11 +485,12 @@ test.describe('URL', () => { ).toBeDisabled(); }, expectEasyReading: async () => { - // url 类型数据不会被 mock,所以这里不会显示值 await expect( page.getByLabel('block-item-CollectionField-general-form-general.url-url').getByRole('textbox'), ).not.toBeVisible(); - await expect(page.getByLabel('block-item-CollectionField-general-form-general.url-url')).toHaveText('url:'); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.url-url')).toHaveText( + 'url:https://nocobase.com', + ); }, }); });