feat(widget-relation): string templates support (#3659)
This commit is contained in:
@ -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"
|
||||
|
@ -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,
|
||||
};
|
||||
});
|
||||
|
@ -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 });
|
||||
|
Reference in New Issue
Block a user