fix: allow any default list as default value for list widgets (#5030)

This commit is contained in:
Pearce
2021-04-05 08:54:07 -07:00
committed by GitHub
parent 9d049ca604
commit 83c235423e
5 changed files with 193 additions and 147 deletions

View File

@ -146,6 +146,28 @@ describe('entries', () => {
expect(createEmptyDraftData(fields)).toEqual({ images: fromJS([]) });
});
it('should allow a complex array as list default for a single field list', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
default: [
{
url: 'https://image.png',
},
],
field: { name: 'url', widget: 'text' },
},
]);
expect(createEmptyDraftData(fields)).toEqual({
images: fromJS([
{
url: 'https://image.png',
},
]),
});
});
it('should allow an empty array as list default for a fields list', () => {
const fields = fromJS([
{
@ -161,78 +183,49 @@ describe('entries', () => {
expect(createEmptyDraftData(fields)).toEqual({ images: fromJS([]) });
});
it('should not allow setting a non empty array as a default value for a single field list', () => {
it('should allow a complex array as list default for a fields list', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
default: [{ name: 'url' }, { other: 'field' }],
field: { name: 'url', widget: 'text' },
},
]);
expect(createEmptyDraftData(fields)).toEqual({});
});
it('should not allow setting a non empty array as a default value for a fields list', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
default: [{ name: 'url' }, { other: 'field' }],
default: [
{
title: 'default image',
url: 'https://image.png',
},
],
fields: [
{ name: 'title', widget: 'text' },
{ name: 'url', widget: 'text' },
],
},
]);
expect(createEmptyDraftData(fields)).toEqual({});
});
it('should set default value for list field widget', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
field: { name: 'url', widget: 'text', default: 'https://image.png' },
},
]);
expect(createEmptyDraftData(fields)).toEqual({ images: ['https://image.png'] });
});
it('should override list default with field default', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
default: [],
field: { name: 'url', widget: 'text', default: 'https://image.png' },
},
]);
expect(createEmptyDraftData(fields)).toEqual({ images: ['https://image.png'] });
});
it('should set default values for list fields widget', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
fields: [
{ name: 'title', widget: 'text', default: 'default image' },
{ name: 'url', widget: 'text', default: 'https://image.png' },
],
},
]);
expect(createEmptyDraftData(fields)).toEqual({
images: [{ title: 'default image', url: 'https://image.png' }],
images: fromJS([
{
title: 'default image',
url: 'https://image.png',
},
]),
});
});
it('should override list default with fields default', () => {
it('should use field default when no list default is provided', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
field: { name: 'url', widget: 'text', default: 'https://image.png' },
},
]);
expect(createEmptyDraftData(fields)).toEqual({ images: [{ url: 'https://image.png' }] });
});
it('should use fields default when no list default is provided', () => {
const fields = fromJS([
{
name: 'images',
widget: 'list',
default: [],
fields: [
{ name: 'title', widget: 'text', default: 'default image' },
{ name: 'url', widget: 'text', default: 'https://image.png' },
@ -298,6 +291,26 @@ describe('entries', () => {
]);
expect(createEmptyDraftData(fields)).toEqual({});
});
it('should populate nested fields', () => {
const fields = fromJS([
{
name: 'names',
widget: 'list',
field: {
name: 'object',
widget: 'object',
fields: [
{ name: 'first', widget: 'string', default: 'first' },
{ name: 'second', widget: 'string', default: 'second' },
],
},
},
]);
expect(createEmptyDraftData(fields)).toEqual({
names: [{ object: { first: 'first', second: 'second' } }],
});
});
});
describe('persistLocalBackup', () => {

View File

@ -771,7 +771,6 @@ interface DraftEntryData {
export function createEmptyDraftData(
fields: EntryFields,
withNameKey = true,
skipField: (field: EntryField) => boolean = () => false,
) {
return fields.reduce(
@ -795,36 +794,27 @@ export function createEmptyDraftData(
return [[{}], {}].some(e => isEqual(val, e));
}
if (List.isList(subfields)) {
const subDefaultValue = list
? [createEmptyDraftData(subfields as EntryFields, withNameKey, skipField)]
: createEmptyDraftData(subfields as EntryFields, withNameKey, skipField);
if (!isEmptyDefaultValue(subDefaultValue)) {
acc[name] = subDefaultValue;
} else if (list && List.isList(defaultValue) && (defaultValue as List<unknown>).isEmpty()) {
// allow setting an empty list as a default
const hasSubfields = List.isList(subfields) || Map.isMap(subfields);
if (hasSubfields) {
if (list && List.isList(defaultValue)) {
acc[name] = defaultValue;
}
return acc;
}
} else {
const asList = List.isList(subfields)
? (subfields as EntryFields)
: List([subfields as EntryField]);
if (Map.isMap(subfields)) {
const subDefaultValue = list
? [createEmptyDraftData(List([subfields as EntryField]), false, skipField)]
: createEmptyDraftData(List([subfields as EntryField]), withNameKey, skipField);
if (!isEmptyDefaultValue(subDefaultValue)) {
acc[name] = subDefaultValue;
} else if (list && List.isList(defaultValue) && (defaultValue as List<unknown>).isEmpty()) {
// allow setting an empty list as a default
acc[name] = defaultValue;
const subDefaultValue = list
? [createEmptyDraftData(asList, skipField)]
: createEmptyDraftData(asList, skipField);
if (!isEmptyDefaultValue(subDefaultValue)) {
acc[name] = subDefaultValue;
}
}
return acc;
}
if (defaultValue !== null) {
if (!withNameKey) {
return defaultValue;
}
acc[name] = defaultValue;
}
@ -843,7 +833,7 @@ function createEmptyDraftI18nData(collection: Collection, dataFields: EntryField
return field.get(I18N) !== I18N_FIELD.DUPLICATE && field.get(I18N) !== I18N_FIELD.TRANSLATE;
}
const i18nData = createEmptyDraftData(dataFields, true, skipField);
const i18nData = createEmptyDraftData(dataFields, skipField);
return duplicateDefaultI18nFields(collection, i18nData);
}

View File

@ -76,7 +76,7 @@ export class PreviewPane extends React.Component {
// We retrieve the field by name so that this function can also be used in
// custom preview templates, where the field object can't be passed in.
let field = fields && fields.find(f => f.get('name') === name);
let value = values && values.get(field.get('name'));
let value = Map.isMap(values) && values.get(field.get('name'));
if (field.get('meta')) {
value = this.props.entry.getIn(['meta', field.get('name')]);
}

View File

@ -80,6 +80,17 @@ function handleSummary(summary, entry, label, item) {
return stringTemplate.compileStringTemplate(summary, null, '', data);
}
function validateItem(field, item) {
if (!Map.isMap(item)) {
console.warn(
`'${field.get('name')}' field item value value should be a map but is a '${typeof item}'`,
);
return false;
}
return true;
}
export default class ListControl extends React.Component {
validations = [];
@ -386,6 +397,9 @@ export default class ListControl extends React.Component {
const valueType = this.getValueType();
switch (valueType) {
case valueTypes.MIXED: {
if (!validateItem(field, item)) {
return;
}
const itemType = getTypedFieldForValue(field, item);
const label = itemType.get('label', itemType.get('name'));
// each type can have its own summary, but default to the list summary if exists
@ -402,6 +416,9 @@ export default class ListControl extends React.Component {
return labelReturn;
}
case valueTypes.MULTIPLE: {
if (!validateItem(field, item)) {
return;
}
const multiFields = field.get('fields');
const labelField = multiFields && multiFields.first();
const value = item.get(labelField.get('name'));