feat(widget-relation): string templates support (#3659)

This commit is contained in:
Erez Rokah
2020-04-30 16:03:08 +03:00
committed by GitHub
parent 02f3cdd102
commit 213ae86b54
17 changed files with 406 additions and 95 deletions

View File

@ -30,6 +30,7 @@
"immutable": "^3.7.6",
"lodash": "^4.17.11",
"netlify-cms-ui-default": "^2.6.0",
"netlify-cms-lib-widgets": "^1.0.0",
"prop-types": "^15.7.2",
"react": "^16.8.4",
"uuid": "^3.3.2"

View File

@ -5,6 +5,7 @@ import { Async as AsyncSelect } from 'react-select';
import { find, isEmpty, last, debounce } from 'lodash';
import { List, Map, fromJS } from 'immutable';
import { reactSelectStyles } from 'netlify-cms-ui-default';
import { stringTemplate } from 'netlify-cms-lib-widgets';
function optionToString(option) {
return option && option.value ? option.value : '';
@ -72,7 +73,7 @@ export default class RelationControl extends React.Component {
if (value) {
const listValue = List.isList(value) ? value : List([value]);
listValue.forEach(val => {
const hit = hits.find(i => this.parseNestedFields(i.data, valueField) === val);
const hit = hits.find(hit => this.parseNestedFields(hit, valueField) === val);
if (hit) {
onChange(value, {
[field.get('name')]: {
@ -113,17 +114,15 @@ export default class RelationControl extends React.Component {
}
};
parseNestedFields = (targetObject, field) => {
const nestedField = field.split('.');
let f = targetObject;
for (let i = 0; i < nestedField.length; i++) {
f = f[nestedField[i]];
if (!f) break;
parseNestedFields = (hit, field) => {
const templateVars = stringTemplate.extractTemplateVars(field);
// wrap non template fields with a template
if (templateVars.length <= 0) {
field = `{{fields.${field}}}`;
}
if (typeof f === 'object' && f !== null) {
return JSON.stringify(f);
}
return f;
const data = stringTemplate.addFileTemplateFields(hit.path, fromJS(hit.data));
const value = stringTemplate.compileStringTemplate(field, null, hit.slug, data);
return value;
};
parseHitOptions = hits => {
@ -136,14 +135,14 @@ export default class RelationControl extends React.Component {
if (List.isList(displayField)) {
labelReturn = displayField
.toJS()
.map(key => this.parseNestedFields(hit.data, key))
.map(key => this.parseNestedFields(hit, key))
.join(' ');
} else {
labelReturn = this.parseNestedFields(hit.data, displayField);
labelReturn = this.parseNestedFields(hit, displayField);
}
return {
data: hit.data,
value: this.parseNestedFields(hit.data, valueField),
value: this.parseNestedFields(hit, valueField),
label: labelReturn,
};
});

View File

@ -43,7 +43,8 @@ const generateHits = length => {
const hits = Array.from({ length }, (val, idx) => {
const title = `Post # ${idx + 1}`;
const slug = `post-number-${idx + 1}`;
return { collection: 'posts', data: { title, slug } };
const path = `posts/${slug}.md`;
return { collection: 'posts', data: { title, slug }, slug, path };
});
return [
@ -247,6 +248,31 @@ describe('Relation widget', () => {
});
});
it('should handle string templates', async () => {
const stringTemplateConfig = {
name: 'post',
collection: 'posts',
displayFields: ['{{slug}}', '{{filename}}', '{{extension}}'],
searchFields: ['slug'],
valueField: '{{slug}}',
};
const field = fromJS(stringTemplateConfig);
const { getByText, input, onChangeSpy } = setup({ field });
const value = 'post-number-1';
const label = 'post-number-1 post-number-1 md';
const metadata = {
post: { posts: { 'post-number-1': { title: 'Post # 1', slug: 'post-number-1' } } },
};
await wait(() => {
fireEvent.keyDown(input, { key: 'ArrowDown' });
fireEvent.click(getByText(label));
expect(onChangeSpy).toHaveBeenCalledTimes(1);
expect(onChangeSpy).toHaveBeenCalledWith(value, metadata);
});
});
describe('with multiple', () => {
it('should call onChange with correct selectedItem value and metadata', async () => {
const field = fromJS({ ...fieldConfig, multiple: true });