mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-02 03:02:19 +08:00
fix: refresh issues (#5838)
* fix(associationField): fix the issue where the configuration popup does not show when reopened * test: add e2e test * refactor: extract template code * chore(e2e): fix e2e error
This commit is contained in:
parent
3a2abcb9a3
commit
3140edf798
@ -86,5 +86,6 @@ export {
|
|||||||
CollectionFieldUISchemaProvider,
|
CollectionFieldUISchemaProvider,
|
||||||
IsInNocoBaseRecursionFieldContext,
|
IsInNocoBaseRecursionFieldContext,
|
||||||
NocoBaseRecursionField,
|
NocoBaseRecursionField,
|
||||||
|
RefreshComponentProvider,
|
||||||
useRefreshFieldSchema,
|
useRefreshFieldSchema,
|
||||||
} from './formily/NocoBaseRecursionField';
|
} from './formily/NocoBaseRecursionField';
|
||||||
|
@ -141,6 +141,7 @@ test.describe('configure actions', () => {
|
|||||||
await expect(
|
await expect(
|
||||||
page.getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname').getByRole('textbox'),
|
page.getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname').getByRole('textbox'),
|
||||||
).toBeHidden();
|
).toBeHidden();
|
||||||
|
await page.mouse.move(600, 0);
|
||||||
|
|
||||||
// 再次点击添加按钮,默认值应该正常显示出来
|
// 再次点击添加按钮,默认值应该正常显示出来
|
||||||
await page.locator('.nb-sub-table-addNew').click();
|
await page.locator('.nb-sub-table-addNew').click();
|
||||||
|
@ -8,7 +8,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { expect, test } from '@nocobase/test/e2e';
|
import { expect, test } from '@nocobase/test/e2e';
|
||||||
import { differentURL_DifferentPopupContent } from './templatesOfBug';
|
import {
|
||||||
|
differentURL_DifferentPopupContent,
|
||||||
|
popupConfigurationShouldPersistAcrossDifferentRowsInTheSameColumn,
|
||||||
|
} from './templatesOfBug';
|
||||||
|
|
||||||
test.describe('popup opened by clicking the association field', async () => {
|
test.describe('popup opened by clicking the association field', async () => {
|
||||||
test('different URL, different popup content', async ({ page, mockPage, mockRecord }) => {
|
test('different URL, different popup content', async ({ page, mockPage, mockRecord }) => {
|
||||||
@ -28,4 +31,91 @@ test.describe('popup opened by clicking the association field', async () => {
|
|||||||
await page.goto(prevURL);
|
await page.goto(prevURL);
|
||||||
await expect(page.getByLabel('block-item-CollectionField-')).toHaveText('Role name:Admin');
|
await expect(page.getByLabel('block-item-CollectionField-')).toHaveText('Role name:Admin');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('popup configuration should persist across different rows in the same column', async ({
|
||||||
|
page,
|
||||||
|
mockPage,
|
||||||
|
mockRecord,
|
||||||
|
}) => {
|
||||||
|
const nocoPage = await mockPage(popupConfigurationShouldPersistAcrossDifferentRowsInTheSameColumn).waitForInit();
|
||||||
|
await mockRecord('users', { roles: [{ name: 'member', title: 'Member' }], nickname: 'test popup' });
|
||||||
|
await nocoPage.goto();
|
||||||
|
|
||||||
|
// 1. 新建一个 View 按钮
|
||||||
|
await page.getByRole('button', { name: 'Actions', exact: true }).hover();
|
||||||
|
await page.getByLabel('designer-schema-initializer-TableV2.Column-fieldSettings:TableColumn-users').hover();
|
||||||
|
await page.getByRole('menuitem', { name: 'View' }).click();
|
||||||
|
|
||||||
|
// 2. 点击第一行的 View 按钮,打开弹窗,然后增加一个 Markdown 区块
|
||||||
|
await page.getByLabel('action-Action.Link-View-view-users-table-0').click();
|
||||||
|
await page.getByLabel('schema-initializer-Grid-popup').hover();
|
||||||
|
await page.getByRole('menuitem', { name: 'form Markdown' }).click();
|
||||||
|
await expect(page.getByLabel('block-item-Markdown.Void-')).toBeVisible();
|
||||||
|
|
||||||
|
// 3. 关闭弹窗,然后点击第二行的 View 按钮,打开弹窗,弹窗中的 Markdown 区块应该和第一行的一样
|
||||||
|
await page.getByLabel('drawer-Action.Container-users-View record-mask').click();
|
||||||
|
await page.getByLabel('action-Action.Link-View-view-users-table-1').click();
|
||||||
|
await expect(page.getByLabel('block-item-Markdown.Void-')).toBeVisible();
|
||||||
|
|
||||||
|
// 4. 关闭弹窗,然后再点击第一行的 View 按钮,打开弹窗,弹窗中的 Markdown 区块依然存在
|
||||||
|
await page.getByLabel('drawer-Action.Container-users-View record-mask').click();
|
||||||
|
await page.getByLabel('action-Action.Link-View-view-users-table-0').click();
|
||||||
|
await expect(page.getByLabel('block-item-Markdown.Void-')).toBeVisible();
|
||||||
|
await page.getByLabel('drawer-Action.Container-users-View record-mask').click();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// 1. 新建一个关系字段(Roles)
|
||||||
|
await page.getByLabel('schema-initializer-TableV2-').hover();
|
||||||
|
await page.getByRole('menuitem', { name: 'Roles' }).click();
|
||||||
|
await page.mouse.move(300, 0);
|
||||||
|
|
||||||
|
// 2. 点击第一行的 Roles 字段,打开弹窗,然后增加一个 Markdown 区块
|
||||||
|
await page.getByText('root').click();
|
||||||
|
await page.getByLabel('schema-initializer-Grid-popup').click();
|
||||||
|
await page.getByRole('menuitem', { name: 'form Markdown' }).click();
|
||||||
|
await expect(page.getByLabel('block-item-Markdown.Void-')).toBeVisible();
|
||||||
|
|
||||||
|
// 3. 关闭弹窗,然后点击第二行的 Roles 字段,打开弹窗,弹窗中的 Markdown 区块应该和第一行的一样
|
||||||
|
await page.getByLabel('drawer-AssociationField.Viewer-roles-View record-mask').click();
|
||||||
|
await page.getByText('member').nth(1).click();
|
||||||
|
await expect(page.getByLabel('block-item-Markdown.Void-')).toBeVisible();
|
||||||
|
|
||||||
|
// 4. 关闭弹窗,然后再点击第一行的 Roles 字段,打开弹窗,弹窗中的 Markdown 区块依然存在
|
||||||
|
await page.getByLabel('drawer-AssociationField.Viewer-roles-View record-mask').click();
|
||||||
|
await page.getByText('root').click();
|
||||||
|
await expect(page.getByLabel('block-item-Markdown.Void-')).toBeVisible();
|
||||||
|
await page.getByLabel('drawer-AssociationField.Viewer-roles-View record-mask').click();
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// 1. 新建一个单行文本字段(nickname),并开启 Enable link
|
||||||
|
await page.getByLabel('schema-initializer-TableV2-').hover();
|
||||||
|
await page.getByRole('menuitem', { name: 'Nickname' }).click();
|
||||||
|
await page.mouse.move(300, 0);
|
||||||
|
// 开启 Enable link
|
||||||
|
await page.getByRole('button', { name: 'Nickname' }).hover();
|
||||||
|
await page
|
||||||
|
.getByRole('button', { name: 'designer-schema-settings-TableV2.Column-fieldSettings:TableColumn-users' })
|
||||||
|
.hover();
|
||||||
|
await page.getByRole('menuitem', { name: 'Enable link' }).click();
|
||||||
|
await page.mouse.move(300, 0);
|
||||||
|
|
||||||
|
// 2. 点击第一行的 nickname 字段,打开弹窗,然后增加一个 Markdown 区块
|
||||||
|
await page.getByRole('button', { name: 'Super Admin' }).locator('a').click();
|
||||||
|
await page.getByLabel('schema-initializer-Grid-popup').click();
|
||||||
|
await page.getByRole('menuitem', { name: 'form Markdown' }).click();
|
||||||
|
await expect(page.getByLabel('block-item-Markdown.Void-')).toBeVisible();
|
||||||
|
|
||||||
|
// 3. 关闭弹窗,然后点击第二行的 nickname 字段,打开弹窗,弹窗中的 Markdown 区块应该和第一行的一样
|
||||||
|
await page.getByLabel('drawer-Action.Container-users-View record-mask').click();
|
||||||
|
await page.getByRole('button', { name: 'test popup' }).locator('a').click();
|
||||||
|
await expect(page.getByLabel('block-item-Markdown.Void-')).toBeVisible();
|
||||||
|
|
||||||
|
// 4. 关闭弹窗,然后再点击第一行的 nickname 字段,打开弹窗,弹窗中的 Markdown 区块依然存在
|
||||||
|
await page.getByLabel('drawer-Action.Container-users-View record-mask').click();
|
||||||
|
await page.getByRole('button', { name: 'Super Admin' }).locator('a').click();
|
||||||
|
await expect(page.getByLabel('block-item-Markdown.Void-')).toBeVisible();
|
||||||
|
await page.getByLabel('drawer-Action.Container-users-View record-mask').click();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -8682,3 +8682,152 @@ export const hideColumnBasic = {
|
|||||||
'x-index': 1,
|
'x-index': 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export const popupConfigurationShouldPersistAcrossDifferentRowsInTheSameColumn = {
|
||||||
|
pageSchema: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Page',
|
||||||
|
properties: {
|
||||||
|
rccgypv911m: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'page:addBlock',
|
||||||
|
properties: {
|
||||||
|
githmw0vywe: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-app-version': '1.6.0-alpha.3',
|
||||||
|
properties: {
|
||||||
|
k76036oekiy: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-app-version': '1.6.0-alpha.3',
|
||||||
|
properties: {
|
||||||
|
w6wzrye5ub7: {
|
||||||
|
_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': '1.6.0-alpha.3',
|
||||||
|
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.6.0-alpha.3',
|
||||||
|
'x-uid': 'cr9fvkuyyq2',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
'4c9c8525dks': {
|
||||||
|
_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.6.0-alpha.3',
|
||||||
|
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.6.0-alpha.3',
|
||||||
|
properties: {
|
||||||
|
b0umb64pa7m: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'DndContext',
|
||||||
|
'x-component': 'Space',
|
||||||
|
'x-component-props': {
|
||||||
|
split: '|',
|
||||||
|
},
|
||||||
|
'x-app-version': '1.6.0-alpha.3',
|
||||||
|
'x-uid': 'uti3lm42fk5',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'r69a6dptvyb',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'v3yjph96rjs',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '6nuwmd062mf',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '4b9z6v33m91',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'wri4ylqnqw3',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '5e7ud75szwt',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '38mzn4lv8by',
|
||||||
|
'x-async': true,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -51,5 +51,6 @@ test.describe('tree table block schema settings', () => {
|
|||||||
|
|
||||||
async function showSettingsMenu(page: Page) {
|
async function showSettingsMenu(page: Page) {
|
||||||
await page.getByLabel('block-item-CardItem-treeCollection-table').hover();
|
await page.getByLabel('block-item-CardItem-treeCollection-table').hover();
|
||||||
await page.getByLabel('designer-schema-settings-CardItem-TableBlockDesigner-treeCollection').hover();
|
// hover 方法有时会失效,所以这里使用 click 方法。原因未知
|
||||||
|
await page.getByLabel('designer-schema-settings-CardItem-TableBlockDesigner-treeCollection').click();
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import { observer, useFieldSchema } from '@formily/react';
|
import { observer, useFieldSchema } from '@formily/react';
|
||||||
import { toArr } from '@formily/shared';
|
import { toArr } from '@formily/shared';
|
||||||
import React, { Fragment, useRef } from 'react';
|
import React, { Fragment, useCallback, useRef } from 'react';
|
||||||
import { useDesignable } from '../../';
|
import { useDesignable } from '../../';
|
||||||
import { useCollectionManager_deprecated } from '../../../collection-manager';
|
import { useCollectionManager_deprecated } from '../../../collection-manager';
|
||||||
import { useCollectionRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
|
import { useCollectionRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
|
||||||
@ -50,6 +50,13 @@ const ButtonTabList: React.FC<ButtonListProps> = observer(
|
|||||||
const isTreeCollection = targetCollection?.template === 'tree';
|
const isTreeCollection = targetCollection?.template === 'tree';
|
||||||
const { openPopup } = usePopupUtils();
|
const { openPopup } = usePopupUtils();
|
||||||
const recordData = useCollectionRecordData();
|
const recordData = useCollectionRecordData();
|
||||||
|
const needWaitForFieldSchemaUpdatedRef = useRef(false);
|
||||||
|
const fieldSchemaRef = useRef(fieldSchema);
|
||||||
|
fieldSchemaRef.current = fieldSchema;
|
||||||
|
|
||||||
|
const getCustomActionSchema = useCallback(() => {
|
||||||
|
return fieldSchemaRef.current;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const renderRecords = () =>
|
const renderRecords = () =>
|
||||||
toArr(props.value).map((record, index, arr) => {
|
toArr(props.value).map((record, index, arr) => {
|
||||||
@ -77,13 +84,28 @@ const ButtonTabList: React.FC<ButtonListProps> = observer(
|
|||||||
props.setBtnHover(true);
|
props.setBtnHover(true);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (designable) {
|
if (designable && !fieldSchema.properties) {
|
||||||
insertViewer(schema.Viewer);
|
insertViewer(schema.Viewer);
|
||||||
|
needWaitForFieldSchemaUpdatedRef.current = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needWaitForFieldSchemaUpdatedRef.current) {
|
||||||
|
// When first inserting, the fieldSchema instance will be updated to a new instance.
|
||||||
|
// We need to wait for the instance update before opening the popup to prevent configuration loss.
|
||||||
|
setTimeout(() => {
|
||||||
|
openPopup({
|
||||||
|
recordData: record,
|
||||||
|
parentRecordData: recordData,
|
||||||
|
customActionSchema: getCustomActionSchema(),
|
||||||
|
});
|
||||||
|
needWaitForFieldSchemaUpdatedRef.current = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
openPopup({
|
openPopup({
|
||||||
recordData: record,
|
recordData: record,
|
||||||
parentRecordData: recordData,
|
parentRecordData: recordData,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
ellipsisWithTooltipRef?.current?.setPopoverVisible(false);
|
ellipsisWithTooltipRef?.current?.setPopoverVisible(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
import { useField, useFieldSchema } from '@formily/react';
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
import { toArr } from '@formily/shared';
|
import { toArr } from '@formily/shared';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { FC, Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { FC, Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useDesignable } from '../../';
|
import { useDesignable } from '../../';
|
||||||
import { WithoutTableFieldResource } from '../../../block-provider';
|
import { WithoutTableFieldResource } from '../../../block-provider';
|
||||||
import { CollectionRecordProvider, useCollectionManager, useCollectionRecordData } from '../../../data-source';
|
import { CollectionRecordProvider, useCollectionManager, useCollectionRecordData } from '../../../data-source';
|
||||||
@ -86,6 +86,13 @@ const RenderRecord = React.memo(
|
|||||||
}) => {
|
}) => {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [result, setResult] = useState<React.ReactNode[]>([]);
|
const [result, setResult] = useState<React.ReactNode[]>([]);
|
||||||
|
const needWaitForFieldSchemaUpdatedRef = useRef(false);
|
||||||
|
const fieldSchemaRef = useRef(fieldSchema);
|
||||||
|
fieldSchemaRef.current = fieldSchema;
|
||||||
|
|
||||||
|
const getCustomActionSchema = useCallback(() => {
|
||||||
|
return fieldSchemaRef.current;
|
||||||
|
}, []);
|
||||||
|
|
||||||
// The map method here maybe quite time-consuming, especially in table blocks.
|
// The map method here maybe quite time-consuming, especially in table blocks.
|
||||||
// Therefore, we use an asynchronous approach to render the list,
|
// Therefore, we use an asynchronous approach to render the list,
|
||||||
@ -122,11 +129,23 @@ const RenderRecord = React.memo(
|
|||||||
setBtnHover(true);
|
setBtnHover(true);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (designable) {
|
if (designable && !fieldSchema.properties) {
|
||||||
insertViewer(schema.Viewer);
|
insertViewer(schema.Viewer);
|
||||||
|
needWaitForFieldSchemaUpdatedRef.current = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldSchema.properties) {
|
if (needWaitForFieldSchemaUpdatedRef.current) {
|
||||||
|
// When first inserting, the fieldSchema instance will be updated to a new instance.
|
||||||
|
// We need to wait for the instance update before opening the popup to prevent configuration loss.
|
||||||
|
setTimeout(() => {
|
||||||
|
openPopup({
|
||||||
|
recordData: record,
|
||||||
|
parentRecordData: recordData,
|
||||||
|
customActionSchema: getCustomActionSchema(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
needWaitForFieldSchemaUpdatedRef.current = false;
|
||||||
|
} else if (fieldSchema.properties) {
|
||||||
openPopup({
|
openPopup({
|
||||||
recordData: record,
|
recordData: record,
|
||||||
parentRecordData: recordData,
|
parentRecordData: recordData,
|
||||||
@ -164,6 +183,7 @@ const RenderRecord = React.memo(
|
|||||||
setBtnHover,
|
setBtnHover,
|
||||||
snapshot,
|
snapshot,
|
||||||
value,
|
value,
|
||||||
|
getCustomActionSchema,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
|
@ -226,6 +226,7 @@ const useTableColumns = (props: { showDel?: any; isSubTable?: boolean }, paginat
|
|||||||
width: columnHidden && !designable ? 0 : columnSchema['x-component-props']?.width || 100,
|
width: columnHidden && !designable ? 0 : columnSchema['x-component-props']?.width || 100,
|
||||||
render: (value, record, index) => {
|
render: (value, record, index) => {
|
||||||
return (
|
return (
|
||||||
|
<RefreshComponentProvider refresh={refresh}>
|
||||||
<TableCellRender
|
<TableCellRender
|
||||||
record={record}
|
record={record}
|
||||||
columnSchema={columnSchema}
|
columnSchema={columnSchema}
|
||||||
@ -235,6 +236,7 @@ const useTableColumns = (props: { showDel?: any; isSubTable?: boolean }, paginat
|
|||||||
field={field}
|
field={field}
|
||||||
index={index}
|
index={index}
|
||||||
/>
|
/>
|
||||||
|
</RefreshComponentProvider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onCell: (record, rowIndex) => {
|
onCell: (record, rowIndex) => {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import { useField, useFieldSchema } from '@formily/react';
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
import { ActionContextProvider, SchemaComponentOptions, useActionContext, useDesignable } from '../../';
|
import { ActionContextProvider, SchemaComponentOptions, useActionContext, useDesignable } from '../../';
|
||||||
import { PopupVisibleProvider } from '../../antd/page/PagePopups';
|
import { PopupVisibleProvider } from '../../antd/page/PagePopups';
|
||||||
import { usePopupUtils } from '../../antd/page/pagePopupUtils';
|
import { usePopupUtils } from '../../antd/page/pagePopupUtils';
|
||||||
@ -55,14 +55,35 @@ function withPopupWrapper<T>(WrappedComponent: React.ComponentType<T>) {
|
|||||||
const { enableLink, openMode, openSize } = fieldSchema?.['x-component-props'] || {};
|
const { enableLink, openMode, openSize } = fieldSchema?.['x-component-props'] || {};
|
||||||
const { visibleWithURL, setVisibleWithURL } = usePopupUtils();
|
const { visibleWithURL, setVisibleWithURL } = usePopupUtils();
|
||||||
const { openPopup } = usePopupUtils();
|
const { openPopup } = usePopupUtils();
|
||||||
|
const needWaitForFieldSchemaUpdatedRef = useRef(false);
|
||||||
|
const fieldSchemaRef = useRef(fieldSchema);
|
||||||
|
fieldSchemaRef.current = fieldSchema;
|
||||||
|
|
||||||
|
const getCustomActionSchema = useCallback(() => {
|
||||||
|
return fieldSchemaRef.current;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
|
if (!fieldSchema.properties) {
|
||||||
insertPopup(popupSchema);
|
insertPopup(popupSchema);
|
||||||
|
needWaitForFieldSchemaUpdatedRef.current = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needWaitForFieldSchemaUpdatedRef.current) {
|
||||||
|
// When first inserting, the fieldSchema instance will be updated to a new instance.
|
||||||
|
// We need to wait for the instance update before opening the popup to prevent configuration loss.
|
||||||
|
setTimeout(() => {
|
||||||
|
openPopup({
|
||||||
|
customActionSchema: getCustomActionSchema(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
needWaitForFieldSchemaUpdatedRef.current = false;
|
||||||
|
|
||||||
// Only open the popup when the popup schema exists
|
// Only open the popup when the popup schema exists
|
||||||
if (fieldSchema.properties) {
|
} else if (fieldSchema.properties) {
|
||||||
openPopup();
|
openPopup();
|
||||||
}
|
}
|
||||||
}, [fieldSchema, insertPopup, openPopup]);
|
}, [fieldSchema, insertPopup, openPopup, getCustomActionSchema]);
|
||||||
const { setSubmitted } = ctx;
|
const { setSubmitted } = ctx;
|
||||||
|
|
||||||
const handleVisibleChange = useCallback(
|
const handleVisibleChange = useCallback(
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
NocoBaseRecursionField,
|
NocoBaseRecursionField,
|
||||||
PopupSettingsProvider,
|
PopupSettingsProvider,
|
||||||
RecordProvider,
|
RecordProvider,
|
||||||
|
RefreshComponentProvider,
|
||||||
TabsContextProvider,
|
TabsContextProvider,
|
||||||
fetchTemplateData,
|
fetchTemplateData,
|
||||||
useACLActionParamsContext,
|
useACLActionParamsContext,
|
||||||
@ -30,6 +31,7 @@ import {
|
|||||||
useRecord,
|
useRecord,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import { App, Button } from 'antd';
|
import { App, Button } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
@ -209,7 +211,9 @@ export const DuplicateAction = observer(
|
|||||||
<RecordProvider record={{ ...parentRecordData, __collection: duplicateCollection || __collection }}>
|
<RecordProvider record={{ ...parentRecordData, __collection: duplicateCollection || __collection }}>
|
||||||
<ActionContextProvider value={{ ...ctx, visible, setVisible }}>
|
<ActionContextProvider value={{ ...ctx, visible, setVisible }}>
|
||||||
<PopupSettingsProvider enableURL={false}>
|
<PopupSettingsProvider enableURL={false}>
|
||||||
|
<RefreshComponentProvider refresh={_.noop}>
|
||||||
<NocoBaseRecursionField schema={fieldSchema} basePath={field.address} onlyRenderProperties />
|
<NocoBaseRecursionField schema={fieldSchema} basePath={field.address} onlyRenderProperties />
|
||||||
|
</RefreshComponentProvider>
|
||||||
</PopupSettingsProvider>
|
</PopupSettingsProvider>
|
||||||
</ActionContextProvider>
|
</ActionContextProvider>
|
||||||
</RecordProvider>
|
</RecordProvider>
|
||||||
|
@ -58,6 +58,25 @@ test.describe('direct duplicate & copy into the form and continue to fill in', (
|
|||||||
await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-general').click();
|
await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-general').click();
|
||||||
await page.getByRole('menuitem', { name: 'Submit' }).click();
|
await page.getByRole('menuitem', { name: 'Submit' }).click();
|
||||||
await page.getByLabel('drawer-Action.Container-general-Duplicate-mask').click();
|
await page.getByLabel('drawer-Action.Container-general-Duplicate-mask').click();
|
||||||
|
|
||||||
|
// 再次打开弹窗,刚配置的字段应该还在
|
||||||
|
await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').click();
|
||||||
|
await expect(
|
||||||
|
page.getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText'),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo-oneToOneBelongsTo'),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByLabel('block-item-CollectionField-general-form-general.oneToOneHasOne-oneToOneHasOne'),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(page.getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne')).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany'),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(page.getByLabel('action-Action-Submit-submit-general-form')).toBeVisible();
|
||||||
|
await page.getByLabel('drawer-Action.Container-general-Duplicate-mask').click();
|
||||||
|
|
||||||
//同步表单字段
|
//同步表单字段
|
||||||
await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').hover();
|
await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').hover();
|
||||||
await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover();
|
await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover();
|
||||||
|
@ -18,7 +18,8 @@ test.describe('form item & filter form', () => {
|
|||||||
page,
|
page,
|
||||||
showMenu: async () => {
|
showMenu: async () => {
|
||||||
await page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToMany-manyToMany').hover();
|
await page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToMany-manyToMany').hover();
|
||||||
await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).hover();
|
// hover 方法有时会失效,所以这里使用 click 方法。原因未知
|
||||||
|
await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).click();
|
||||||
},
|
},
|
||||||
supportedOptions: [
|
supportedOptions: [
|
||||||
'Edit field title',
|
'Edit field title',
|
||||||
|
@ -27,7 +27,8 @@ test.describe('form item & filter form', () => {
|
|||||||
page,
|
page,
|
||||||
showMenu: async () => {
|
showMenu: async () => {
|
||||||
await page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToOne-manyToOne').hover();
|
await page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToOne-manyToOne').hover();
|
||||||
await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).hover();
|
// hover 方法有时会失效,所以这里使用 click 方法。原因未知
|
||||||
|
await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).click();
|
||||||
},
|
},
|
||||||
supportedOptions: [
|
supportedOptions: [
|
||||||
'Edit field title',
|
'Edit field title',
|
||||||
@ -48,7 +49,8 @@ test.describe('form item & filter form', () => {
|
|||||||
page,
|
page,
|
||||||
showMenu: async () => {
|
showMenu: async () => {
|
||||||
await page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToOne-manyToOne').hover();
|
await page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToOne-manyToOne').hover();
|
||||||
await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).hover();
|
// hover 方法有时会失效,所以这里使用 click 方法。原因未知
|
||||||
|
await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).click();
|
||||||
},
|
},
|
||||||
supportedOptions: [
|
supportedOptions: [
|
||||||
'Edit field title',
|
'Edit field title',
|
||||||
|
@ -125,7 +125,8 @@ test.describe('form item & filter form', () => {
|
|||||||
page,
|
page,
|
||||||
showMenu: async () => {
|
showMenu: async () => {
|
||||||
await page.getByLabel('block-item-CollectionField-general-filter-form-general.oneToMany-oneToMany').hover();
|
await page.getByLabel('block-item-CollectionField-general-filter-form-general.oneToMany-oneToMany').hover();
|
||||||
await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).hover();
|
// hover 方法有时会失效,所以这里使用 click 方法。原因未知
|
||||||
|
await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).click();
|
||||||
},
|
},
|
||||||
supportedOptions: [
|
supportedOptions: [
|
||||||
'Edit field title',
|
'Edit field title',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user