diff --git a/packages/netlify-cms-widget-relation/src/RelationControl.js b/packages/netlify-cms-widget-relation/src/RelationControl.js index d9fb17e8..8ba3e100 100644 --- a/packages/netlify-cms-widget-relation/src/RelationControl.js +++ b/packages/netlify-cms-widget-relation/src/RelationControl.js @@ -73,7 +73,6 @@ function getSelectedValue({ value, options, isMultiple }) { } export default class RelationControl extends React.Component { - didInitialSearch = false; mounted = false; 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 // this is required since each search is limited by optionsLength so the selected value // 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 file = field.get('file'); - const initialSearchValues = this.isMultiple() ? getSelectedOptions(value) : [value]; + const initialSearchValues = value && (this.isMultiple() ? getSelectedOptions(value) : [value]); if (initialSearchValues && initialSearchValues.length > 0) { + const metadata = {}; const allOptions = await Promise.all( initialSearchValues.map((v, index) => { return query(forID, collection, [field.get('valueField')], v, file, 1).then( ({ payload }) => { const hits = payload.response?.hits || []; const options = this.parseHitOptions(hits); + metadata[v] = hits[0]?.data; return { options, index }; }, ); @@ -127,6 +128,13 @@ export default class RelationControl extends React.Component { ...sortBy(allOptions, ({ index }) => index).map(({ options }) => options), ); 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; } - 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 => { const { onChange, field } = this.props; let value; diff --git a/packages/netlify-cms-widget-relation/src/__tests__/relation.spec.js b/packages/netlify-cms-widget-relation/src/__tests__/relation.spec.js index d2401933..98f80ede 100644 --- a/packages/netlify-cms-widget-relation/src/__tests__/relation.spec.js +++ b/packages/netlify-cms-widget-relation/src/__tests__/relation.spec.js @@ -1,6 +1,5 @@ import React from 'react'; import { fromJS, Map } from 'immutable'; -import { last } from 'lodash'; import { render, fireEvent, waitFor } from '@testing-library/react'; import { NetlifyCmsWidgetRelation } from '../'; @@ -85,6 +84,10 @@ const generateHits = length => { collection: 'posts', 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; } else if (file === 'simple_file') { hits = simpleFileCollectionHits; - } else if (term === 'YAML') { - hits = [last(queryHits)]; - } else if (term === 'Nested') { + } else if (term === 'JSON post') { + hits = [queryHits[queryHits.length - 1]]; + } else if (term === 'YAML' || term === 'YAML post') { hits = [queryHits[queryHits.length - 2]]; - } else if (term === 'Deeply nested') { + } else if (term === 'Nested') { hits = [queryHits[queryHits.length - 3]]; + } else if (term === 'Deeply nested') { + hits = [queryHits[queryHits.length - 4]]; } hits = hits.slice(0, optionsLength); @@ -411,24 +416,23 @@ describe('Relation widget', () => { it('should update metadata for initial preview', async () => { const field = fromJS({ ...fieldConfig, multiple: true }); - const value = fromJS(['Post # 1', 'Post # 2']); - const { getByText, onChangeSpy, setQueryHitsSpy } = setup({ field, value }); - const metadata1 = { - post: { posts: { 'Post # 1': { title: 'Post # 1', slug: 'post-number-1' } } }, + const value = fromJS(['YAML post', 'JSON post']); + const { getByText, onChangeSpy } = setup({ field, value }); + const metadata = { + 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(() => { - expect(getByText('Post # 1 post-number-1')).toBeInTheDocument(); - expect(getByText('Post # 2 post-number-2')).toBeInTheDocument(); + expect(getByText('YAML post post-yaml')).toBeInTheDocument(); + expect(getByText('JSON post post-json')).toBeInTheDocument(); - expect(onChangeSpy).toHaveBeenCalledTimes(2); - expect(onChangeSpy).toHaveBeenCalledWith(value, metadata1); - expect(onChangeSpy).toHaveBeenCalledWith(value, metadata2); + expect(onChangeSpy).toHaveBeenCalledTimes(1); + expect(onChangeSpy).toHaveBeenCalledWith(value, metadata); }); }); });