feat: default value (#679)
* feat: default value * feat: add global default value * fix: field default value should be updated * feat: adjust defaultValue logic * feat: add hasDefaultValue property Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
b9fb69c7aa
commit
f4f35bdb43
@ -11,7 +11,9 @@ import { useCollectionField } from './hooks';
|
|||||||
const InternalField: React.FC = (props) => {
|
const InternalField: React.FC = (props) => {
|
||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { name, interface: interfaceType, uiSchema } = useCollectionField();
|
const { name, interface: interfaceType, uiSchema, defaultValue } = useCollectionField();
|
||||||
|
const collectionField = useCollectionField();
|
||||||
|
|
||||||
const component = useComponent(uiSchema?.['x-component']);
|
const component = useComponent(uiSchema?.['x-component']);
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const setFieldProps = (key, value) => {
|
const setFieldProps = (key, value) => {
|
||||||
@ -38,7 +40,10 @@ const InternalField: React.FC = (props) => {
|
|||||||
setFieldProps('content', uiSchema['x-content']);
|
setFieldProps('content', uiSchema['x-content']);
|
||||||
setFieldProps('title', uiSchema.title);
|
setFieldProps('title', uiSchema.title);
|
||||||
setFieldProps('description', uiSchema.description);
|
setFieldProps('description', uiSchema.description);
|
||||||
setFieldProps('initialValue', uiSchema.default);
|
if (ctx?.form) {
|
||||||
|
setFieldProps('initialValue', fieldSchema.default || defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
if (!field.validator && (uiSchema['x-validator'] || fieldSchema['x-validator'])) {
|
if (!field.validator && (uiSchema['x-validator'] || fieldSchema['x-validator'])) {
|
||||||
const concatSchema = concat([], uiSchema['x-validator'] || [], fieldSchema['x-validator'] || []);
|
const concatSchema = concat([], uiSchema['x-validator'] || [], fieldSchema['x-validator'] || []);
|
||||||
field.validator = concatSchema;
|
field.validator = concatSchema;
|
||||||
|
@ -19,7 +19,15 @@ const getSchema = (schema: IField, record: any, compile): ISchema => {
|
|||||||
if (!schema) {
|
if (!schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const properties = cloneDeep(schema.properties) as any;
|
const properties = cloneDeep(schema.properties) as any;
|
||||||
|
|
||||||
|
if (schema.hasDefaultValue === true) {
|
||||||
|
properties['defaultValue'] = cloneDeep(schema.default.uiSchema);
|
||||||
|
properties['defaultValue']['title'] = compile('{{ t("Default value") }}');
|
||||||
|
properties['defaultValue']['x-decorator'] = 'FormItem';
|
||||||
|
}
|
||||||
|
|
||||||
const initialValue = {
|
const initialValue = {
|
||||||
name: `f_${uid()}`,
|
name: `f_${uid()}`,
|
||||||
...cloneDeep(schema.default),
|
...cloneDeep(schema.default),
|
||||||
|
@ -19,6 +19,13 @@ const getSchema = (schema: IField, record: any, compile): ISchema => {
|
|||||||
}
|
}
|
||||||
const properties = cloneDeep(schema.properties) as any;
|
const properties = cloneDeep(schema.properties) as any;
|
||||||
properties.name['x-disabled'] = true;
|
properties.name['x-disabled'] = true;
|
||||||
|
|
||||||
|
if (schema.hasDefaultValue === true) {
|
||||||
|
properties['defaultValue'] = cloneDeep(schema.default.uiSchema);
|
||||||
|
properties['defaultValue']['title'] = compile('{{ t("Default value") }}');
|
||||||
|
properties['defaultValue']['x-decorator'] = 'FormItem';
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -15,6 +15,7 @@ export const checkbox: IField = {
|
|||||||
'x-component': 'Checkbox',
|
'x-component': 'Checkbox',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -17,6 +17,7 @@ export const checkboxGroup: IField = {
|
|||||||
'x-component': 'Checkbox.Group',
|
'x-component': 'Checkbox.Group',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
'uiSchema.enum': dataSource,
|
'uiSchema.enum': dataSource,
|
||||||
|
@ -20,6 +20,7 @@ export const datetime: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
...dateTimeProps,
|
...dateTimeProps,
|
||||||
|
@ -18,6 +18,7 @@ export const email: IField = {
|
|||||||
'x-validator': 'email',
|
'x-validator': 'email',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -16,6 +16,7 @@ export const icon: IField = {
|
|||||||
'x-component': 'IconPicker',
|
'x-component': 'IconPicker',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -18,6 +18,7 @@ export const input: IField = {
|
|||||||
'x-component': 'Input',
|
'x-component': 'Input',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -30,6 +30,7 @@ export const integer: IField = {
|
|||||||
'x-validator': 'integer',
|
'x-validator': 'integer',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -17,6 +17,7 @@ export const markdown: IField = {
|
|||||||
'x-component': 'Markdown',
|
'x-component': 'Markdown',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -21,6 +21,7 @@ export const multipleSelect: IField = {
|
|||||||
enum: [],
|
enum: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
'uiSchema.enum': dataSource,
|
'uiSchema.enum': dataSource,
|
||||||
|
@ -24,6 +24,7 @@ export const number: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
'uiSchema.x-component-props.step': {
|
'uiSchema.x-component-props.step': {
|
||||||
|
@ -18,6 +18,7 @@ export const password: IField = {
|
|||||||
'x-component': 'Password',
|
'x-component': 'Password',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -68,6 +68,7 @@ export const percent: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
'uiSchema.x-component-props.step': {
|
'uiSchema.x-component-props.step': {
|
||||||
|
@ -21,6 +21,7 @@ export const phone: IField = {
|
|||||||
// 'x-validator': 'phone',
|
// 'x-validator': 'phone',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -17,6 +17,7 @@ export const radioGroup: IField = {
|
|||||||
'x-component': 'Radio.Group',
|
'x-component': 'Radio.Group',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
'uiSchema.enum': dataSource,
|
'uiSchema.enum': dataSource,
|
||||||
|
@ -18,6 +18,7 @@ export const richText: IField = {
|
|||||||
'x-component': 'RichText',
|
'x-component': 'RichText',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -18,6 +18,7 @@ export const select: IField = {
|
|||||||
enum: [],
|
enum: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
'uiSchema.enum': dataSource,
|
'uiSchema.enum': dataSource,
|
||||||
|
@ -18,6 +18,7 @@ export const textarea: IField = {
|
|||||||
'x-component': 'Input.TextArea',
|
'x-component': 'Input.TextArea',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
},
|
},
|
||||||
|
@ -16,6 +16,7 @@ export const time: IField = {
|
|||||||
'x-component': 'TimePicker',
|
'x-component': 'TimePicker',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hasDefaultValue: true,
|
||||||
properties: {
|
properties: {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
'uiSchema.x-component-props.format': {
|
'uiSchema.x-component-props.format': {
|
||||||
|
@ -255,6 +255,8 @@ export default {
|
|||||||
"The field value cannot be greater than ": "数值不能大于",
|
"The field value cannot be greater than ": "数值不能大于",
|
||||||
"The field value cannot be less than ": "数值不能小于",
|
"The field value cannot be less than ": "数值不能小于",
|
||||||
"The field value is not an integer number": "数字不是整数",
|
"The field value is not an integer number": "数字不是整数",
|
||||||
|
"Set default value": "设置默认值",
|
||||||
|
"Default value": "默认值",
|
||||||
|
|
||||||
"is before": "早于",
|
"is before": "早于",
|
||||||
"is after": "晚于",
|
"is after": "晚于",
|
||||||
|
@ -326,6 +326,39 @@ FormItem.Designer = (props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{form && !form?.readPretty && collectionField?.uiSchema?.type && (
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Set default value')}
|
||||||
|
components={{ ArrayCollapse, FormLayout }}
|
||||||
|
schema={{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Set default value'),
|
||||||
|
properties: {
|
||||||
|
default: {
|
||||||
|
...collectionField.uiSchema,
|
||||||
|
name: 'default',
|
||||||
|
title: t('Default value'),
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
default: fieldSchema.default || collectionField.defaultValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as ISchema}
|
||||||
|
onSubmit={(v) => {
|
||||||
|
const schema: ISchema = {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
};
|
||||||
|
if (field.value !== v.default) {
|
||||||
|
field.value = v.default;
|
||||||
|
}
|
||||||
|
fieldSchema.default = v.default;
|
||||||
|
schema.default = v.default;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{form && !isSubFormAssocitionField && ['o2o', 'oho', 'obo', 'o2m'].includes(collectionField?.interface) && (
|
{form && !isSubFormAssocitionField && ['o2o', 'oho', 'obo', 'o2m'].includes(collectionField?.interface) && (
|
||||||
<SchemaSettings.SelectItem
|
<SchemaSettings.SelectItem
|
||||||
title={t('Field component')}
|
title={t('Field component')}
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
import { MockServer } from '@nocobase/test';
|
||||||
|
import { createApp } from '..';
|
||||||
|
|
||||||
|
describe('field defaultValue', () => {
|
||||||
|
let app: MockServer;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
app = await createApp();
|
||||||
|
await app.install({ clean: true });
|
||||||
|
await app.start();
|
||||||
|
await app
|
||||||
|
.agent()
|
||||||
|
.resource('collections')
|
||||||
|
.create({
|
||||||
|
values: {
|
||||||
|
name: 'test1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await app.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be updated', async () => {
|
||||||
|
await app
|
||||||
|
.agent()
|
||||||
|
.resource('collections.fields', 'test1')
|
||||||
|
.create({
|
||||||
|
values: {
|
||||||
|
name: 'field1',
|
||||||
|
type: 'string',
|
||||||
|
defaultValue: 'abc',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const response1 = await app.agent().resource('test1').create();
|
||||||
|
expect(response1.body.data.field1).toBe('abc');
|
||||||
|
await app
|
||||||
|
.agent()
|
||||||
|
.resource('collections.fields', 'test1')
|
||||||
|
.update({
|
||||||
|
filterByTk: 'field1',
|
||||||
|
values: {
|
||||||
|
type: 'string',
|
||||||
|
defaultValue: 'cba',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const response2 = await app.agent().resource('test1').create();
|
||||||
|
expect(response2.body.data.field1).toBe('cba');
|
||||||
|
});
|
||||||
|
});
|
@ -70,6 +70,12 @@ export class CollectionManagerPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.app.db.on('fields.afterUpdateWithAssociations', async (model, { context, transaction }) => {
|
||||||
|
if (context) {
|
||||||
|
await model.load({ transaction });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.app.db.on('fields.afterCreateWithAssociations', async (model, { context, transaction }) => {
|
this.app.db.on('fields.afterCreateWithAssociations', async (model, { context, transaction }) => {
|
||||||
if (context) {
|
if (context) {
|
||||||
await model.load({ transaction });
|
await model.load({ transaction });
|
||||||
|
Loading…
Reference in New Issue
Block a user