From be4ae42376ce98e69c9bcc89fa031ae2ef8a4ed7 Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Wed, 14 Aug 2024 09:33:32 +0800 Subject: [PATCH] fix(inherit): fix 'Add new' button for inherited collectons (#5049) * fix(inherit): fix 'Add new' button for inherited collectons * test: add e2e test --- .../src/data-source/collection/Collection.ts | 2 +- .../actions/add-new/__e2e__/inherit.test.ts | 47 +++ .../actions/add-new/__e2e__/templates.ts | 273 ++++++++++++++++++ .../schema-component/antd/page/PagePopups.tsx | 2 +- .../antd/page/pagePopupUtils.tsx | 19 +- .../components/CreateRecordAction.tsx | 17 +- 6 files changed, 352 insertions(+), 8 deletions(-) create mode 100644 packages/core/client/src/modules/actions/add-new/__e2e__/inherit.test.ts create mode 100644 packages/core/client/src/modules/actions/add-new/__e2e__/templates.ts diff --git a/packages/core/client/src/data-source/collection/Collection.ts b/packages/core/client/src/data-source/collection/Collection.ts index a3f9263224..977a6769c2 100644 --- a/packages/core/client/src/data-source/collection/Collection.ts +++ b/packages/core/client/src/data-source/collection/Collection.ts @@ -299,7 +299,7 @@ export class Collection { } /** - * is inherited from other collection + * is inherited from other collections * @returns boolean */ isInherited() { diff --git a/packages/core/client/src/modules/actions/add-new/__e2e__/inherit.test.ts b/packages/core/client/src/modules/actions/add-new/__e2e__/inherit.test.ts new file mode 100644 index 0000000000..ec3a21997a --- /dev/null +++ b/packages/core/client/src/modules/actions/add-new/__e2e__/inherit.test.ts @@ -0,0 +1,47 @@ +/** + * 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 { T5084 } from './templates'; + +test.describe('Add new: inherit', () => { + test('creating block by child collection should work correctly', async ({ page, mockPage }) => { + await mockPage(T5084).goto(); + + // 1. click the "Add new" button, and then create a block, the block's collection should be "parent" + await page.getByRole('button', { name: 'plus Add new' }).click(); + await page.getByLabel('schema-initializer-Grid-popup').hover(); + await page.getByRole('menuitem', { name: 'form Form right' }).hover(); + await page.getByRole('menuitem', { name: 'Current collection' }).click(); + await page.getByLabel('block-item-CardItem-parent-form').hover(); + await expect(page.getByLabel('block-item-CardItem-parent-form').getByText('parent')).toBeVisible(); + // close popup + await page.getByLabel('drawer-Action.Container-parent-Add record-mask').click(); + + // 2. click the "child1" option, and then create a block, the block's collection should be "child1" + await page.getByRole('button', { name: 'down' }).hover(); + await page.getByRole('menuitem', { name: 'child1' }).click(); + await page.getByLabel('schema-initializer-Grid-popup').hover(); + await page.getByRole('menuitem', { name: 'form Form right' }).hover(); + await page.getByRole('menuitem', { name: 'Current collection' }).click(); + await page.getByLabel('block-item-CardItem-child1-').hover(); + await expect(page.getByLabel('block-item-CardItem-child1-').getByText('child1')).toBeVisible(); + // close popup + await page.getByLabel('drawer-Action.Container-child1-Add record-mask').click(); + + // 3. click the "child2" option, and then create a block, the block's collection should be "child2" + await page.getByRole('button', { name: 'down' }).hover(); + await page.getByRole('menuitem', { name: 'child2' }).click(); + await page.getByLabel('schema-initializer-Grid-popup').hover(); + await page.getByRole('menuitem', { name: 'form Form right' }).hover(); + await page.getByRole('menuitem', { name: 'Current collection' }).click(); + await page.getByLabel('block-item-CardItem-child2-').hover(); + await expect(page.getByLabel('block-item-CardItem-child2-').getByText('child2')).toBeVisible(); + }); +}); diff --git a/packages/core/client/src/modules/actions/add-new/__e2e__/templates.ts b/packages/core/client/src/modules/actions/add-new/__e2e__/templates.ts new file mode 100644 index 0000000000..b5bc27f935 --- /dev/null +++ b/packages/core/client/src/modules/actions/add-new/__e2e__/templates.ts @@ -0,0 +1,273 @@ +/** + * 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. + */ + +export const T5084 = { + collections: [ + { + name: 'parent', + }, + { + name: 'child1', + inherits: ['parent'], + }, + { + name: 'child2', + inherits: ['parent'], + }, + ], + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + '9z728grhuw5': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'page:addBlock', + properties: { + qunhcwzgdrq: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.3.0-alpha', + properties: { + '232zkncxw1p': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.3.0-alpha', + properties: { + hj5wtj01v9m: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'parent:list', + 'x-use-decorator-props': 'useTableBlockDecoratorProps', + 'x-decorator-props': { + collection: 'parent', + 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.3.0-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.3.0-alpha', + properties: { + uqw9g1a6bx2: { + 'x-uid': 'atwcb9plntt', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-action': 'create', + 'x-acl-action': 'create', + title: "{{t('Add new')}}", + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:addNew', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-component-props': { + openMode: 'drawer', + type: 'primary', + component: 'CreateRecordAction', + icon: 'PlusOutlined', + }, + 'x-action-context': { + dataSource: 'main', + collection: 'parent', + }, + 'x-align': 'right', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-app-version': '1.3.0-alpha', + 'x-enable-children': [ + { + collection: 'child1', + }, + { + collection: 'child2', + }, + ], + 'x-allow-add-to-current': true, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Add record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + 'x-app-version': '1.3.0-alpha', + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'popup:addTab', + 'x-initializer-props': { + gridInitializer: 'popup:addNew:addBlock', + }, + 'x-app-version': '1.3.0-alpha', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Add new")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + 'x-app-version': '1.3.0-alpha', + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'popup:addNew:addBlock', + 'x-app-version': '1.3.0-alpha', + 'x-uid': '9b9jmnkn2f5', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'flmsg97ib9h', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xd5niej584x', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nlmwpvv9vd3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'v0oc2ik3mqw', + 'x-async': false, + 'x-index': 1, + }, + jecm8jee085: { + _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.3.0-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.3.0-alpha', + properties: { + '4f5sce3w9fx': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-app-version': '1.3.0-alpha', + 'x-uid': 'qtr5an6qbu6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r8msyk257y9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'm2m7kgypy5z', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'g0mdajxejhl', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r7uvf8c2gdq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fr8e99uwlgl', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'awqpmazhs8a', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'st43un0l7kl', + 'x-async': true, + 'x-index': 1, + }, +}; diff --git a/packages/core/client/src/schema-component/antd/page/PagePopups.tsx b/packages/core/client/src/schema-component/antd/page/PagePopups.tsx index 3bcd678fbc..0f850d0c39 100644 --- a/packages/core/client/src/schema-component/antd/page/PagePopups.tsx +++ b/packages/core/client/src/schema-component/antd/page/PagePopups.tsx @@ -155,7 +155,7 @@ const PagePopupsItemProvider: FC<{ { }); export const getPopupPathFromParams = (params: PopupParams) => { - const { popupuid: popupUid, tab, filterbytk, sourceid } = params; + const { popupuid: popupUid, tab, filterbytk, sourceid, collection } = params; const popupPath = [ popupUid, + collection && 'collection', + collection, filterbytk && 'filterbytk', filterbytk, sourceid && 'sourceid', @@ -148,15 +152,18 @@ export const usePagePopup = () => { popupUid, recordData, sourceId, + collection: _collection, }: { popupUid: string; recordData: Record; sourceId: string; tabKey?: string; + collection?: string; }) => { const filterByTK = cm.getFilterByTK(association || collection, recordData); return getPopupPathFromParams({ popupuid: popupUid, + collection: _collection, filterbytk: filterByTK, sourceid: sourceId, tab: tabKey, @@ -179,9 +186,12 @@ export const usePagePopup = () => { ({ recordData, parentRecordData, + collectionNameUsedInURL, }: { recordData?: Record; parentRecordData?: Record; + /** if this value exists, it will be saved in the URL */ + collectionNameUsedInURL?: string; } = {}) => { if (!isPopupVisibleControlledByURL()) { return setVisibleFromAction?.(true); @@ -190,7 +200,12 @@ export const usePagePopup = () => { const sourceId = getSourceId(parentRecordData); recordData = recordData || record?.data; - const pathname = getNewPathname({ popupUid: currentPopupUidWithoutOpened, recordData, sourceId }); + const pathname = getNewPathname({ + popupUid: currentPopupUidWithoutOpened, + recordData, + sourceId, + collection: collectionNameUsedInURL, + }); let url = location.pathname; if (_.last(url) === '/') { url = url.slice(0, -1); diff --git a/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx b/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx index c3e2d3e5b1..5631ddeb9d 100644 --- a/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx +++ b/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx @@ -12,7 +12,7 @@ import { observer, useField, useFieldSchema, useForm } from '@formily/react'; import { Button, Dropdown, MenuProps } from 'antd'; import { composeRef } from 'rc-util/lib/ref'; import React, { createRef, forwardRef, useEffect, useMemo } from 'react'; -import { Collection, useDesignable } from '../../'; +import { Collection, useCollectionManager, useDesignable } from '../../'; import { useACLActionParamsContext, useACLRolesCheck, useRecordPkValue } from '../../acl/ACLProvider'; import { useCollectionManager_deprecated, useCollection_deprecated } from '../../collection-manager'; import { useTreeParentRecord } from '../../modules/blocks/data-blocks/table/TreeRecordProvider'; @@ -65,7 +65,6 @@ function useAclCheckFn() { const InternalCreateRecordAction = (props: any, ref) => { const fieldSchema = useFieldSchema(); - const openMode = fieldSchema?.['x-component-props']?.['openMode']; const field: any = useField(); const linkageRules: any[] = fieldSchema?.['x-linkage-rules'] || []; const values = useRecord(); @@ -73,6 +72,7 @@ const InternalCreateRecordAction = (props: any, ref) => { const localVariables = useLocalVariables({ currentForm: { values } as any }); const { openPopup } = usePagePopup(); const treeRecordData = useTreeParentRecord(); + const cm = useCollectionManager(); useEffect(() => { field.stateOfLinkageRules = {}; @@ -98,13 +98,22 @@ const InternalCreateRecordAction = (props: any, ref) => {
}> { + onClick={(collection: Partial) => { + collection = cm.getCollection(collection.name) || collection; + if (treeRecordData) { openPopup({ recordData: treeRecordData, }); } else { - openPopup(); + // fix https://nocobase.height.app/T-5084/description + if (collection.isInherited?.()) { + openPopup({ + collectionNameUsedInURL: collection.name, + }); + } else { + openPopup(); + } } }} />