mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-01 18:52:20 +08:00
fix(dataScope): fix issue with nested association field variables (#5866)
This commit is contained in:
parent
f9afb13cee
commit
d5ac3eee04
@ -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;
|
||||
},
|
||||
});
|
||||
|
@ -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')
|
||||
|
@ -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();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
@ -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],
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user