fix(widget-relation): set initial metadata value (#4182)

This commit is contained in:
Bartholomew 2020-08-30 17:34:22 +01:00 committed by GitHub
parent 8d693caebd
commit 4a510f3a9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 49 deletions

View File

@ -73,7 +73,6 @@ function getSelectedValue({ value, options, isMultiple }) {
} }
export default class RelationControl extends React.Component { export default class RelationControl extends React.Component {
didInitialSearch = false;
mounted = false; mounted = false;
state = { state = {
@ -106,17 +105,19 @@ export default class RelationControl extends React.Component {
// if the field has a previous value perform an initial search based on the value field // if the field has a previous value perform an initial search based on the value field
// this is required since each search is limited by optionsLength so the selected value // this is required since each search is limited by optionsLength so the selected value
// might not show up on the search // might not show up on the search
const { forID, field, value, query } = this.props; const { forID, field, value, query, onChange } = this.props;
const collection = field.get('collection'); const collection = field.get('collection');
const file = field.get('file'); const file = field.get('file');
const initialSearchValues = this.isMultiple() ? getSelectedOptions(value) : [value]; const initialSearchValues = value && (this.isMultiple() ? getSelectedOptions(value) : [value]);
if (initialSearchValues && initialSearchValues.length > 0) { if (initialSearchValues && initialSearchValues.length > 0) {
const metadata = {};
const allOptions = await Promise.all( const allOptions = await Promise.all(
initialSearchValues.map((v, index) => { initialSearchValues.map((v, index) => {
return query(forID, collection, [field.get('valueField')], v, file, 1).then( return query(forID, collection, [field.get('valueField')], v, file, 1).then(
({ payload }) => { ({ payload }) => {
const hits = payload.response?.hits || []; const hits = payload.response?.hits || [];
const options = this.parseHitOptions(hits); const options = this.parseHitOptions(hits);
metadata[v] = hits[0]?.data;
return { options, index }; return { options, index };
}, },
); );
@ -127,6 +128,13 @@ export default class RelationControl extends React.Component {
...sortBy(allOptions, ({ index }) => index).map(({ options }) => options), ...sortBy(allOptions, ({ index }) => index).map(({ options }) => options),
); );
this.mounted && this.setState({ initialOptions }); this.mounted && this.setState({ initialOptions });
//set metadata
onChange(value, {
[field.get('name')]: {
[field.get('collection')]: metadata,
},
});
} }
} }
@ -134,33 +142,6 @@ export default class RelationControl extends React.Component {
this.mounted = false; this.mounted = false;
} }
componentDidUpdate(prevProps) {
/**
* Load extra post data into the store after first query.
*/
if (this.didInitialSearch) return;
const { value, field, forID, queryHits, onChange } = this.props;
if (queryHits !== prevProps.queryHits && queryHits.get(forID)) {
this.didInitialSearch = true;
const valueField = field.get('valueField');
const hits = queryHits.get(forID);
if (value) {
const listValue = List.isList(value) ? value : List([value]);
listValue.forEach(val => {
const hit = hits.find(hit => this.parseNestedFields(hit, valueField) === val);
if (hit) {
onChange(value, {
[field.get('name')]: {
[field.get('collection')]: { [val]: hit.data },
},
});
}
});
}
}
}
handleChange = selectedOption => { handleChange = selectedOption => {
const { onChange, field } = this.props; const { onChange, field } = this.props;
let value; let value;

View File

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { fromJS, Map } from 'immutable'; import { fromJS, Map } from 'immutable';
import { last } from 'lodash';
import { render, fireEvent, waitFor } from '@testing-library/react'; import { render, fireEvent, waitFor } from '@testing-library/react';
import { NetlifyCmsWidgetRelation } from '../'; import { NetlifyCmsWidgetRelation } from '../';
@ -85,6 +84,10 @@ const generateHits = length => {
collection: 'posts', collection: 'posts',
data: { title: 'YAML post', slug: 'post-yaml', body: 'Body yaml' }, data: { title: 'YAML post', slug: 'post-yaml', body: 'Body yaml' },
}, },
{
collection: 'posts',
data: { title: 'JSON post', slug: 'post-json', body: 'Body json' },
},
]; ];
}; };
@ -166,12 +169,14 @@ class RelationController extends React.Component {
hits = nestedFileCollectionHits; hits = nestedFileCollectionHits;
} else if (file === 'simple_file') { } else if (file === 'simple_file') {
hits = simpleFileCollectionHits; hits = simpleFileCollectionHits;
} else if (term === 'YAML') { } else if (term === 'JSON post') {
hits = [last(queryHits)]; hits = [queryHits[queryHits.length - 1]];
} else if (term === 'Nested') { } else if (term === 'YAML' || term === 'YAML post') {
hits = [queryHits[queryHits.length - 2]]; hits = [queryHits[queryHits.length - 2]];
} else if (term === 'Deeply nested') { } else if (term === 'Nested') {
hits = [queryHits[queryHits.length - 3]]; hits = [queryHits[queryHits.length - 3]];
} else if (term === 'Deeply nested') {
hits = [queryHits[queryHits.length - 4]];
} }
hits = hits.slice(0, optionsLength); hits = hits.slice(0, optionsLength);
@ -411,24 +416,23 @@ describe('Relation widget', () => {
it('should update metadata for initial preview', async () => { it('should update metadata for initial preview', async () => {
const field = fromJS({ ...fieldConfig, multiple: true }); const field = fromJS({ ...fieldConfig, multiple: true });
const value = fromJS(['Post # 1', 'Post # 2']); const value = fromJS(['YAML post', 'JSON post']);
const { getByText, onChangeSpy, setQueryHitsSpy } = setup({ field, value }); const { getByText, onChangeSpy } = setup({ field, value });
const metadata1 = { const metadata = {
post: { posts: { 'Post # 1': { title: 'Post # 1', slug: 'post-number-1' } } }, post: {
posts: {
'YAML post': { title: 'YAML post', slug: 'post-yaml', body: 'Body yaml' },
'JSON post': { title: 'JSON post', slug: 'post-json', body: 'Body json' },
},
},
}; };
const metadata2 = {
post: { posts: { 'Post # 2': { title: 'Post # 2', slug: 'post-number-2' } } },
};
setQueryHitsSpy(generateHits(2));
await waitFor(() => { await waitFor(() => {
expect(getByText('Post # 1 post-number-1')).toBeInTheDocument(); expect(getByText('YAML post post-yaml')).toBeInTheDocument();
expect(getByText('Post # 2 post-number-2')).toBeInTheDocument(); expect(getByText('JSON post post-json')).toBeInTheDocument();
expect(onChangeSpy).toHaveBeenCalledTimes(2); expect(onChangeSpy).toHaveBeenCalledTimes(1);
expect(onChangeSpy).toHaveBeenCalledWith(value, metadata1); expect(onChangeSpy).toHaveBeenCalledWith(value, metadata);
expect(onChangeSpy).toHaveBeenCalledWith(value, metadata2);
}); });
}); });
}); });