From 2409323dba1abe8a670d18453369fd75c6e240fb Mon Sep 17 00:00:00 2001 From: Erez Rokah Date: Mon, 16 Mar 2020 20:48:49 +0100 Subject: [PATCH] fix: call createDraftFromEntry after entry is loaded instead in Editor (#3418) * fix: call createDraftFromEntry after entry is loaded instead in Editor --- .../__tests__/editorialWorkflow.spec.js | 16 ++++++- .../src/actions/editorialWorkflow.ts | 3 +- .../netlify-cms-core/src/actions/entries.ts | 42 +++++++++---------- .../src/components/Editor/Editor.js | 21 +--------- .../Editor/__tests__/Editor.spec.js | 29 ------------- .../src/reducers/entryDraft.js | 7 +--- 6 files changed, 41 insertions(+), 77 deletions(-) diff --git a/packages/netlify-cms-core/src/actions/__tests__/editorialWorkflow.spec.js b/packages/netlify-cms-core/src/actions/__tests__/editorialWorkflow.spec.js index 32472ed7..9a99410b 100644 --- a/packages/netlify-cms-core/src/actions/__tests__/editorialWorkflow.spec.js +++ b/packages/netlify-cms-core/src/actions/__tests__/editorialWorkflow.spec.js @@ -64,7 +64,7 @@ describe('editorialWorkflow actions', () => { return store.dispatch(actions.loadUnpublishedEntry(collection, slug)).then(() => { const actions = store.getActions(); - expect(actions).toHaveLength(3); + expect(actions).toHaveLength(4); expect(actions[0]).toEqual({ type: 'UNPUBLISHED_ENTRY_REQUEST', payload: { @@ -80,6 +80,12 @@ describe('editorialWorkflow actions', () => { entry: { ...entry, mediaFiles: [{ file: { name: 'name' }, id: '1', draft: true }] }, }, }); + expect(actions[3]).toEqual({ + type: 'DRAFT_CREATE_FROM_ENTRY', + payload: { + entry, + }, + }); }); }); }); @@ -111,7 +117,7 @@ describe('editorialWorkflow actions', () => { return store.dispatch(actions.publishUnpublishedEntry('posts', slug)).then(() => { const actions = store.getActions(); - expect(actions).toHaveLength(6); + expect(actions).toHaveLength(7); expect(actions[0]).toEqual({ type: 'UNPUBLISHED_ENTRY_PUBLISH_REQUEST', @@ -155,6 +161,12 @@ describe('editorialWorkflow actions', () => { collection: 'posts', }, }); + expect(actions[6]).toEqual({ + type: 'DRAFT_CREATE_FROM_ENTRY', + payload: { + entry, + }, + }); }); }); diff --git a/packages/netlify-cms-core/src/actions/editorialWorkflow.ts b/packages/netlify-cms-core/src/actions/editorialWorkflow.ts index ea0ac630..8fe26f8d 100644 --- a/packages/netlify-cms-core/src/actions/editorialWorkflow.ts +++ b/packages/netlify-cms-core/src/actions/editorialWorkflow.ts @@ -15,7 +15,7 @@ import { import { selectFields } from '../reducers/collections'; import { EDITORIAL_WORKFLOW, status, Status } from '../constants/publishModes'; import { EDITORIAL_WORKFLOW_ERROR } from 'netlify-cms-lib-util'; -import { loadEntry, entryDeleted, getMediaAssets } from './entries'; +import { loadEntry, entryDeleted, getMediaAssets, createDraftFromEntry } from './entries'; import { createAssetProxy } from '../valueObjects/AssetProxy'; import { addAssets } from './media'; import { loadMedia } from './mediaLibrary'; @@ -290,6 +290,7 @@ export function loadUnpublishedEntry(collection: Collection, slug: string) { } dispatch(unpublishedEntryLoaded(collection, { ...entry, mediaFiles })); + dispatch(createDraftFromEntry(entry)); } catch (error) { if (error.name === EDITORIAL_WORKFLOW_ERROR && error.notUnderEditorialWorkflow) { dispatch(unpublishedEntryRedirected(collection, slug)); diff --git a/packages/netlify-cms-core/src/actions/entries.ts b/packages/netlify-cms-core/src/actions/entries.ts index ba3a1f29..2afc881b 100644 --- a/packages/netlify-cms-core/src/actions/entries.ts +++ b/packages/netlify-cms-core/src/actions/entries.ts @@ -201,10 +201,10 @@ export function emptyDraftCreated(entry: EntryValue) { /* * Exported simple Action Creators */ -export function createDraftFromEntry(entry: EntryMap, metadata?: Map) { +export function createDraftFromEntry(entry: EntryValue) { return { type: DRAFT_CREATE_FROM_ENTRY, - payload: { entry, metadata }, + payload: { entry }, }; } @@ -339,25 +339,25 @@ export function loadEntry(collection: Collection, slug: string) { const backend = currentBackend(state.config); await waitForMediaLibraryToLoad(dispatch, getState()); dispatch(entryLoading(collection, slug)); - return backend - .getEntry(getState(), collection, slug) - .then((loadedEntry: EntryValue) => { - return dispatch(entryLoaded(collection, loadedEntry)); - }) - .catch((error: Error) => { - console.error(error); - dispatch( - notifSend({ - message: { - details: error.message, - key: 'ui.toast.onFailToLoadEntries', - }, - kind: 'danger', - dismissAfter: 8000, - }), - ); - dispatch(entryLoadError(error, collection, slug)); - }); + + try { + const loadedEntry = await backend.getEntry(getState(), collection, slug); + dispatch(entryLoaded(collection, loadedEntry)); + dispatch(createDraftFromEntry(loadedEntry)); + } catch (error) { + console.error(error); + dispatch( + notifSend({ + message: { + details: error.message, + key: 'ui.toast.onFailToLoadEntries', + }, + kind: 'danger', + dismissAfter: 8000, + }), + ); + dispatch(entryLoadError(error, collection, slug)); + } }; } diff --git a/packages/netlify-cms-core/src/components/Editor/Editor.js b/packages/netlify-cms-core/src/components/Editor/Editor.js index f915ded8..f11f8bb0 100644 --- a/packages/netlify-cms-core/src/components/Editor/Editor.js +++ b/packages/netlify-cms-core/src/components/Editor/Editor.js @@ -10,7 +10,6 @@ import { logoutUser } from 'Actions/auth'; import { loadEntry, loadEntries, - createDraftFromEntry, createDraftDuplicateFromEntry, createEmptyDraft, discardDraft, @@ -30,7 +29,6 @@ import { deleteUnpublishedEntry, } from 'Actions/editorialWorkflow'; import { loadDeployPreview } from 'Actions/deploys'; -import { deserializeValues } from 'Lib/serializeEntryValues'; import { selectEntry, selectUnpublishedEntry, selectDeployPreview } from 'Reducers'; import { selectFields } from 'Reducers/collections'; import { status, EDITORIAL_WORKFLOW } from 'Constants/publishModes'; @@ -48,7 +46,6 @@ export class Editor extends React.Component { changeDraftField: PropTypes.func.isRequired, changeDraftFieldValidation: PropTypes.func.isRequired, collection: ImmutablePropTypes.map.isRequired, - createDraftFromEntry: PropTypes.func.isRequired, createDraftDuplicateFromEntry: PropTypes.func.isRequired, createEmptyDraft: PropTypes.func.isRequired, discardDraft: PropTypes.func.isRequired, @@ -198,18 +195,9 @@ export class Editor extends React.Component { if (prevProps.entry === this.props.entry) return; - const { entry, newEntry, fields, collection } = this.props; + const { newEntry, collection } = this.props; - if (entry && !entry.get('isFetching') && !entry.get('error')) { - /** - * Deserialize entry values for widgets with registered serializers before - * creating the entry draft. - */ - const values = deserializeValues(entry.get('data'), fields); - const deserializedEntry = entry.set('data', values); - const fieldsMetaData = this.props.entryDraft && this.props.entryDraft.get('fieldsMetaData'); - this.createDraft(deserializedEntry, fieldsMetaData); - } else if (newEntry) { + if (newEntry) { prevProps.createEmptyDraft(collection, this.props.location.search); } } @@ -224,10 +212,6 @@ export class Editor extends React.Component { this.props.persistLocalBackup(entry, collection); }, 2000); - createDraft = (entry, metadata) => { - if (entry) this.props.createDraftFromEntry(entry, metadata); - }; - handleChangeDraftField = (field, value, metadata) => { const entries = [this.props.unPublishedEntry, this.props.publishedEntry].filter(Boolean); this.props.changeDraftField(field, value, metadata, entries); @@ -509,7 +493,6 @@ const mapDispatchToProps = { retrieveLocalBackup, persistLocalBackup, deleteLocalBackup, - createDraftFromEntry, createDraftDuplicateFromEntry, createEmptyDraft, discardDraft, diff --git a/packages/netlify-cms-core/src/components/Editor/__tests__/Editor.spec.js b/packages/netlify-cms-core/src/components/Editor/__tests__/Editor.spec.js index 6e0f3490..5c1f2217 100644 --- a/packages/netlify-cms-core/src/components/Editor/__tests__/Editor.spec.js +++ b/packages/netlify-cms-core/src/components/Editor/__tests__/Editor.spec.js @@ -25,7 +25,6 @@ describe('Editor', () => { changeDraftField: jest.fn(), changeDraftFieldValidation: jest.fn(), collection: fromJS({ name: 'posts' }), - createDraftFromEntry: jest.fn(), createDraftDuplicateFromEntry: jest.fn(), createEmptyDraft: jest.fn(), discardDraft: jest.fn(), @@ -215,32 +214,4 @@ describe('Editor', () => { props.collection, ); }); - - it('should create draft from entry when done fetching', () => { - const { rerender } = render( - , - ); - - jest.clearAllMocks(); - rerender( - , - ); - - expect(props.createDraftFromEntry).toHaveBeenCalledTimes(1); - expect(props.createDraftFromEntry).toHaveBeenCalledWith( - fromJS({ isFetching: false, data: {}, mediaFiles: [{ id: '1' }] }), - fromJS({}), - ); - }); }); diff --git a/packages/netlify-cms-core/src/reducers/entryDraft.js b/packages/netlify-cms-core/src/reducers/entryDraft.js index 6b28051e..fea29792 100644 --- a/packages/netlify-cms-core/src/reducers/entryDraft.js +++ b/packages/netlify-cms-core/src/reducers/entryDraft.js @@ -36,12 +36,9 @@ const entryDraftReducer = (state = Map(), action) => { case DRAFT_CREATE_FROM_ENTRY: // Existing Entry return state.withMutations(state => { - state.set('entry', action.payload.entry); + state.set('entry', fromJS(action.payload.entry)); state.setIn(['entry', 'newRecord'], false); - // An existing entry may already have metadata. If we surfed away and back to its - // editor page, the metadata will have been fetched already, so we shouldn't - // clear it as to not break relation lists. - state.set('fieldsMetaData', action.payload.metadata || Map()); + state.set('fieldsMetaData', Map()); state.set('fieldsErrors', Map()); state.set('hasChanged', false); state.set('key', uuid());