fix(formula-field): formula field set form value change (#3873)

* fix: formula field set form value change

* test: form edit unsave change
This commit is contained in:
katherinehhh 2024-03-30 09:04:56 +08:00 committed by GitHub
parent eb9b19ddcf
commit e1dca5deab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 729 additions and 4 deletions

View File

@ -6,7 +6,7 @@ import {
oneTableBlockWithActionsAndFormBlocks, oneTableBlockWithActionsAndFormBlocks,
test, test,
} from '@nocobase/test/e2e'; } from '@nocobase/test/e2e';
import { T3825 } from './templatesOfBug';
const clickOption = async (page: Page, optionName: string) => { const clickOption = async (page: Page, optionName: string) => {
await page.getByLabel('block-item-CardItem-general-form').hover(); await page.getByLabel('block-item-CardItem-general-form').hover();
await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').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 page.getByText('Edit', { exact: true }).click();
await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); 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', () => { test.describe('actions schema settings', () => {

View File

@ -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,
},
};

View File

@ -10,10 +10,11 @@ import {
useCollection_deprecated, useCollection_deprecated,
useCollectionManager_deprecated, useCollectionManager_deprecated,
useFormBlockContext, useFormBlockContext,
ActionContext,
} from '@nocobase/client'; } from '@nocobase/client';
import { Evaluator, evaluators } from '@nocobase/evaluators/client'; import { Evaluator, evaluators } from '@nocobase/evaluators/client';
import { Registry, toFixedByStep } from '@nocobase/utils/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'; import { toDbType } from '../../../utils';
@ -58,11 +59,13 @@ export function Result(props) {
const [editingValue, setEditingValue] = useState(value); const [editingValue, setEditingValue] = useState(value);
const { evaluate } = (evaluators as Registry<Evaluator>).get(engine); const { evaluate } = (evaluators as Registry<Evaluator>).get(engine);
const formBlockContext = useFormBlockContext(); const formBlockContext = useFormBlockContext();
const field = useField(); const field: any = useField();
const path: any = field.path.entire; const path: any = field.path.entire;
const fieldPath = path?.replace(`.${fieldSchema.name}`, ''); const fieldPath = path?.replace(`.${fieldSchema.name}`, '');
const fieldName = fieldPath.split('.')[0]; const fieldName = fieldPath.split('.')[0];
const index = parseInt(fieldPath.split('.')?.[1]); const index = parseInt(fieldPath.split('.')?.[1]);
const ctx = useContext(ActionContext);
useEffect(() => { useEffect(() => {
setEditingValue(value); setEditingValue(value);
}, [value]); }, [value]);
@ -88,7 +91,8 @@ export function Result(props) {
setEditingValue(v); setEditingValue(v);
} }
setEditingValue(v); setEditingValue(v);
v !== value && props.onChange(v); props.onChange(v);
ctx.setFormValueChanged(false);
}); });
}); });
const Component = TypedComponents[dataType] ?? InputString; const Component = TypedComponents[dataType] ?? InputString;