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

🐛 Fixed unsaved changes confirmation on Lexical schema change #20687

Merged
merged 23 commits into from
Aug 5, 2024

Conversation

ronaldlangeveld
Copy link
Member

@ronaldlangeveld ronaldlangeveld commented Jul 30, 2024

refs ENG-661

Fixes a long-standing issue where an outdated Lexical schema in the database triggered the unsaved changes confirmation dialog incorrectly.
Implemented a secondary hidden Lexical instance that loads the state from the database, renders it, and uses this updated state to compare with the live editor's scratch.
This ensures the unsaved changes prompt appears only when there are real changes from the user.

@github-actions github-actions bot added the affects:admin Anything relating to Ghost Admin label Jul 30, 2024
@ronaldlangeveld ronaldlangeveld changed the title [WIP] Koenig double instance rendering 🐛 Fixed unsaved changes confirmation on Lexical schema change Aug 1, 2024
placeholderText={this.args.placeholder}
darkMode={this.feature.nightShift}
onChange={isInitInstance ? e => handleInitInstance(e) : this.args.onChange}
registerAPI={this.args.registerAPI}
Copy link
Member

Choose a reason for hiding this comment

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

We'll want to make sure this doesn't get registered for the secondary instance otherwise we won't have a stable reference to the main editor

Comment on lines 704 to 705
<WordCountPlugin editorResource={this.editorResource} onChange={this.args.updateWordCount} />
<TKCountPlugin editorResource={this.editorResource} onChange={this.args.updatePostTkCount} />
Copy link
Member

Choose a reason for hiding this comment

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

Same for both of these, we don't want the secondary instance interacting with any of the outside world aside from the main content onChange handler

Comment on lines 676 to 678
if (this.args.initLexical && isInitInstance && !hasInitialised) {
this.args.initLexical(data);
setHasInitialised(true);
Copy link
Member

@kevinansfield kevinansfield Aug 1, 2024

Choose a reason for hiding this comment

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

Why do we need hasInitialised here? One of the issues Steve ran into is that the changes made when opening the editor come in batches so we can't guarantee that only the first onChange call is the one we want - if we could rely on that then we could use the first call's data from the main editor instance rather than needing a secondary instance

@@ -404,6 +404,12 @@ export default class LexicalEditorController extends Controller {
this.set('postTkCount', count);
}

@action
initLexical(data) {
this.post.set('lexical', JSON.stringify(data));
Copy link
Member

@kevinansfield kevinansfield Aug 1, 2024

Choose a reason for hiding this comment

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

I don't think we should be updating the post's lexical data otherwise we're in the same position as before but we're masking it by setting hasDirtyAttributes to false which may not be correct! Aside from indirectly masking the problem it also means the model immediately has dirty attributes so we can no longer use that as part of our dirty checks.

The idea of having the secondary instance was so we can add a new property that contains the modified-on-init data that we can compare against inside our _hasDirtyAttributes() function

@ronaldlangeveld ronaldlangeveld marked this pull request as ready for review August 3, 2024 05:17
if (post.get('isError')) {
this._leaveModalReason = {reason: 'isError', context: post.errors.messages};
return true;
}

// post.tags is an array so hasDirtyAttributes doesn't pick up
// changes unless the array ref is changed
// Post tags comparison
Copy link
Member

Choose a reason for hiding this comment

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

Can we switch back to the comments that explain why this is necessary rather than a comment that just tells you what the code is doing?

Copy link
Member

@kevinansfield kevinansfield left a comment

Choose a reason for hiding this comment

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

Added a minor thing about code comments being replaced with less-useful comments but otherwise the functionality all looks good! 🙌

@ronaldlangeveld ronaldlangeveld enabled auto-merge (squash) August 5, 2024 12:58
@ronaldlangeveld ronaldlangeveld merged commit c8ba9e8 into main Aug 5, 2024
19 checks passed
@ronaldlangeveld ronaldlangeveld deleted the wip-double-instance-kg branch August 5, 2024 12:58
cmraible added a commit to cmraible/Ghost that referenced this pull request Aug 16, 2024
ronaldlangeveld added a commit that referenced this pull request Aug 17, 2024
refs ENG-661

Fixes a long-standing issue where an outdated Lexical schema in the
database triggered the unsaved changes confirmation dialog incorrectly.
Implemented a secondary hidden Lexical instance that loads the state
from the database, renders it, and uses this updated state to compare
with the live editor's scratch.
This ensures the unsaved changes prompt appears only when there are real
changes from the user.
kevinansfield added a commit that referenced this pull request Aug 19, 2024
ref [ENG-661](https://linear.app/tryghost/issue/ENG-661/) 
ref [ONC-253](https://linear.app/tryghost/issue/ONC-253/)
ref [PLG-174](https://linear.app/tryghost/issue/PLG-174/)

- restored the original but reverted fix for unsaved changes modal from #20687
- updated code to remove some incorrect early-falsy-return logic in `editorController.hasDirtyAttributes` that prevented save of unsaved changes on the underlying model (e.g. excerpt)
- updated unit tests so they are testing real post model instances and therefore are testing what we expect them to test
- added acceptance tests to ensure autosave is working for title and excerpt fields

---------

Co-authored-by: Ronald Langeveld <[email protected]>
kevinansfield added a commit that referenced this pull request Aug 20, 2024
ref [ENG-661](https://linear.app/tryghost/issue/ENG-661/) 
ref [ONC-253](https://linear.app/tryghost/issue/ONC-253/)
ref [PLG-174](https://linear.app/tryghost/issue/PLG-174/)

- restored the original but reverted fix for unsaved changes modal from #20687
- updated code to remove some incorrect early-falsy-return logic in `editorController.hasDirtyAttributes` that prevented save of unsaved changes on the underlying model (e.g. excerpt)
- updated unit tests so they are testing real post model instances and therefore are testing what we expect them to test
- added acceptance tests to ensure autosave is working for title and excerpt fields

---------

Co-authored-by: Ronald Langeveld <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
affects:admin Anything relating to Ghost Admin
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants