From e1dca5deab0a6c55818cda78b9cf12037c68563c Mon Sep 17 00:00:00 2001 From: katherinehhh Date: Sat, 30 Mar 2024 09:04:56 +0800 Subject: [PATCH] fix(formula-field): formula field set form value change (#3873) * fix: formula field set form value change * test: form edit unsave change --- .../__e2e__/form-edit/schemaSettings.test.ts | 24 +- .../form/__e2e__/form-edit/templatesOfBug.ts | 699 ++++++++++++++++++ .../src/client/__e2e__/form-edit.test.ts | 0 .../src/client/__e2e__/utils.ts | 0 .../src/client/components/Formula/Result.tsx | 10 +- 5 files changed, 729 insertions(+), 4 deletions(-) create mode 100644 packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-edit.test.ts create mode 100644 packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/utils.ts diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/schemaSettings.test.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/schemaSettings.test.ts index c0b0c6dd79..8933fcf82d 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/schemaSettings.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/schemaSettings.test.ts @@ -6,7 +6,7 @@ import { oneTableBlockWithActionsAndFormBlocks, test, } from '@nocobase/test/e2e'; - +import { T3825 } from './templatesOfBug'; const clickOption = async (page: Page, optionName: string) => { await page.getByLabel('block-item-CardItem-general-form').hover(); await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); @@ -146,6 +146,28 @@ test.describe('edit form block schema settings', () => { await page.getByText('Edit', { exact: true }).click(); await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); }); + // https://nocobase.height.app/T-3825 + test('Unsaved changes warning display', async ({ page, mockPage, mockRecord }) => { + await mockPage(T3825).goto(); + await mockRecord('general', { number: 9, formula: 10 }); + await expect(await page.getByLabel('block-item-CardItem-general-')).toBeVisible(); + //没有改动时不显示提示 + await page.getByLabel('action-Action.Link-Edit-').click(); + await page.getByLabel('drawer-Action.Container-general-Edit record-mask').click(); + await expect(await page.getByLabel('action-Action-Add new-create-')).toBeVisible(); + //有改动时显示提示 + await page.getByLabel('action-Action.Link-Edit-').click(); + await page.getByRole('spinbutton').fill(''); + await page.getByRole('spinbutton').fill('10'); + await expect( + await page + .getByLabel('block-item-CollectionField-general-form-general.formula-formula') + .locator('.nb-read-pretty-input-number') + .innerText(), + ).toBe('11'); + await page.getByLabel('drawer-Action.Container-general-Edit record-mask').click(); + await expect(await page.getByText('Unsaved changes')).toBeVisible(); + }); }); test.describe('actions schema settings', () => { diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/templatesOfBug.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/templatesOfBug.ts index e69de29bb2..3f10631b62 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/templatesOfBug.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/templatesOfBug.ts @@ -0,0 +1,699 @@ +import { PageConfig } from '@nocobase/test/e2e'; + +export const T3825: PageConfig = { + collections: [ + { + name: 'general', + title: 'general', + fields: [ + { + key: 'v2otrrj0ci7', + name: 'number', + type: 'double', + interface: 'number', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + uiSchema: { + 'x-component-props': { + step: '1', + stringMode: true, + }, + type: 'number', + 'x-component': 'InputNumber', + title: 'number', + }, + }, + { + key: 'qj3x1ud4z28', + name: 'formula', + type: 'formula', + interface: 'formula', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + dataType: 'double', + uiSchema: { + 'x-component-props': { + step: '1', + stringMode: true, + }, + type: 'string', + 'x-component': 'Formula.Result', + 'x-read-pretty': true, + title: 'formula', + }, + engine: 'math.js', + expression: '{{number}}+1', + }, + ], + }, + ], + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + '0biqfy2zml3': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'page:addBlock', + properties: { + '0s1f7fp2izu': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + zxv8gjscs2u: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + k9sn3kljtiz: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'general:list', + 'x-use-decorator-props': 'useTableBlockDecoratorProps', + 'x-decorator-props': { + collection: 'general', + 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': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'table:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + properties: { + is4wntpw700: { + _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-align': 'right', + 'x-acl-action-props': { + skipScopeCheck: 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', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializersForCreateFormBlock', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Add new")}}', + '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:addNew:addBlock', + properties: { + mwt2j2b8ld1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + a9gqvjrweql: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + ujkjn3r4401: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'general:create', + 'x-decorator': 'FormBlockProvider', + 'x-use-decorator-props': 'useCreateFormBlockDecoratorProps', + 'x-decorator-props': { + dataSource: 'main', + collection: 'general', + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:createForm', + 'x-component': 'CardItem', + properties: { + bua02um0mds: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useCreateFormBlockProps', + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'form:configureFields', + properties: { + '98ms35vwlx7': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '3gd85f0560m': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + formula: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.formula', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-uid': 's9nzzjl1ikg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fsq1tv8dbeg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'e7uvqvk33tg', + 'x-async': false, + 'x-index': 1, + }, + t46yegdn557: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + l4yp279yrh1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + number: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.number', + 'x-component-props': {}, + 'x-uid': 'wsvzmw7xh9f', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '22lcs4yh8cx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'uqfhapkkoan', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'ckbhppzqxdm', + 'x-async': false, + 'x-index': 1, + }, + '5m5c0lbxw4e': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'createForm:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + properties: { + c0n5o4oxujz: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:createSubmit', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ useCreateActionProps }}', + }, + 'x-action-settings': { + triggerWorkflows: [], + }, + type: 'void', + 'x-uid': 'ja9nqniwql2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '39pm08qey9x', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '71ka95326it', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nv5mmqmaznb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7wtzzkobopg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'jmgn68hohcg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'sy89mdmowx4', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'k5vs1az4m5x', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rps43vm0x5y', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'trqp1tchkja', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'asw0518ng90', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9on4xy0qhkk', + 'x-async': false, + 'x-index': 1, + }, + z9j7ox6eth1: { + _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', + }, + }, + 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', + properties: { + '3f8sk9ls98c': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + fpqhthzthwq: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit") }}', + 'x-action': 'update', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:edit', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + icon: 'EditOutlined', + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit 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': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + '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: { + ax3qx2zptby: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + atcx7ntysba: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + eq3bx9kc1vp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: false, + }, + 'x-acl-action': 'general:update', + 'x-decorator': 'FormBlockProvider', + 'x-use-decorator-props': + 'useEditFormBlockDecoratorProps', + 'x-decorator-props': { + action: 'get', + dataSource: 'main', + collection: 'general', + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:editForm', + 'x-component': 'CardItem', + properties: { + '5z7042we9r3': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useEditFormBlockProps', + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'form:configureFields', + properties: { + '1jhlaok57b7': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '9vwbbpjwbdd': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + number: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'general.number', + 'x-component-props': {}, + 'x-uid': '8d9j7fscxaq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9q13csuxjue', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '2ndghm9nmms', + 'x-async': false, + 'x-index': 1, + }, + dqm6kyqavz2: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + fq06zgkvcz4: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + formula: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'general.formula', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-uid': 'ir8xgcqe3jk', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'yrqeyd268w1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '31iexi3p7v4', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '33kdyaos7cp', + 'x-async': false, + 'x-index': 1, + }, + '9f1vdmx4yf5': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'editForm:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'mx39adnt22r', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '3vifw73q7a1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nebpfn05tbz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1ehiymukfyw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4fguesasbn8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '54jwk7yazy0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fc64v5tjfma', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ysubu5eksvf', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'icn3htcat5h', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'i3vptzj5mwv', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'id4303zfv3n', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ih90oed6kaa', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8w3vkvavxge', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'ikq5dgl699g', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'mvyi335olgz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qgoavprouvh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'l61yqcsimvo', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'e0tx911rj7f', + 'x-async': true, + 'x-index': 1, + }, +}; diff --git a/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-edit.test.ts b/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-edit.test.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/utils.ts b/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/utils.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/plugins/@nocobase/plugin-formula-field/src/client/components/Formula/Result.tsx b/packages/plugins/@nocobase/plugin-formula-field/src/client/components/Formula/Result.tsx index 893d907fb4..e2ab162806 100644 --- a/packages/plugins/@nocobase/plugin-formula-field/src/client/components/Formula/Result.tsx +++ b/packages/plugins/@nocobase/plugin-formula-field/src/client/components/Formula/Result.tsx @@ -10,10 +10,11 @@ import { useCollection_deprecated, useCollectionManager_deprecated, useFormBlockContext, + ActionContext, } from '@nocobase/client'; import { Evaluator, evaluators } from '@nocobase/evaluators/client'; import { Registry, toFixedByStep } from '@nocobase/utils/client'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useContext } from 'react'; import { toDbType } from '../../../utils'; @@ -58,11 +59,13 @@ export function Result(props) { const [editingValue, setEditingValue] = useState(value); const { evaluate } = (evaluators as Registry).get(engine); const formBlockContext = useFormBlockContext(); - const field = useField(); + const field: any = useField(); const path: any = field.path.entire; const fieldPath = path?.replace(`.${fieldSchema.name}`, ''); const fieldName = fieldPath.split('.')[0]; const index = parseInt(fieldPath.split('.')?.[1]); + const ctx = useContext(ActionContext); + useEffect(() => { setEditingValue(value); }, [value]); @@ -88,7 +91,8 @@ export function Result(props) { setEditingValue(v); } setEditingValue(v); - v !== value && props.onChange(v); + props.onChange(v); + ctx.setFormValueChanged(false); }); }); const Component = TypedComponents[dataType] ?? InputString;