From fa815aeb3c3d9d4eeecea485b89c6030cbbb3b54 Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Thu, 11 Apr 2024 17:25:46 +0800 Subject: [PATCH] fix(TreeTable): add child error (#4008) * fix(TreeTable): add new error * test: add e2e for T-3235 * fix: parentId --- .../src/block-provider/FormBlockProvider.tsx | 5 +++-- .../client/src/block-provider/hooks/index.ts | 9 ++++---- .../data-blocks/table/TreeRecordProvider.tsx | 21 +++++++++++++++++++ .../table/__e2e__/schemaSettings.test.ts | 18 ++++++++++++++++ .../modules/blocks/useParentRecordCommon.ts | 2 +- .../schema-component/antd/action/Action.tsx | 9 +++++--- 6 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 packages/core/client/src/modules/blocks/data-blocks/table/TreeRecordProvider.tsx diff --git a/packages/core/client/src/block-provider/FormBlockProvider.tsx b/packages/core/client/src/block-provider/FormBlockProvider.tsx index 5e9bb38578..f64f0d4b39 100644 --- a/packages/core/client/src/block-provider/FormBlockProvider.tsx +++ b/packages/core/client/src/block-provider/FormBlockProvider.tsx @@ -5,6 +5,7 @@ import React, { createContext, useContext, useEffect, useMemo, useRef } from 're import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps'; import { useCollection_deprecated } from '../collection-manager'; import { CollectionRecord, useCollectionParentRecordData, useCollectionRecord } from '../data-source'; +import { useTreeParentRecord } from '../modules/blocks/data-blocks/table/TreeRecordProvider'; import { RecordProvider, useRecord } from '../record-provider'; import { useActionContext, useDesignable } from '../schema-component'; import { Templates as DataTemplateSelect } from '../schema-component/antd/form-v2/Templates'; @@ -147,14 +148,14 @@ export const useFormBlockContext = () => { */ export const useFormBlockProps = () => { const ctx = useFormBlockContext(); - const record = useRecord(); + const treeParentRecord = useTreeParentRecord(); const { fieldSchema } = useActionContext(); const addChild = fieldSchema?.['x-component-props']?.addChild; useEffect(() => { if (addChild) { ctx.form?.query('parent').take((field) => { field.disabled = true; - field.value = new Proxy({ ...record?.__parent }, {}); + field.value = treeParentRecord; }); } }); diff --git a/packages/core/client/src/block-provider/hooks/index.ts b/packages/core/client/src/block-provider/hooks/index.ts index 9d0143b296..0f72f8e920 100644 --- a/packages/core/client/src/block-provider/hooks/index.ts +++ b/packages/core/client/src/block-provider/hooks/index.ts @@ -22,6 +22,7 @@ import { useAPIClient, useRequest } from '../../api-client'; import { useCollectionManager_deprecated, useCollection_deprecated } from '../../collection-manager'; import { useFilterBlock } from '../../filter-provider/FilterProvider'; import { mergeFilter, transformToFilter } from '../../filter-provider/utils'; +import { useTreeParentRecord } from '../../modules/blocks/data-blocks/table/TreeRecordProvider'; import { useRecord } from '../../record-provider'; import { removeNullCondition, useActionContext, useCompile } from '../../schema-component'; import { isSubMode } from '../../schema-component/antd/association-field/util'; @@ -117,7 +118,7 @@ export function useCollectValuesToSubmit() { const variables = useVariables(); const localVariables = useLocalVariables({ currentForm: form }); const actionSchema = useFieldSchema(); - const currentRecord = useRecord(); + const treeParentRecord = useTreeParentRecord(); return useCallback(async () => { const { assignedValues: originalAssignedValues = {}, overwriteValues } = actionSchema?.['x-action-settings'] ?? {}; @@ -156,8 +157,8 @@ export function useCollectValuesToSubmit() { const addChild = fieldSchema?.['x-component-props']?.addChild; if (addChild) { const treeParentField = getTreeParentField(); - values[treeParentField?.name ?? 'parent'] = omit(currentRecord?.__parent, ['children']); - values[treeParentField?.foreignKey ?? 'parentId'] = currentRecord?.__parent?.id; + values[treeParentField?.name ?? 'parent'] = treeParentRecord; + values[treeParentField?.foreignKey ?? 'parentId'] = treeParentRecord?.id; } return { @@ -167,7 +168,6 @@ export function useCollectValuesToSubmit() { }; }, [ actionSchema, - currentRecord?.__parent, field, fieldNames, fieldSchema, @@ -179,6 +179,7 @@ export function useCollectValuesToSubmit() { localVariables, name, resource, + treeParentRecord, variables, ]); } diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/TreeRecordProvider.tsx b/packages/core/client/src/modules/blocks/data-blocks/table/TreeRecordProvider.tsx new file mode 100644 index 0000000000..efcc9ed696 --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/table/TreeRecordProvider.tsx @@ -0,0 +1,21 @@ +import React, { FC, createContext } from 'react'; + +interface TreeRecordContextProps { + parent: any; +} + +const TreeRecordContext = createContext(null); + +/** + * Tree Table 的上下文,用于在 Tree Table 中替代 RecordProvider。因为 RecordProvider 用在 Tree Table 中会有问题(和关系区块有冲突) + * @param param0 + * @returns + */ +export const TreeRecordProvider: FC = ({ children, parent }) => { + return {children}; +}; + +export const useTreeParentRecord = () => { + const context = React.useContext(TreeRecordContext); + return context?.parent; +}; diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts index e00de1008d..6cbfe2df12 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts @@ -788,6 +788,24 @@ test.describe('actions schema settings', () => { showMenu: () => showMenu(page), supportedOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], }); + + // https://nocobase.height.app/T-3235 + // add child 表单中的 Parent 字段应该有数据 + await page.getByLabel('action-Action.Link-Add child-').click({ + position: { x: 5, y: 5 }, // 防止按钮被遮挡 + }); + await page.getByLabel('schema-initializer-Grid-popup').hover(); + await page.getByRole('menuitem', { name: 'form Form' }).click(); + await page.mouse.move(300, 0); + await page.getByLabel('schema-initializer-Grid-form:').hover(); + await page.getByRole('menuitem', { name: 'Parent', exact: true }).click(); + await page.mouse.move(300, 0); + await expect( + page + .getByLabel('block-item-CollectionField-') + .getByTestId('select-object-single') + .getByText('1', { exact: true }), + ).toBeVisible(); }); }); diff --git a/packages/core/client/src/modules/blocks/useParentRecordCommon.ts b/packages/core/client/src/modules/blocks/useParentRecordCommon.ts index 1cc103a6f3..c7bb9ac92d 100644 --- a/packages/core/client/src/modules/blocks/useParentRecordCommon.ts +++ b/packages/core/client/src/modules/blocks/useParentRecordCommon.ts @@ -2,7 +2,7 @@ import { useCollectionRecordData } from '../../data-source/collection-record/Col /** * @internal - * 大部分区块(除了详情和编辑表单)都适用的获取 sourceId 的 hook + * 大部分区块(除了详情和编辑表单)都适用的获取 sourceRecord 的 hook * @param association * @returns */ diff --git a/packages/core/client/src/schema-component/antd/action/Action.tsx b/packages/core/client/src/schema-component/antd/action/Action.tsx index 0b60268832..1a728330a2 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.tsx +++ b/packages/core/client/src/schema-component/antd/action/Action.tsx @@ -9,8 +9,9 @@ import { StablePopover, useActionContext } from '../..'; import { useDesignable } from '../../'; import { useACLActionParamsContext } from '../../../acl'; import { withDynamicSchemaProps } from '../../../application/hoc/withDynamicSchemaProps'; -import { useDataBlockRequest } from '../../../data-source'; +import { useCollectionParentRecordData, useDataBlockRequest } from '../../../data-source'; import { Icon } from '../../../icon'; +import { TreeRecordProvider } from '../../../modules/blocks/data-blocks/table/TreeRecordProvider'; import { RecordProvider, useRecord } from '../../../record-provider'; import { useLocalVariables, useVariables } from '../../../variables'; import { SortableItem } from '../../common'; @@ -63,6 +64,7 @@ export const Action: ComposedAction = withDynamicSchemaProps( const compile = useCompile(); const form = useForm(); const record = useRecord(); + const parentRecordData = useCollectionParentRecordData(); const designerProps = fieldSchema['x-designer-props']; const openMode = fieldSchema?.['x-component-props']?.['openMode']; const openSize = fieldSchema?.['x-component-props']?.['openSize']; @@ -202,8 +204,9 @@ export const Action: ComposedAction = withDynamicSchemaProps( // fix https://nocobase.height.app/T-3235/description if (addChild) { return wrapSSR( - - {result} + // fix https://nocobase.height.app/T-3966 + + {result} , ); }