From f6cb299678e04ae06186bde8fe026241a626934f Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Sun, 11 Aug 2024 15:46:16 +0800 Subject: [PATCH] fix(Table): should not error when open a popup by clicking a multi-level field (#5038) --- .../__tests__/hooks/index.test.ts | 21 + .../client/src/block-provider/hooks/index.ts | 20 + .../__e2e__/displayAssociationFields.test.ts | 27 ++ .../table/__e2e__/templatesOfBug.ts | 401 ++++++++++++++++++ 4 files changed, 469 insertions(+) create mode 100644 packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/displayAssociationFields.test.ts diff --git a/packages/core/client/src/block-provider/__tests__/hooks/index.test.ts b/packages/core/client/src/block-provider/__tests__/hooks/index.test.ts index 574503de3c1..7500de347d3 100644 --- a/packages/core/client/src/block-provider/__tests__/hooks/index.test.ts +++ b/packages/core/client/src/block-provider/__tests__/hooks/index.test.ts @@ -10,6 +10,7 @@ import { appendQueryStringToUrl, completeURL, + fillParentFields, navigateWithinSelf, parseVariablesAndChangeParamsToQueryString, reduceValueSize, @@ -235,3 +236,23 @@ describe('navigateWithinSelf', () => { expect(console.error).toHaveBeenCalledWith('link should be a string'); }); }); + +describe('fillParentFields', () => { + it('should fill parent fields for multi-level fields', () => { + const appends = new Set(['a', 'b.c']); + const result = fillParentFields(appends); + expect(result).toEqual(new Set(['a', 'b', 'b.c'])); + }); + + it('[a, b.c.d] -> [a, b.c, b.c.d]', () => { + const appends = new Set(['a', 'b.c.d']); + const result = fillParentFields(appends); + expect(result).toEqual(new Set(['a', 'b.c', 'b.c.d'])); + }); + + it('should not modify the set if there are no multi-level fields', () => { + const appends = new Set(['a', 'b', 'c']); + const result = fillParentFields(appends); + expect(result).toEqual(new Set(['a', 'b', 'c'])); + }); +}); diff --git a/packages/core/client/src/block-provider/hooks/index.ts b/packages/core/client/src/block-provider/hooks/index.ts index b0a45a50f2b..402dd83cde5 100644 --- a/packages/core/client/src/block-provider/hooks/index.ts +++ b/packages/core/client/src/block-provider/hooks/index.ts @@ -1474,6 +1474,7 @@ export const useAssociationNames = (dataSource?: string) => { updateAssociationValues = new Set([]); appends = new Set([]); _getAssociationAppends(fieldSchema, ''); + appends = fillParentFields(appends); return { appends: [...appends], updateAssociationValues: [...updateAssociationValues] }; }; @@ -1705,3 +1706,22 @@ export function navigateWithinSelf(link: string, navigate: NavigateFunction, ori navigate(link.startsWith('/') ? link : `/${link}`); } } + +/** + * 为多层级的关系字段补充上父级字段 + * e.g. ['a', 'b.c'] => ['a', 'b', 'b.c'] + * @param appends + * @returns + */ +export function fillParentFields(appends: Set) { + const depFields = Array.from(appends).filter((field) => field.includes('.')); + + depFields.forEach((field) => { + const fields = field.split('.'); + fields.pop(); + const parentField = fields.join('.'); + appends.add(parentField); + }); + + return appends; +} diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/displayAssociationFields.test.ts b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/displayAssociationFields.test.ts new file mode 100644 index 00000000000..7e8f07c5714 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/displayAssociationFields.test.ts @@ -0,0 +1,27 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +import { expect, test } from '@nocobase/test/e2e'; +import { T4942 } from './templatesOfBug'; + +test.describe('Configure columns - Display association fields', () => { + // https://nocobase.height.app/T-4942/description + test('should not error when open a popup by clicking a multi-level field', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(T4942).waitForInit(); + + const record = await mockRecord('collection1', 2); + + await nocoPage.goto(); + + await page.getByRole('button', { name: record.manyToOne1.manyToOne2.id, exact: true }).locator('a').click(); + await expect(page.getByLabel('block-item-CollectionField-')).toHaveText( + `field1:${record.manyToOne1.manyToOne2.field1}`, + ); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/templatesOfBug.ts index 318c65ae366..939beb3dbe2 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/templatesOfBug.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/templatesOfBug.ts @@ -4611,3 +4611,404 @@ export const ordinaryBlockTemplatesCannotBeUsedToCreateAssociationBlocksAndViceV 'x-async': true, }, }; + +export const T4942 = { + collections: [ + { + name: 'collection1', + fields: [ + { + interface: 'm2o', + name: 'manyToOne1', + target: 'collection2', + }, + ], + }, + { + name: 'collection2', + fields: [ + { + interface: 'm2o', + name: 'manyToOne2', + target: 'collection3', + }, + ], + }, + { + name: 'collection3', + fields: [{ interface: 'input', name: 'field1' }], + }, + ], + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + gietupulya5: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'page:addBlock', + properties: { + gyp6czp73wk: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.2.34-alpha', + properties: { + '1ajolx72bp5': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.2.34-alpha', + properties: { + wgwjrzpjb46: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'collection1:list', + 'x-use-decorator-props': 'useTableBlockDecoratorProps', + 'x-decorator-props': { + collection: 'collection1', + dataSource: 'main', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:table', + 'x-component': 'CardItem', + 'x-filter-targets': [], + 'x-app-version': '1.2.34-alpha', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'table:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-app-version': '1.2.34-alpha', + 'x-uid': 'vt14g7yqceq', + 'x-async': false, + 'x-index': 1, + }, + '4g4v3tfs2ml': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'table:configureColumns', + 'x-component': 'TableV2', + 'x-use-component-props': 'useTableBlockProps', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + }, + 'x-app-version': '1.2.34-alpha', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-toolbar': 'TableColumnSchemaToolbar', + 'x-initializer': 'table:configureItemActions', + 'x-settings': 'fieldSettings:TableColumn', + 'x-toolbar-props': { + initializer: 'table:configureItemActions', + }, + 'x-app-version': '1.2.34-alpha', + properties: { + c9kah38ersq: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-app-version': '1.2.34-alpha', + 'x-uid': 'mjg0y0l542i', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qltvfj6o636', + 'x-async': false, + 'x-index': 1, + }, + q89848gjz6w: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-toolbar': 'TableColumnSchemaToolbar', + 'x-settings': 'fieldSettings:TableColumn', + 'x-component': 'TableV2.Column', + 'x-app-version': '1.2.34-alpha', + properties: { + 'manyToOne1.manyToOne2': { + _isJSONSchemaObject: true, + version: '2.0', + 'x-component': 'CollectionField', + 'x-read-pretty': true, + 'x-collection-field': 'collection1.manyToOne1.manyToOne2', + 'x-component-props': { + fieldNames: { + value: 'id', + label: 'id', + }, + ellipsis: true, + size: 'small', + }, + 'x-app-version': '1.2.34-alpha', + properties: { + '5j1v2ecmxni': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'AssociationField.Viewer', + 'x-component-props': { + className: 'nb-action-popup', + }, + 'x-index': 1, + 'x-app-version': '1.2.34-alpha', + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'popup:addTab', + 'x-app-version': '1.2.34-alpha', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + 'x-app-version': '1.2.34-alpha', + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'popup:common:addBlock', + 'x-app-version': '1.2.34-alpha', + properties: { + s0p3nt7zhyw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.2.34-alpha', + properties: { + gf3b29ty19n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.2.34-alpha', + properties: { + u8jzln7uovy: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action': 'collection2.manyToOne2:get', + 'x-decorator': 'DetailsBlockProvider', + 'x-use-decorator-props': 'useDetailsDecoratorProps', + 'x-decorator-props': { + dataSource: 'main', + association: 'collection2.manyToOne2', + readPretty: true, + action: 'get', + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:details', + 'x-component': 'CardItem', + 'x-is-current': true, + 'x-app-version': '1.2.34-alpha', + properties: { + '3zqugaam6ef': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Details', + 'x-read-pretty': true, + 'x-use-component-props': 'useDetailsProps', + 'x-app-version': '1.2.34-alpha', + properties: { + zviz7m97b07: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'details:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + 'x-app-version': '1.2.34-alpha', + 'x-uid': 'nkqso1gzv6p', + 'x-async': false, + 'x-index': 1, + }, + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'details:configureFields', + 'x-app-version': '1.2.34-alpha', + properties: { + '36mth0l7n2v': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.2.34-alpha', + properties: { + zpykwlwos9l: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.2.34-alpha', + properties: { + field1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'collection3.field1', + 'x-component-props': {}, + 'x-app-version': '1.2.34-alpha', + 'x-uid': 'gboyi91blj1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xqrhqfr6e8q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'v0uyq6az6fb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '14xzvjcg5hq', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'k0ipmlnr0lo', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'h3mag8s3uet', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'p19iz8ia0my', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'halz5ecr26k', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lnpz1z5fd0h', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'gli9nxpltqb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'bvhk6mb3zar', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qk4acu33rbi', + 'x-async': false, + }, + }, + 'x-uid': 'mm8y0ky3qaz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6iep94y4qgb', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'l6c1rntmsly', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'u0o05lk778c', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lki6ivvlzs2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nd5k4x2fn3a', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qe16f8am538', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'jlc3g38jakh', + 'x-async': true, + 'x-index': 1, + }, +};