diff --git a/packages/core/client/src/block-provider/FormBlockProvider.tsx b/packages/core/client/src/block-provider/FormBlockProvider.tsx index 7122b27c17..5e9bb38578 100644 --- a/packages/core/client/src/block-provider/FormBlockProvider.tsx +++ b/packages/core/client/src/block-provider/FormBlockProvider.tsx @@ -98,7 +98,7 @@ export const useIsDetailBlock = () => { export const FormBlockProvider = withDynamicSchemaProps((props) => { const record = useRecord(); const parentRecordData = useCollectionParentRecordData(); - const { collection, isCusomeizeCreate } = props; + const { collection, isCusomeizeCreate, parentRecord } = props; const { __collection } = record; const currentCollection = useCollection_deprecated(); const { designable } = useDesignable(); @@ -120,7 +120,12 @@ export const FormBlockProvider = withDynamicSchemaProps((props) => { return ( - + diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/associationForm.test.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/associationForm.test.ts index f7ce94f736..9fb0298743 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/associationForm.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/associationForm.test.ts @@ -1,5 +1,5 @@ -import { test, expect } from '@nocobase/test/e2e'; -import { T3529 } from './templatesOfBug'; +import { deleteRecords, expect, test } from '@nocobase/test/e2e'; +import { T3529, T3953 } from './templatesOfBug'; test.describe('association form block', () => { // https://nocobase.height.app/T-3529 @@ -18,4 +18,20 @@ test.describe('association form block', () => { // 应该有包含 :create 的请求 expect(request).toBeTruthy(); }); + + // https://nocobase.height.app/T-3953/description + test('form (Add new)', async ({ page, mockPage }) => { + await mockPage(T3953).goto(); + + // 1. 打开弹窗,填写表单 + await page.getByLabel('action-Action.Link-View-view-').click(); + await page.getByLabel('block-item-CollectionField-').getByRole('textbox').fill('1234'); + await page.getByLabel('action-Action-Submit-submit-').click(); + + // 2. 提交后,Table 会显示新增的数据 + await expect(page.getByLabel('block-item-CardItem-users-').getByText('1234')).toBeVisible(); + + // 3. 将创建的 roles record 删除,防止影响其他测试 + await deleteRecords('roles', { name: { $ne: ['root', 'admin', 'member'] } }); + }); }); diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/templatesOfBug.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/templatesOfBug.ts index ae90074438..bfc8b3ea93 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/templatesOfBug.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/templatesOfBug.ts @@ -7190,3 +7190,426 @@ export const T3871 = { 'x-index': 1, }, }; +export const T3953 = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + 'x-app-version': '0.21.0-alpha.6', + properties: { + n666dtj6omu: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'page:addBlock', + 'x-app-version': '0.21.0-alpha.6', + properties: { + '9z4u9212i9d': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '0.21.0-alpha.6', + properties: { + syjj7mksnk1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '0.21.0-alpha.6', + properties: { + lv2u3j85fue: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-use-decorator-props': 'useTableBlockDecoratorProps', + 'x-decorator-props': { + collection: 'users', + 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': '0.21.0-alpha.6', + 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': '0.21.0-alpha.6', + 'x-uid': '9y1rpremah0', + 'x-async': false, + 'x-index': 1, + }, + wrg1doc2s25: { + _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': '0.21.0-alpha.6', + 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-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'table:configureItemActions', + 'x-app-version': '0.21.0-alpha.6', + properties: { + li0jrjj5xzd: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-app-version': '0.21.0-alpha.6', + properties: { + lw1i9nvgj69: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View") }}', + 'x-action': 'view', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:view', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'popup:addTab', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'popup:common:addBlock', + properties: { + whxl1gjy2i1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '0.21.0-alpha.6', + properties: { + ngbr0vzmply: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '0.21.0-alpha.6', + properties: { + muushivmktf: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'users.roles:create', + 'x-decorator': 'FormBlockProvider', + 'x-use-decorator-props': + 'useCreateFormBlockDecoratorProps', + 'x-decorator-props': { + dataSource: 'main', + association: 'users.roles', + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:createForm', + 'x-component': 'CardItem', + 'x-app-version': '0.21.0-alpha.6', + properties: { + '4q1wobzy33u': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useCreateFormBlockProps', + 'x-app-version': '0.21.0-alpha.6', + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'form:configureFields', + 'x-app-version': '0.21.0-alpha.6', + properties: { + v84lrgs188k: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '0.21.0-alpha.6', + properties: { + '75qkhwgryu3': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '0.21.0-alpha.6', + properties: { + title: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'roles.title', + 'x-component-props': {}, + 'x-app-version': '0.21.0-alpha.6', + 'x-uid': 'mrh2r6j0oy1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fuzhfebdlft', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5e9kmlywtpu', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'abmijedxpmw', + 'x-async': false, + 'x-index': 1, + }, + '5aqhq3fck0w': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'createForm:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-app-version': '0.21.0-alpha.6', + properties: { + pji7mkqbg5w: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-use-component-props': + 'useCreateActionProps', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:createSubmit', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + }, + 'x-action-settings': { + triggerWorkflows: [], + }, + type: 'void', + 'x-app-version': '0.21.0-alpha.6', + 'x-uid': 'ehlamh5jond', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xpv3riybuuw', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '46usos5j9c6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'cdr83eb368w', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'bw993qtjlrz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'tipccl4y5b8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'x9xofyyfeso', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'mcucnbxpx76', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3208vu2vv5j', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'tdpo6b5f0n8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'e3fqdkzfvy3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rnttf38vdco', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'naezr8t9rd6', + 'x-async': false, + 'x-index': 1, + }, + wz4sx2in3zm: { + _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': '0.21.0-alpha.6', + properties: { + roles: { + 'x-uid': 'l1i2ebbn5yp', + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'users.roles', + 'x-component': 'CollectionField', + 'x-component-props': { + fieldNames: { + label: 'title', + value: 'name', + }, + ellipsis: true, + size: 'small', + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-app-version': '0.21.0-alpha.6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r1ag1f5w96p', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'oofh9gz63w5', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '0ih4jhp49gd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5ubrq8koffa', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'dfnkmkw8u24', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5979mzb49da', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fm798ucrett', + 'x-async': true, + 'x-index': 1, + }, +}; diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaInitializer.test.ts b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaInitializer.test.ts index f3c7dfd705..b733601989 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaInitializer.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaInitializer.test.ts @@ -161,7 +161,12 @@ test.describe('configure columns', () => { // 点击开关,删除创建的字段 await configureColumnButton.hover(); - await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click({ + position: { + x: 30, + y: 10, + }, + }); await page.getByRole('menuitem', { name: 'One to one (belongs to)' }).first().click(); await page.getByRole('menuitem', { name: 'One to one (has one)' }).first().click(); await page.getByRole('menuitem', { name: 'Many to one' }).first().click(); diff --git a/packages/core/test/src/e2e/e2eUtils.ts b/packages/core/test/src/e2e/e2eUtils.ts index 9fdcde002f..faf5a85649 100644 --- a/packages/core/test/src/e2e/e2eUtils.ts +++ b/packages/core/test/src/e2e/e2eUtils.ts @@ -344,6 +344,8 @@ const _test = base.extend({ await nocoPage.destroy(); await setDefaultRole('root'); } + // 删除掉 id 不是 1 的 users 和 name 不是 root admin member 的 roles + await removeRedundantUserAndRoles(); }, mockManualDestroyPage: async ({ browser }, use) => { const mockManualDestroyPage = (config?: PageConfig) => { @@ -414,13 +416,6 @@ const _test = base.extend({ }; await use(mockRecords); - - // 删除掉 id 不是 1 的 users 和 name 不是 root admin member 的 roles - const deletePromises = [ - deleteRecords('users', { id: { $ne: 1 } }), - deleteRecords('roles', { name: { $ne: ['root', 'admin', 'member'] } }), - ]; - await Promise.all(deletePromises); }, mockRecord: async ({ page }, use) => { const mockRecord = async (collectionName: string, data?: any) => { @@ -429,13 +424,6 @@ const _test = base.extend({ }; await use(mockRecord); - - // 删除掉 id 不是 1 的 users 和 name 不是 root admin member 的 roles - const deletePromises = [ - deleteRecords('users', { id: { $ne: 1 } }), - deleteRecords('roles', { name: { $ne: ['root', 'admin', 'member'] } }), - ]; - await Promise.all(deletePromises); }, deletePage: async ({ page }, use) => { const deletePage = async (pageName: string) => { @@ -446,13 +434,6 @@ const _test = base.extend({ }; await use(deletePage); - - // 删除掉 id 不是 1 的 users 和 name 不是 root admin member 的 roles - const deletePromises = [ - deleteRecords('users', { id: { $ne: 1 } }), - deleteRecords('roles', { name: { $ne: ['root', 'admin', 'member'] } }), - ]; - await Promise.all(deletePromises); }, mockRole: async ({ page }, use) => { const mockRole = async (roleSetting: AclRoleSetting) => { @@ -668,7 +649,7 @@ const deleteCollections = async (collectionNames: string[]) => { * @param collectionName * @param records */ -const deleteRecords = async (collectionName: string, filter: any) => { +export const deleteRecords = async (collectionName: string, filter: any) => { const api = await request.newContext({ storageState: process.env.PLAYWRIGHT_AUTH_FILE, }); @@ -900,6 +881,15 @@ const createRandomData = async (collectionName: string, count = 10, data?: any) return (await result.json()).data; }; +// 删除掉 id 不是 1 的 users 和 name 不是 root admin member 的 roles +async function removeRedundantUserAndRoles() { + const deletePromises = [ + deleteRecords('users', { id: { $ne: 1 } }), + deleteRecords('roles', { name: { $ne: ['root', 'admin', 'member'] } }), + ]; + await Promise.all(deletePromises); +} + function getHeaders(storageState: any) { const headers: any = {}; const token = getStorageItem('NOCOBASE_TOKEN', storageState);