fix(Form): retain field's default value after submitting the form (#3665)
* fix(Form): should not be clear default value after submit * test: make e2e more stable
This commit is contained in:
parent
ca0f1b5c05
commit
9e88972ba6
@ -29,6 +29,9 @@ import { transformVariableValue } from '../../variables/utils/transformVariableV
|
|||||||
import { useBlockRequestContext, useFilterByTk, useParamsFromRecord } from '../BlockProvider';
|
import { useBlockRequestContext, useFilterByTk, useParamsFromRecord } from '../BlockProvider';
|
||||||
import { useDetailsBlockContext } from '../DetailsBlockProvider';
|
import { useDetailsBlockContext } from '../DetailsBlockProvider';
|
||||||
import { TableFieldResource } from '../TableFieldProvider';
|
import { TableFieldResource } from '../TableFieldProvider';
|
||||||
|
import { Field, Form } from '@formily/core';
|
||||||
|
import { untracked } from '@formily/reactive';
|
||||||
|
import { isSubMode } from '../../schema-component/antd/association-field/util';
|
||||||
|
|
||||||
export * from './useFormActiveFields';
|
export * from './useFormActiveFields';
|
||||||
export * from './useParsedFilter';
|
export * from './useParsedFilter';
|
||||||
@ -222,14 +225,14 @@ export const useCreateActionProps = () => {
|
|||||||
__parent?.service?.refresh?.();
|
__parent?.service?.refresh?.();
|
||||||
if (!onSuccess?.successMessage) {
|
if (!onSuccess?.successMessage) {
|
||||||
message.success(t('Saved successfully'));
|
message.success(t('Saved successfully'));
|
||||||
await form.reset(undefined, { forceClear: true });
|
await resetFormCorrectly(form);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (onSuccess?.manualClose) {
|
if (onSuccess?.manualClose) {
|
||||||
modal.success({
|
modal.success({
|
||||||
title: compile(onSuccess?.successMessage),
|
title: compile(onSuccess?.successMessage),
|
||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
await form.reset(undefined, { forceClear: true });
|
await resetFormCorrectly(form);
|
||||||
if (onSuccess?.redirecting && onSuccess?.redirectTo) {
|
if (onSuccess?.redirecting && onSuccess?.redirectTo) {
|
||||||
if (isURL(onSuccess.redirectTo)) {
|
if (isURL(onSuccess.redirectTo)) {
|
||||||
window.location.href = onSuccess.redirectTo;
|
window.location.href = onSuccess.redirectTo;
|
||||||
@ -241,7 +244,7 @@ export const useCreateActionProps = () => {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
message.success(compile(onSuccess?.successMessage));
|
message.success(compile(onSuccess?.successMessage));
|
||||||
await form.reset(undefined, { forceClear: true });
|
await resetFormCorrectly(form);
|
||||||
if (onSuccess?.redirecting && onSuccess?.redirectTo) {
|
if (onSuccess?.redirecting && onSuccess?.redirectTo) {
|
||||||
if (isURL(onSuccess.redirectTo)) {
|
if (isURL(onSuccess.redirectTo)) {
|
||||||
window.location.href = onSuccess.redirectTo;
|
window.location.href = onSuccess.redirectTo;
|
||||||
@ -1343,3 +1346,20 @@ function getTargetField(obj) {
|
|||||||
const result = keys.slice(0, index);
|
const result = keys.slice(0, index);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 之所以不直接使用 form.reset() 是因为其无法将子表格重置为空
|
||||||
|
* 主要用于修复这个问题:https://nocobase.height.app/T-3106
|
||||||
|
* @param form
|
||||||
|
*/
|
||||||
|
async function resetFormCorrectly(form: Form) {
|
||||||
|
untracked(() => {
|
||||||
|
Object.keys(form.fields).forEach((key) => {
|
||||||
|
if (isSubMode(form.fields[key])) {
|
||||||
|
// 清空子表格或者子表单的初始值,可以确保后面的 reset 会清空子表格或者子表单的值
|
||||||
|
(form.fields[key] as Field).initialValue = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
await form.reset();
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { createBlockInPage, expect, oneEmptyForm, test } from '@nocobase/test/e2e';
|
import { createBlockInPage, expect, oneEmptyForm, test } from '@nocobase/test/e2e';
|
||||||
import { T3106 } from './templatesOfBug';
|
import { T3106, T3469 } from './templatesOfBug';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
|
||||||
test.describe('where creation form block can be added', () => {
|
test.describe('where creation form block can be added', () => {
|
||||||
test('page', async ({ page, mockPage }) => {
|
test('page', async ({ page, mockPage }) => {
|
||||||
@ -101,6 +102,38 @@ test.describe('configure actions', () => {
|
|||||||
).toHaveValue('test name');
|
).toHaveValue('test name');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// https://nocobase.height.app/T-3469
|
||||||
|
test('default values for fields should not be cleared after submission', async ({ page, mockPage }) => {
|
||||||
|
await mockPage(T3469).goto();
|
||||||
|
|
||||||
|
// username 的值不能重复,所以为了避免报错这里随机生成一个值
|
||||||
|
const username = uid();
|
||||||
|
|
||||||
|
// Username 字段没有设置默认值,手动输入一个值
|
||||||
|
await page
|
||||||
|
.getByLabel('block-item-CollectionField-users-form-users.username-Username')
|
||||||
|
.getByRole('textbox')
|
||||||
|
.fill(username);
|
||||||
|
|
||||||
|
// Nickname 字段设置了默认值,应该显示出默认值
|
||||||
|
await expect(
|
||||||
|
page.getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname').getByRole('textbox'),
|
||||||
|
).toHaveValue('Should be cleared after submission');
|
||||||
|
await expect(
|
||||||
|
page.getByLabel('block-item-CollectionField-users-form-users.username-Username').getByRole('textbox'),
|
||||||
|
).toHaveValue(username);
|
||||||
|
|
||||||
|
// 点击提交按钮之后,Nickname 字段的默认值应该依然显示,Username 字段的值应该被清空
|
||||||
|
await page.getByLabel('action-Action-Submit-submit-').click();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
page.getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname').getByRole('textbox'),
|
||||||
|
).toHaveValue('Should be cleared after submission');
|
||||||
|
await expect(
|
||||||
|
page.getByLabel('block-item-CollectionField-users-form-users.username-Username').getByRole('textbox'),
|
||||||
|
).toHaveValue('');
|
||||||
|
});
|
||||||
|
|
||||||
test('customize: save record', async ({ page, mockPage }) => {
|
test('customize: save record', async ({ page, mockPage }) => {
|
||||||
await mockPage(oneEmptyForm).goto();
|
await mockPage(oneEmptyForm).goto();
|
||||||
|
|
||||||
|
@ -1165,7 +1165,7 @@ test.describe('creation form block schema settings', () => {
|
|||||||
await page.getByRole('menuitem', { name: 'form Form' }).first().hover();
|
await page.getByRole('menuitem', { name: 'form Form' }).first().hover();
|
||||||
await page.getByRole('menuitem', { name: 'Users' }).hover();
|
await page.getByRole('menuitem', { name: 'Users' }).hover();
|
||||||
await page.getByRole('menuitem', { name: 'Duplicate template' }).hover();
|
await page.getByRole('menuitem', { name: 'Duplicate template' }).hover();
|
||||||
await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).click();
|
await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).first().click();
|
||||||
await page.mouse.move(300, 0);
|
await page.mouse.move(300, 0);
|
||||||
await expect(page.getByLabel('block-item-CardItem-users-form')).toBeVisible();
|
await expect(page.getByLabel('block-item-CardItem-users-form')).toBeVisible();
|
||||||
|
|
||||||
@ -1174,7 +1174,7 @@ test.describe('creation form block schema settings', () => {
|
|||||||
await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-users').hover();
|
await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-users').hover();
|
||||||
await page.getByRole('menuitem', { name: 'form Form' }).first().hover();
|
await page.getByRole('menuitem', { name: 'form Form' }).first().hover();
|
||||||
await page.getByRole('menuitem', { name: 'Reference template' }).hover();
|
await page.getByRole('menuitem', { name: 'Reference template' }).hover();
|
||||||
await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).click();
|
await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).first().click();
|
||||||
await page.mouse.move(300, 0);
|
await page.mouse.move(300, 0);
|
||||||
await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-users').hover();
|
await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-users').hover();
|
||||||
await expect(page.locator('.ant-drawer').getByLabel('block-item-CardItem-users-form')).toBeVisible();
|
await expect(page.locator('.ant-drawer').getByLabel('block-item-CardItem-users-form')).toBeVisible();
|
||||||
@ -1185,7 +1185,7 @@ test.describe('creation form block schema settings', () => {
|
|||||||
await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-users').click();
|
await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-users').click();
|
||||||
await page.getByRole('menuitem', { name: 'form Form' }).first().hover();
|
await page.getByRole('menuitem', { name: 'form Form' }).first().hover();
|
||||||
await page.getByRole('menuitem', { name: 'Reference template' }).hover();
|
await page.getByRole('menuitem', { name: 'Reference template' }).hover();
|
||||||
await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).click();
|
await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).first().click();
|
||||||
await page.mouse.move(300, 0);
|
await page.mouse.move(300, 0);
|
||||||
|
|
||||||
//修改引用模板
|
//修改引用模板
|
||||||
|
@ -5491,3 +5491,213 @@ export const T3251: PageConfig = {
|
|||||||
'x-index': 1,
|
'x-index': 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const T3469: PageConfig = {
|
||||||
|
pageSchema: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Page',
|
||||||
|
'x-index': 1,
|
||||||
|
properties: {
|
||||||
|
'9u463vapg0k': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'BlockInitializers',
|
||||||
|
'x-index': 1,
|
||||||
|
properties: {
|
||||||
|
isaxpp1w32b: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-index': 1,
|
||||||
|
properties: {
|
||||||
|
'5dld0j6dehi': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-index': 1,
|
||||||
|
properties: {
|
||||||
|
'96xwhprgfdg': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-acl-action-props': {
|
||||||
|
skipScopeCheck: true,
|
||||||
|
},
|
||||||
|
'x-acl-action': 'users:create',
|
||||||
|
'x-decorator': 'FormBlockProvider',
|
||||||
|
'x-decorator-props': {
|
||||||
|
dataSource: 'main',
|
||||||
|
resource: 'users',
|
||||||
|
collection: 'users',
|
||||||
|
},
|
||||||
|
'x-toolbar': 'BlockSchemaToolbar',
|
||||||
|
'x-settings': 'blockSettings:createForm',
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-index': 1,
|
||||||
|
properties: {
|
||||||
|
'0sj1sfgjoxa': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormV2',
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useFormBlockProps }}',
|
||||||
|
},
|
||||||
|
'x-index': 1,
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'FormItemInitializers',
|
||||||
|
'x-index': 1,
|
||||||
|
properties: {
|
||||||
|
e4ke3wqxm2o: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-index': 1,
|
||||||
|
properties: {
|
||||||
|
l8uf6qeppmb: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-index': 1,
|
||||||
|
properties: {
|
||||||
|
nickname: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'string',
|
||||||
|
'x-toolbar': 'FormItemSchemaToolbar',
|
||||||
|
'x-settings': 'fieldSettings:FormItem',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-collection-field': 'users.nickname',
|
||||||
|
'x-component-props': {},
|
||||||
|
default: 'Should be cleared after submission',
|
||||||
|
'x-index': 1,
|
||||||
|
'x-uid': 'lpgebrm0gig',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'novdv1tcz37',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'kzf3dxvr0mb',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
s17cswscq2o: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
properties: {
|
||||||
|
oh79jnxzotw: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
properties: {
|
||||||
|
username: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'string',
|
||||||
|
'x-toolbar': 'FormItemSchemaToolbar',
|
||||||
|
'x-settings': 'fieldSettings:FormItem',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-collection-field': 'users.username',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-uid': 'z9dn5rnc3oi',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '62vb90prmzk',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'ti5u46epv08',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'e365kp0cwm9',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
'7660qws6e4c': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-initializer': 'FormActionInitializers',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
layout: 'one-column',
|
||||||
|
style: {
|
||||||
|
marginTop: 24,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-index': 2,
|
||||||
|
properties: {
|
||||||
|
'79tmpu1usft': {
|
||||||
|
_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-index': 1,
|
||||||
|
'x-uid': '96sageysorb',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'nnn377hn4o4',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'j5qpwo8d6su',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'rlcmlnna7k8',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'b6n82zkmrsh',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'agdpemeoz1v',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'dn5nok8na2g',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'lb8hlm9oyv8',
|
||||||
|
'x-async': true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -175,7 +175,6 @@ export const SubTable: any = observer(
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
field.value = field.value || [];
|
field.value = field.value || [];
|
||||||
field.value.push(markRecordAsNew({}));
|
field.value.push(markRecordAsNew({}));
|
||||||
field.onInput(field.value);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('Add new')}
|
{t('Add new')}
|
||||||
|
@ -5,6 +5,7 @@ import { Tag } from 'antd';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CollectionFieldOptions_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
|
import { CollectionFieldOptions_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
|
||||||
|
import { Field } from '@formily/core';
|
||||||
|
|
||||||
export const useLabelUiSchemaV2 = () => {
|
export const useLabelUiSchemaV2 = () => {
|
||||||
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
||||||
@ -102,6 +103,7 @@ export function isShowFilePicker(labelUiSchema) {
|
|||||||
/**
|
/**
|
||||||
* 当前字段的模式是否是 `子表格` 或者 `子表单`
|
* 当前字段的模式是否是 `子表格` 或者 `子表单`
|
||||||
*/
|
*/
|
||||||
export function isSubMode(fieldSchema: Schema) {
|
export function isSubMode(field: any) {
|
||||||
return ['Nester', 'SubTable', 'PopoverNester'].includes(fieldSchema['x-component-props']?.mode);
|
const mode = field['x-component-props']?.mode || (field as Field).componentProps?.mode;
|
||||||
|
return ['Nester', 'SubTable', 'PopoverNester'].includes(mode);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user