fix(dataScope): fix issue with nested association field variables (#5866)

This commit is contained in:
Zeke Zhang 2024-12-12 10:27:42 +08:00 committed by GitHub
parent f9afb13cee
commit d5ac3eee04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 328 additions and 8 deletions

View File

@ -57,12 +57,27 @@ export function useParsedFilter({ filterOption }: { filterOption: any }) {
throw new Error(`useParsedFilter: can not find variable ${variableName}`);
}
const result = getValuesByPath(
{
[variableName]: variable?.ctx || {},
},
getPath(value),
);
let result = null;
const path = getPath(value);
const keys = path.split('.');
// For a path like 'a.b.c', if ctx.a exists but ctx.a.b doesn't,
// we return the value of ctx.a. This ensures the `run` function is triggered
// when field 'a' changes.
keys.forEach((key, index) => {
const subpath = keys.slice(0, index + 1).join('.');
const _result = getValuesByPath(
{
[variableName]: variable?.ctx || {},
},
subpath,
);
if (!_.isEmpty(_result)) {
result = _result;
}
});
return result;
},
});

View File

@ -28,7 +28,7 @@ test.describe('variables with default value', () => {
.getByRole('textbox'),
).toHaveValue('1');
// https://nocobase.height.app/T-2805 ----------------------------------------------------------------------
// ----------------------------------------------------------------------
await page
.getByLabel('block-item-CollectionField-general-form-general.m2oField0-m2oField0')
.getByTestId('select-object-single')

View File

@ -8,7 +8,7 @@
*/
import { expect, test } from '@nocobase/test/e2e';
import { associationSelectDataScope } from './templatesOfBug';
import { associationSelectDataScope, usingMultiLevelAssociationFieldValuesInDataScope } from './templatesOfBug';
test.describe('AssociationSelect ', () => {
test('data scope linkage with other association select field', async ({ page, mockPage, mockRecord }) => {
@ -42,4 +42,64 @@ test.describe('AssociationSelect ', () => {
//请求参数符合预期
await expect(JSON.parse(filter1)).toEqual({ $and: [{ school: { id: { $eq: 1 } } }] });
});
test('using multi-level association field values in data scope', async ({ page, mockPage, mockRecord }) => {
const nocoPage = await mockPage(usingMultiLevelAssociationFieldValuesInDataScope).waitForInit();
await nocoPage.goto();
const record = await mockRecord('test', 2);
// 1. 一开始字段 b 的下拉列表为空
await page
.getByLabel('block-item-CollectionField-test-form-test.b-b')
.getByTestId('select-object-multiple')
.click();
await expect(page.getByText('No data')).toBeVisible();
// 2. 当给字段 a 选择一个值后,字段 b 的下拉列表中会显示符合条件的值
await page
.getByLabel('block-item-CollectionField-test-form-test.a-a')
.getByTestId('select-object-multiple')
.click();
await page.getByRole('option', { name: record.a[0].id }).click();
// 关闭下拉框
await page.click('body', {
position: {
x: 0,
y: 0,
},
});
await page
.getByLabel('block-item-CollectionField-test-form-test.b-b')
.getByTestId('select-object-multiple')
.click();
for (const item of record.a[0].b) {
await expect(page.getByRole('option', { name: item.id })).toBeVisible();
}
// 3. 当给字段 a 的值变化时,字段 b 的下拉列表也会变化
await page.click('body', {
position: {
x: 0,
y: 0,
},
});
await page
.getByLabel('block-item-CollectionField-test-form-test.a-a')
.getByTestId('select-object-multiple')
.click();
await page.getByRole('option', { name: record.a[1].id }).click();
await page.click('body', {
position: {
x: 0,
y: 0,
},
});
await page
.getByLabel('block-item-CollectionField-test-form-test.b-b')
.getByTestId('select-object-multiple')
.click();
for (const item of record.a[1].b) {
await expect(page.getByRole('option', { name: item.id })).toBeVisible();
}
});
});

View File

@ -456,3 +456,247 @@ export const associationSelectDataScope = {
},
],
};
export const usingMultiLevelAssociationFieldValuesInDataScope = {
collections: [
{
name: 'test',
fields: [
{
name: 'a',
interface: 'm2m',
target: 'A',
},
{
name: 'b',
interface: 'm2m',
target: 'B',
},
],
},
{
name: 'A',
fields: [
{
name: 'b',
interface: 'm2m',
target: 'B',
},
],
},
{
name: 'B',
},
],
pageSchema: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Page',
properties: {
dvf2mwe6bvn: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'page:addBlock',
properties: {
'98y2p0ausvb': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.4.8',
properties: {
t865qbsqxhb: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.4.8',
properties: {
'4ceh9f8smkv': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-acl-action-props': {
skipScopeCheck: true,
},
'x-acl-action': 'test:create',
'x-decorator': 'FormBlockProvider',
'x-use-decorator-props': 'useCreateFormBlockDecoratorProps',
'x-decorator-props': {
dataSource: 'main',
collection: 'test',
},
'x-toolbar': 'BlockSchemaToolbar',
'x-settings': 'blockSettings:createForm',
'x-component': 'CardItem',
'x-app-version': '1.4.8',
properties: {
dq224dw86wj: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'FormV2',
'x-use-component-props': 'useCreateFormBlockProps',
'x-app-version': '1.4.8',
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'form:configureFields',
'x-app-version': '1.4.8',
properties: {
y6j67vnmhw4: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.4.8',
properties: {
bef7a7oph86: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.4.8',
properties: {
a: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': 'test.a',
'x-component-props': {
fieldNames: {
label: 'id',
value: 'id',
},
},
'x-app-version': '1.4.8',
'x-uid': 'y3gtqj8pdqb',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'xad7ytjjufv',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '4gj0r5upoq0',
'x-async': false,
'x-index': 1,
},
shmpsuanpwa: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.4.8',
properties: {
uzy27mws6no: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.4.8',
properties: {
b: {
'x-uid': '7h0yrs8u2bl',
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': 'test.b',
'x-component-props': {
fieldNames: {
label: 'id',
value: 'id',
},
service: {
params: {
filter: {
$and: [
{
id: {
$eq: '{{$nForm.a.b.id}}',
},
},
],
},
},
},
},
'x-app-version': '1.4.8',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'by3u5cxvah1',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'gdn131j2208',
'x-async': false,
'x-index': 2,
},
},
'x-uid': '9navauip2qh',
'x-async': false,
'x-index': 1,
},
culdrszlt2z: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-initializer': 'createForm:configureActions',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
},
'x-app-version': '1.4.8',
'x-uid': 'l8uhg0tzxdh',
'x-async': false,
'x-index': 2,
},
},
'x-uid': 'b4m5no3h8xp',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'a0lixg1oxfr',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'nrbzm8f8wp9',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'co3ws9xtbww',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'ybhswoe7nee',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'd5c5o9pl70o',
'x-async': true,
'x-index': 1,
},
};

View File

@ -71,6 +71,7 @@ const useParseDataScopeFilter = ({ exclude = defaultExclude }: Props = {}) => {
const result = unflatten(flat);
return result;
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[exclude, localVariables, variables?.parseVariable],
);