-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Block Editor: Consider received blocks state change as ignored #14916
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -188,16 +188,6 @@ export function isUpdatingSameBlockAttribute( action, lastAction ) { | |
function withPersistentBlockChange( reducer ) { | ||
let lastAction; | ||
|
||
/** | ||
* Set of action types for which a blocks state change should be considered | ||
* non-persistent. | ||
* | ||
* @type {Set} | ||
*/ | ||
const IGNORED_ACTION_TYPES = new Set( [ | ||
'RECEIVE_BLOCKS', | ||
] ); | ||
|
||
return ( state, action ) => { | ||
let nextState = reducer( state, action ); | ||
|
||
|
@@ -206,19 +196,14 @@ function withPersistentBlockChange( reducer ) { | |
// Defer to previous state value (or default) unless changing or | ||
// explicitly marking as persistent. | ||
if ( state === nextState && ! isExplicitPersistentChange ) { | ||
return { | ||
...nextState, | ||
isPersistentChange: get( state, [ 'isPersistentChange' ], true ), | ||
}; | ||
} | ||
const nextIsPersistentChange = get( state, [ 'isPersistentChange' ], true ); | ||
if ( state.isPersistentChange === nextIsPersistentChange ) { | ||
return state; | ||
} | ||
|
||
// Some state changes should not be considered persistent, namely those | ||
// which are not a direct result of user interaction. | ||
const isIgnoredActionType = IGNORED_ACTION_TYPES.has( action.type ); | ||
if ( isIgnoredActionType ) { | ||
return { | ||
...nextState, | ||
isPersistentChange: false, | ||
isPersistentChange: nextIsPersistentChange, | ||
}; | ||
} | ||
|
||
|
@@ -239,6 +224,37 @@ function withPersistentBlockChange( reducer ) { | |
}; | ||
} | ||
|
||
/** | ||
* Higher-order reducer intended to augment the blocks reducer, assigning an | ||
* `isIgnoredChange` property value corresponding to whether a change in state | ||
* can be considered as ignored. A change is considered ignored when the result | ||
* of an action not incurred by direct user interaction. | ||
* | ||
* @param {Function} reducer Original reducer function. | ||
* | ||
* @return {Function} Enhanced reducer function. | ||
*/ | ||
function withIgnoredBlockChange( reducer ) { | ||
/** | ||
* Set of action types for which a blocks state change should be ignored. | ||
* | ||
* @type {Set} | ||
*/ | ||
const IGNORED_ACTION_TYPES = new Set( [ | ||
'RECEIVE_BLOCKS', | ||
] ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so for now is this just going to be a hardcoded list? Would there be value in being able to customize what action types are ignored? Eg. being able to call it like this: withIgnoredBlockChange( [ 'RECEIVE_BLOCKS' ] ) If so, and that's useful, then the name of the HOC could maybe be changed to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Re There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
So, considering all of the above: Our use of Long-term then: In the meantime though, this basically restores the behavior we had prior to #13088 rather faithfully (including all imperfections therein). |
||
|
||
return ( state, action ) => { | ||
const nextState = reducer( state, action ); | ||
|
||
if ( nextState !== state ) { | ||
nextState.isIgnoredChange = IGNORED_ACTION_TYPES.has( action.type ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so what is exactly the difference between isIgnoredChange and ! isPersistentChange? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From
From
Effectively: Non-persistent changes are still surfaced up to the rendering Editor, but treated as omitted from history. Ignored changes are not surfaced to the rendering Editor at all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I think I got it, while one is about the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (I replied to myself before I see your comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is a good summary of the problem. They're not the same. One is considered by If the question is whether "changes" should be a reflection of the presence of undo levels: I think long ago we had it this way, and it changed (presumably necessarily). Possibly as a result of some of the work to merge undo levels while still needing to consider them as changed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Thanks for the clarification, it makes sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think the reason we don't consider Undo levels as part of post dirtiness is because Undo history doesn't reset when a Save occurs, but the post is "clean". |
||
} | ||
|
||
return nextState; | ||
}; | ||
} | ||
|
||
/** | ||
* Higher-order reducer targeting the combined blocks reducer, augmenting | ||
* block client IDs in remove action to include cascade of inner blocks. | ||
|
@@ -380,6 +396,7 @@ export const blocks = flow( | |
withBlockReset, | ||
withSaveReusableBlock, | ||
withPersistentBlockChange, | ||
withIgnoredBlockChange, | ||
)( { | ||
byClientId( state = {}, action ) { | ||
switch ( action.type ) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -288,4 +288,21 @@ describe( 'Change detection', () => { | |
|
||
await assertIsDirty( true ); | ||
} ); | ||
|
||
it( 'should not prompt when receiving reusable blocks', async () => { | ||
// Regression Test: Verify that non-modifying behaviors does not incur | ||
// dirtiness. Previously, this could occur as a result of either (a) | ||
// selecting a block, (b) opening the inserter, or (c) editing a post | ||
// which contained a reusable block. The root issue was changes in | ||
// block editor state as a result of reusable blocks data having been | ||
// received, reflected here in this test. | ||
// | ||
// TODO: This should be considered a temporary test, existing only so | ||
// long as the experimental reusable blocks fetching data flow exists. | ||
// | ||
// See: https://github.com/WordPress/gutenberg/issues/14766 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very good comment block explaining things 👍 |
||
await page.evaluate( () => window.wp.data.dispatch( 'core/editor' ).__experimentalReceiveReusableBlocks( [] ) ); | ||
|
||
await assertIsDirty( false ); | ||
} ); | ||
} ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm... I didn't think __unstable or __experimental was supposed to show up in docs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It caught me off guard as well. I think they may only be omitted in documentation generated by the
docgen
tool. The data modules documentation is a separate process. It should be improved (I'll create a follow-up task).