Framework: Handle and upgrade deprecated blocks#3665
Conversation
Codecov Report
@@ Coverage Diff @@
## master #3665 +/- ##
==========================================
- Coverage 37.74% 37.47% -0.28%
==========================================
Files 279 277 -2
Lines 6743 6709 -34
Branches 1227 1219 -8
==========================================
- Hits 2545 2514 -31
Misses 3536 3536
+ Partials 662 659 -3
Continue to review full report at Codecov.
|
blocks/api/parser.js
Outdated
| // as invalid, or future serialization attempt results in an error | ||
| block.originalContent = innerHTML; | ||
|
|
||
| // If the block is invalid, try to find an older compatible version |
There was a problem hiding this comment.
Maybe expand a bit on this comment, as it's important to understand why.
Quick one:
When a block is invalid, attempt to validate again using a supplied `deprecated` definition.
This allows blocks to modify their attribute and markup structure without invalidating
content written in previous formats.
| icon: 'format-quote', | ||
| category: 'common', | ||
|
|
||
| attributes: { |
There was a problem hiding this comment.
Why move this away?
To address this, it's because the deprecated and original versions share most of the same attributes, with deprecated assigning into to reflect the original attributes behavior of citation.
There was a problem hiding this comment.
I have concerns with block looking different at first sight when you open one to learn from, that i think we should minimize.
blocks/library/quote/index.js
Outdated
| ); | ||
| }, | ||
|
|
||
| deprecatedVersions: [ |
There was a problem hiding this comment.
Sounds good to me
| deprecatedVersions: [ | ||
| { | ||
| attributes: { | ||
| ...blockAttributes, |
There was a problem hiding this comment.
I see. This is the kind of thing I think we should standardize. :)
| }, | ||
| }, | ||
|
|
||
| save( { attributes } ) { |
There was a problem hiding this comment.
I have a slight concern with accumulating save mechanisms just for validation, but I don't see an alternative. Might be worth moving all the deprecated definitions into a deprecated.js file to not burden the main js with additional save definitions.
There was a problem hiding this comment.
What about the "attributes"? do you think we should share common attributes or maybe fine to duplicate?
|
I like this approach a lot more. |
39583ed to
37de716
Compare
|
@youknowriad another side thing, I'd like to use this opportunity to change the class names used for the quote styles to be |
|
@mtias Yep, sounds like a good idea. The |
|
I'd be ok with introducing here if it serves a good testing purpose. |
| return ( | ||
| <blockquote | ||
| className={ `blocks-quote-style-${ style }` } | ||
| className={ style === 2 ? 'is-large' : '' } |
There was a problem hiding this comment.
I think we could use default and large for the attribute itself? Or undefined and large maybe.
There was a problem hiding this comment.
mmm, this means the value of the attribute can change between two versions, I'm going to introduce a migrate function to handle this
There was a problem hiding this comment.
Mmm, can it be handled in the attribute itself as a fallback?
There was a problem hiding this comment.
We might want to sit on it a bit otherwise.
There was a problem hiding this comment.
No, we can't :(. Adding it is not so complex though 5dd81ce
There was a problem hiding this comment.
Let's extract that commit into a separate PR so we can discuss the migration of values in isolation.
blocks/api/parser.js
Outdated
| let attributesParsedWithDeprecatedVersion; | ||
| const hasValidOlderVersion = find( blockType.deprecated, ( oldBlockType ) => { | ||
| const deprecatedBlockType = { | ||
| ...omit( blockType, [ 'attributes', 'save', 'supports' ] ), // Parsing/Serialization properties |
There was a problem hiding this comment.
Do we need to omit here, or is it enough that the spread will override those properties?
There was a problem hiding this comment.
Yes, we do because some of these properties are optional and we do not want to copy them in the old block's definition.
blocks/api/parser.js
Outdated
| // as invalid, or future serialization attempt results in an error | ||
| block.originalContent = innerHTML; | ||
|
|
||
| // When a block is invalid, attempt to validate again using a supplied `deprecated` definition. |
There was a problem hiding this comment.
Should we extract this logic to a separate function, or would it be possible to take advantage of recursion here in returning via createBlockWithFallback using the deprecated block attempt attributes in place of the original?
There was a problem hiding this comment.
Thanks for the suggestion Andrew, the code is better now. I preferred to avoid recursion because the logic is a bit simpler than createBlockWithFallback and it may include a specific "migrate" call in the future #3673
blocks/api/parser.js
Outdated
| // content written in previous formats. | ||
| if ( ! block.isValid && blockType.deprecated ) { | ||
| let attributesParsedWithDeprecatedVersion; | ||
| const hasValidOlderVersion = find( blockType.deprecated, ( oldBlockType ) => { |
There was a problem hiding this comment.
Array#some (or Lodash's equivalent) would be a more appropriate method here, since we don't care about the found value, just that it exists.
blocks/api/parser.js
Outdated
| }; | ||
| const deprecatedBlockAttributes = getBlockAttributes( deprecatedBlockType, innerHTML, attributes ); | ||
| const isValid = isValidBlock( innerHTML, deprecatedBlockType, deprecatedBlockAttributes ); | ||
| attributesParsedWithDeprecatedVersion = isValid ? deprecatedBlockAttributes : undefined; |
There was a problem hiding this comment.
If we did extract this to a separate method, I could see this working well as an early return from a loop:
for ( let i = 0; i < deprecated.length; i++ ) {
// ...
if ( isValid ) {
return deprecatedBlockAttributes;
}
}9240a66 to
e6393ac
Compare
aduth
left a comment
There was a problem hiding this comment.
Overall this looks good to me.
Two things I noted in testing:
- The validation error for the original attempt shows even when there is a deprecated version available. This might be okay.
- I added a
{"style":2}block topost-content.jsand it didn't upgrade to apply theis-largeclass name.
Try:
'<!-- wp:quote {"style":2} -->',
'<blockquote class="wp-block-quote blocks-quote-style-2"><p>The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.</p><footer>Matt Mullenweg, 2017</footer></blockquote>',
'<!-- /wp:quote -->',| setUnknownTypeHandlerName, | ||
| } from '../registration'; | ||
|
|
||
| const expectFailingBlockValidation = () => { |
There was a problem hiding this comment.
Aside: I had a similar need for validation tests, wondering if we ought to put the effort into a generalized "expect console errors" assertion:
gutenberg/blocks/api/test/validation.js
Lines 33 to 43 in 9bfd837
Maybe expect( console ).toHaveLogged( 'error' ); set up in test/unit/setup-test-framework.js?
https://facebook.github.io/jest/docs/en/expect.html#expectextendmatchers
cc @gziolo
There was a problem hiding this comment.
Nice idea! We are spying already on console warn and error methods: https://github.com/WordPress/gutenberg/blob/master/test/unit/setup-test-framework.js#L25. It should be easy to inplement 👍
blocks/api/test/parser.js
Outdated
| selector: 'div', | ||
| }, | ||
| }, | ||
| save: ( { attributes } ) => <div>{attributes.fruit}</div>, |
There was a problem hiding this comment.
Hmm, we have this rule, but it is not capturing this:
https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md
We should seek to include whitespace inside the curly for these cases for consistency with similar rules.
| icon: 'format-quote', | ||
| category: 'common', | ||
|
|
||
| attributes: { |
There was a problem hiding this comment.
Why move this away?
To address this, it's because the deprecated and original versions share most of the same attributes, with deprecated assigning into to reflect the original attributes behavior of citation.
e6393ac to
5a1ef20
Compare
It did upgrade for me with this exact same code, what am I missing here? |
You mean the visual dialog prompting the user or in console? |
5a1ef20 to
bd6f99c
Compare
|
I'm merging this one to include it in the release. It's working for me, can't reproduce the failing use-case |
|
I can't reproduce my originally reported issue on master. Maybe a fluke 👍 |
refs #2541 alternative to #3327
Instead of adding a "version" to the block comment and upgrading blocks version by version, this uses a simpler alternative where:
save,attributesandsupport)Testing instructions
citeand you can still edit the block as expected in the visual editor