Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor: Avoid scheduling autosave if same edit reference as last completion #12624

Merged
merged 1 commit into from
Feb 14, 2019

Conversation

aduth
Copy link
Member

@aduth aduth commented Dec 5, 2018

Fixes #12318

This pull request seeks to resolve an issue where autosaves will repeatedly occur when an edit is made to a published post. As explained in #12318 (comment) , this is a consequence of a published post's autosave occurring as a revision, not a proper save. The post is still in an "unsaved" state, in the sense that the user has not yet Updated the post.

With these changes, an autosave will not be scheduled after a prior autosave had completed until an explicit edit occurs, even if the post is dirty or autosaveable.

Implementation notes:

For posterity's sake, there are some specific intricacies of the autosave flow which may appear to be redundant with the logic included here, but which still serve an independent role. Namely, the re-dirtying of an autosaved published post performed as a consequence of:

optimist: {
// Note: REVERT is not a failure case here. Rather, it
// is simply reversing the assumption that the updates
// were applied to the post proper, such that the post
// treated as having unsaved changes.
type: isRevision ? REVERT : COMMIT,
id: POST_UPDATE_TRANSACTION_ID,
},

/**
* Returns true if there are unsaved values for the current edit session, or
* false if the editing state matches the saved or new post.
*
* @param {Object} state Global application state.
*
* @return {boolean} Whether unsaved values exist.
*/
export function isEditedPostDirty( state ) {
if ( hasChangedContent( state ) ) {
return true;
}
// Edits should contain only fields which differ from the saved post (reset
// at initial load and save complete). Thus, a non-empty edits state can be
// inferred to contain unsaved values.
if ( Object.keys( state.editor.present.edits ).length > 0 ) {
return true;
}
// Edits and change detectiona are reset at the start of a save, but a post
// is still considered dirty until the point at which the save completes.
// Because the save is performed optimistically, the prior states are held
// until committed. These can be referenced to determine whether there's a
// chance that state may be reverted into one considered dirty.
return inSomeHistory( state, isEditedPostDirty );
}

To reiterate, it is correct that a post is considered dirty after a published post is autosaved. The user should be prompted when attempting to navigate away. It's because of this distinction that an additional "has autosaved for edits reference" is included here.

It may, however, be worth considering for future refactoring to remove the isEditedPostAutosaveable selector in favor of dirtiness conditions, or reflecting the last autosave which had occurred. Currently, the recurring autosave occurs because hasChangedContent will return true due to the re-dirtying behavior described above.

Testing instructions:

Repeat steps to reproduce from #12318, verifying by Network DevTools activity that only a single autosave occurs for a single edit to a published post.

Verify that after an autosave occurs, continued edits will still autosave.

Pending:

This is worth testing via an end-to-end test.

@aduth aduth force-pushed the fix/12318-published-autosave branch from 10ee732 to fdd44b2 Compare December 18, 2018 21:54
@aduth aduth force-pushed the fix/12318-published-autosave branch from fdd44b2 to 93d3027 Compare January 9, 2019 14:20
@aduth aduth requested a review from a team January 9, 2019 19:04
Copy link
Member

@tofumatt tofumatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kinda confusing logic to follow and I don't quite understand the test, but maybe if explained a bit more I would. The code seems fine but I don't grok the test.

// Once edit occurs after autosave, resume scheduling.
wrapper.setProps( { isDirty: true, isAutosaving: false, isAutosaveable: true, editsReference: afterReference } );

expect( toggleTimer ).toHaveBeenCalledWith( false );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm mis-reading the test, but I would expect this to test for something different. Now the post is dirty, isn't autosaving, is autosavable, and has a different editsReference, but the expectation is the same.

I don't quite follow 🤷‍♂️

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm mis-reading the test, but I would expect this to test for something different.

You're totally right. We expect toggleTimer to have been called with true, which it is, but as written toHaveBeenCalledWith would consider both this and the prior invocation (since we didn't clear mock calls between). So while it's true that it had been called with false, this was not what we're testing.

I've updated the test so that it explicitly checks that the second time around, it's called with true.

@tofumatt tofumatt requested a review from a team January 9, 2019 20:15
@aduth aduth force-pushed the fix/12318-published-autosave branch from 93d3027 to 6a91586 Compare January 24, 2019 17:58
@gziolo gziolo added this to the 5.1 (Gutenberg) milestone Feb 7, 2019
@aduth
Copy link
Member Author

aduth commented Feb 12, 2019

In case it has an impact on how people prioritize reviewing this: Without this change, published posts will currently autosave infinitely after an initial change is made to a block.

@gziolo gziolo added the [Priority] High Used to indicate top priority items that need quick attention label Feb 13, 2019
@@ -53,6 +73,7 @@ export default compose( [
isDirty: isEditedPostDirty(),
isAutosaveable: isEditedPostAutosaveable(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It definitely does feel like this selector is useless or doesn't have the same meaning as its name.

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix.

@youknowriad youknowriad added the [Type] Bug An existing feature does not function as intended label Feb 13, 2019
@youknowriad youknowriad merged commit 51ccfe6 into master Feb 14, 2019
@youknowriad youknowriad deleted the fix/12318-published-autosave branch February 14, 2019 08:21
This was referenced Apr 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Saving Related to saving functionality [Priority] High Used to indicate top priority items that need quick attention [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Autosave continues to trigger for published posts when no changes applied
5 participants