-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Fix max upload size error message #4203
Conversation
247e67e
to
34534a1
Compare
Nice pre checking! Would it perhaps be nice to display the error on the block itself (locally), instead of at the top (globally)? |
Right now all our error/success messages go in one place, the top. I think having this also go there is for now right. We absolutely could consider what messages work for contextual, but that feels a different issue and shouldn't block this going in as is. |
@karmatosed We currently have some error messages that are block-specific that go in the block, such as JS errors and externally modified messages. |
Hmm, isn't it only JS errors though or external? I'm thinking from a UX perspective the 'message place' works at top for user information. So we can track this, do we have a record/list of all error messages and where they output? Would be a good exercise in seeing we're being consistent. |
E.g. create a list block, click the ellipsis, edit in HTML, remove the list HTML and add something else, then try to go back to visual. There will be a message with three action buttons. |
Would be good to have this. Ran into it with paste too. |
@@ -421,6 +422,7 @@ export class BlockListBlock extends Component { | |||
id={ block.uid } | |||
isSelectionEnabled={ this.props.isSelectionEnabled } | |||
toggleSelection={ this.props.toggleSelection } | |||
createErrorNotice={ this.props.createErrorNotice } |
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.
Code-wise it also seems cleaner to display the error within the block? This error does not apply to the whole page.
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.
Thank you for the feedback @iseulde, I will propose a version with a block-specific error 👍
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.
Awesome, thanks! :)
34534a1
to
64c67b3
Compare
Hi @karmatosed, @iseulde, I added a new mechanism so we can test a different approach using block level error notices. The errors are different from the existing block parsing error. In this case, the block should continue to work normally e.g in the gallery even if one image failed the upload I should be able to see and manage the other images or upload a different one. I will update screenshots so we can see the new approach. |
Just wondering out loud... What if the error notice is part of the block edit component, and we just have a standard class for the error notice (kind of like it is done in WP core now). Or it is a component similar to |
The problem with this approach is that each block would need to implement the management of the notices. E.g: keep the state of which notices are being shown, and provide functions to dismiss them and then pass this functions down to the generic component as props. This notices management logic would be repeated across the blocks needing notices. Right now it is not repeated e.g blocks just have a function to throw notices and then they don't have to handle them.
We can try to improve the visual, instead of rendering directly we can pass a prop that contains the rendered notices. The blocks can then choose to place them inside some specific part, for example, render inside the placeholders like in your first example ( I will try to provide a sample). But in the non-empty states ( e.g: a gallery with images where the upload of a new image failed.) the notices would still look similar to the example we have now. |
That makes sense. |
64c67b3
to
8a98a71
Compare
Hi @iseulde, this PR got updated so the notices feel more part of the block. Thank you for the feedback 👍 I added screenshots to the new design. The mechanism is still easy to use for block creators e.g: notices can be added with online to show them and another line to create a new message. |
blocks/library/gallery/index.js
Outdated
@@ -62,6 +62,10 @@ registerBlockType( 'core/gallery', { | |||
}, | |||
}, | |||
|
|||
supports: { | |||
notices: true, |
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.
Why is this needed? I'm not sure I understand this.
blocks/hooks/notices/index.js
Outdated
|
||
/** @inheritdoc */ | ||
render() { | ||
if ( ! hasBlockSupport( this.props.name, 'notices' ) ) { |
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.
From the previous comment, can't we always add the notices
props?
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.
Yes, it would be an option, the supports notices is just for the property to be opt-in, e.g: blocks just receive if they ask for it.
blocks/hooks/notices/index.js
Outdated
* | ||
* @param {string} id Id of the notice to remove. | ||
*/ | ||
removeNotice( id ) { |
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.
What happens when a block with a notice disappears? Does it just stay around here in the state? This is why I think it would be beneficial for the state to be local, not global.
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.
In other words, why do we need to keep a global list?
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.
Notices is a HoC around blocks, it would be the same as doing something like withNotices( GalleryBlock ); that adds notices property to gallery block. I can easily switch to this version. The only disadvantage is that blocks would need to be React components to use it and the current approach also allows blocks to take advantage even if their edit method is a function. When a block with notices is removed, the HoC around it will also be removed and its state is deleted.
Similar to happens when we use withAPIData the HoC also has its own state when a block it wraps is removed its own state is also deleted.
cf08e69
to
6c1c06f
Compare
Hi @iseulde, from the technical point of view this code was also updated we now make use of a HOC, I would appreciate if you could have a new look :) |
blocks/editor-media-upload/index.js
Outdated
* @param {Array} filesList List of files. | ||
* @param {Function} onFileChange Function to be called each time a file or a temporary representation of the file is available. | ||
* @param {string} allowedType The type of media that can be uploaded. | ||
* @param {Object} $0 Parameters object passed to the function. |
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.
Interesting notation! :)
blocks/editor-media-upload/index.js
Outdated
maxUploadFileSize, | ||
onError = noop, | ||
onFileChange, | ||
} ) { |
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.
Nice to have an options object here!
this.removeNotice = this.removeNotice.bind( this ); | ||
|
||
this.state = { | ||
notices: [], |
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.
Wouldn't it be simpler to store notices by ID here?
this.state = {
1: {},
2: {},
}
That also makes it easier to add and delete.
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.
I used an array to follow the same logic we use on the global notices. I wanted to use the same that is being used globally.
* @return {Component} Wrapped component. | ||
*/ | ||
export default createHigherOrderComponent( ( BlockEdit ) => { | ||
return class WrappedBlockEdit extends Component { |
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.
Curious: why enhance the BlockEdit
component and not let block authors enhance their own edit
component or a child component of that? The whole BlockEdit
does not need to rerender on a state change, right? Notices are only shown within the edit
component of the block, or am I mistaken?
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.
Sorry, I missed the update to the component name during the changes, it should have been called OriginalComponent instead of BlockEdit.
withNotices is a generic HOC that can be passed to any react component and it is not being used against BlockEdit we use it inside the blocks edit because as you said notices are only shown within the edit component of the block.
core-blocks/gallery/block.js
Outdated
@@ -236,6 +247,7 @@ class GalleryBlock extends Component { | |||
</PanelBody> | |||
</InspectorControls> | |||
<ul className={ `${ className } align${ align } columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }` }> | |||
{ noticesUI } |
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.
Can this be a child of ul
?
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 should be outside of the ul during the rebase I made a mistake it was corrected. Thank you!
The main question for me is #4203 (comment). I don't understand why the component need to be so high up the tree with passing a |
2c7ff1f
to
b704760
Compare
Hi, @iseulde thank you a lot for the review. The component was not high up in the tree, but as I used BlockEdit as the name of the component passed to the HOC, it looked like it was being used high up in the tree. The name was corrected. |
@jorgefilipecosta - can you update this PR and make it mergeable? What are remaining blockers in here? |
f17dffb
to
9ba0213
Compare
Hi @gziolo, thank you for checking this PR, I rebased it. I think we don't have blocking points, from the design perspective it was approved. I would like to have final approval from the code perspective because we are implementing and exposing a local notices mechanism for block creators (which may not be trivial to change later). |
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.
Just a few questions... looks great otherwise. I wish there wasn't so much stuff passed and that the API were a bit simpler.
There's also a failing test.
components/placeholder/index.js
Outdated
const classes = classnames( 'components-placeholder', className ); | ||
|
||
return ( | ||
<div { ...additionalProps } className={ classes }> | ||
{ !! notices && notices } |
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.
Why is !! notices
needed? Can't it be null
?
core-blocks/gallery/edit.js
Outdated
@@ -195,6 +198,13 @@ export default class GalleryEdit extends Component { | |||
</BlockControls> | |||
); | |||
|
|||
const noticesUI = notices.noticeList.length > 0 && | |||
<BlockNotices |
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.
I'm just wondering here... Could the BlockNotices
be a prop of this component that is added by withNotices
. Or would there be any other way to avoid passing all this stuff (less for the block author to worry about).
9ba0213
to
caa931c
Compare
Hi, @iseulde thank you for your review! I followed your suggestion, and now withNotices adds a UI prop so we make the usage easier and we don't have to pass many props around. If the user wants a custom UI it is still possible to have one. |
<OriginalComponent | ||
noticeList={ this.state.noticeList } | ||
noticeOperations={ this.noticeOperations } | ||
noticeUI={ |
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.
This seems nicer! Wondering if it could make it clear things up even more if noticeOperations
are properties on noticeUI
? Do you think that would be strange?
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.
Related with #4203 (comment) although we pass a noticeUI I wanted it to be a totally optional prop and allow components to ignore it if they just want the notices without relying on the default UI we provide.
render() { | ||
return ( | ||
<OriginalComponent | ||
noticeList={ this.state.noticeList } |
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.
Does that still need to be passed?
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 is not being used, but passing it allows a user of the HOC to create a different UI and not rely on the provided noticeUI.
caa931c
to
9092d69
Compare
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.
Looks good to me!
Squashed commits: [5cceb909a] Added maximum file size validation to media upload; Passed maxUploadSize client-assets. This change makes client size validation of the file size, avoiding spending time uploading invalid files to server. It also shows a friendly error message if the file size validation fails.
9092d69
to
ce37495
Compare
Description
This PR aims to fix #3984. It improves media upload error handling, by showing a generic message when the upload fails, and by validating the max file size before starting the upload so we are not wasting resources try to send an invalid file to the server.
How Has This Been Tested?
Add an image block. Try to upload an image bigger than max file size upload limit. the value can be changed by adding this lines "php_value upload_max_filesize 3M / php_value post_max_size 3M" in .htaccess.
See that the correct error notice appears.
Screenshots (jpeg or gifs if applicable):
Types of changes
Added an onError handler to media handler. Used the handler to validate max file size and generic upload problems.
Passed max upload size from in client assets to allow max file size validation.
Added the ability for blocks to display error notices.