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
This commit is contained in:
Zeke Zhang 2023-12-20 13:56:24 +08:00 committed by GitHub
parent aaee46e0c2
commit e7b9737920
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 172 deletions

View File

@ -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 }) => { test('subform: load association fields', async ({ page, mockPage, mockRecord }) => {
const nocoPage = await mockPage(oneTableSubformWithMultiLevelAssociationFields).waitForInit(); const nocoPage = await mockPage(oneTableSubformWithMultiLevelAssociationFields).waitForInit();
const record = await mockRecord('general'); 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 // fix https://nocobase.height.app/T-2200
test('BUG: should be possible to change the value of the association field normally', async ({ page, mockPage }) => { test('BUG: should be possible to change the value of the association field normally', async ({ page, mockPage }) => {
await mockPage(T2200).goto(); await mockPage(T2200).goto();

View File

@ -14,7 +14,6 @@ import { BlockItem } from '../block-item';
import { HTMLEncode } from '../input/shared'; import { HTMLEncode } from '../input/shared';
import { FilterFormDesigner } from './FormItem.FilterFormDesigner'; import { FilterFormDesigner } from './FormItem.FilterFormDesigner';
import { useEnsureOperatorsValid } from './SchemaSettingOptions'; import { useEnsureOperatorsValid } from './SchemaSettingOptions';
import useLazyLoadAssociationFieldOfForm from './hooks/useLazyLoadAssociationFieldOfForm';
import useLazyLoadDisplayAssociationFieldsOfForm from './hooks/useLazyLoadDisplayAssociationFieldsOfForm'; import useLazyLoadDisplayAssociationFieldsOfForm from './hooks/useLazyLoadDisplayAssociationFieldsOfForm';
import useParseDefaultValue from './hooks/useParseDefaultValue'; import useParseDefaultValue from './hooks/useParseDefaultValue';
@ -34,7 +33,6 @@ export const FormItem: any = observer(
// 需要放在注冊完变量之后 // 需要放在注冊完变量之后
useParseDefaultValue(); useParseDefaultValue();
useLazyLoadDisplayAssociationFieldsOfForm(); useLazyLoadDisplayAssociationFieldsOfForm();
useLazyLoadAssociationFieldOfForm();
useEffect(() => { useEffect(() => {
addActiveFieldName?.(schema.name as string); addActiveFieldName?.(schema.name as string);

View File

@ -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<Field>();
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;

View File

@ -86,22 +86,11 @@ test.describe('icon', () => {
}, },
expectReadonly: async () => { expectReadonly: async () => {
// 只读模式下,选择图标按钮会被禁用 // 只读模式下,选择图标按钮会被禁用
if (record.icon) { await expect(page.getByRole('button', { name: 'account-book' })).toBeDisabled();
await expect(page.getByRole('button', { name: record.icon })).toBeDisabled();
} else {
await expect(page.getByRole('button', { name: 'Select icon' })).toBeDisabled();
}
}, },
expectEasyReading: async () => { expectEasyReading: async () => {
// 按钮会消失,只剩下图标 // 按钮会消失,只剩下图标
if (record.icon) { await expect(page.getByRole('button', { name: 'account-book' })).not.toBeVisible();
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();
}
}, },
}); });
}); });
@ -298,7 +287,7 @@ test.describe('password', () => {
page.getByLabel('block-item-CollectionField-general-form-general.password-password').getByRole('textbox'), page.getByLabel('block-item-CollectionField-general-form-general.password-password').getByRole('textbox'),
).not.toBeVisible(); ).not.toBeVisible();
await expect(page.getByLabel('block-item-CollectionField-general-form-general.password-password')).toHaveText( 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'), page.getByLabel('block-item-CollectionField-general-form-general.phone-phone').getByRole('textbox'),
).not.toBeVisible(); ).not.toBeVisible();
await expect(page.getByLabel('block-item-CollectionField-general-form-general.phone-phone')).toHaveText( 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'), page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'),
).not.toBeVisible(); ).not.toBeVisible();
await expect(page.getByLabel('block-item-CollectionField-general-form-general.longText-longText')).toHaveText( 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(); ).toBeDisabled();
}, },
expectEasyReading: async () => { expectEasyReading: async () => {
// url 类型数据不会被 mock所以这里不会显示值
await expect( await expect(
page.getByLabel('block-item-CollectionField-general-form-general.url-url').getByRole('textbox'), page.getByLabel('block-item-CollectionField-general-form-general.url-url').getByRole('textbox'),
).not.toBeVisible(); ).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',
);
}, },
}); });
}); });