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

Fix max upload size error message #4203

Merged
merged 1 commit into from
May 22, 2018

Conversation

jorgefilipecosta
Copy link
Member

@jorgefilipecosta jorgefilipecosta commented Dec 29, 2017

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):

screen shot 2018-01-15 at 22 43 53

screen shot 2018-01-15 at 22 44 11

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.

@jorgefilipecosta jorgefilipecosta added [Feature] Blocks Overall functionality of blocks [Type] Bug An existing feature does not function as intended labels Dec 29, 2017
@jorgefilipecosta jorgefilipecosta self-assigned this Dec 29, 2017
@jorgefilipecosta jorgefilipecosta force-pushed the fix/max-upload-size-error-message branch 2 times, most recently from 247e67e to 34534a1 Compare December 29, 2017 16:39
@ellatrix
Copy link
Member

Nice pre checking! Would it perhaps be nice to display the error on the block itself (locally), instead of at the top (globally)?

@mtias mtias added the Needs Design Feedback Needs general design feedback. label Jan 3, 2018
@karmatosed
Copy link
Member

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 karmatosed removed the Needs Design Feedback Needs general design feedback. label Jan 3, 2018
@ellatrix
Copy link
Member

ellatrix commented Jan 3, 2018

@karmatosed We currently have some error messages that are block-specific that go in the block, such as JS errors and externally modified messages.

@karmatosed
Copy link
Member

karmatosed commented Jan 4, 2018

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.

@ellatrix
Copy link
Member

ellatrix commented Jan 4, 2018

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.

@ellatrix
Copy link
Member

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 }
Copy link
Member

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.

Copy link
Member Author

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 👍

Copy link
Member

Choose a reason for hiding this comment

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

Awesome, thanks! :)

@jorgefilipecosta jorgefilipecosta force-pushed the fix/max-upload-size-error-message branch from 34534a1 to 64c67b3 Compare January 11, 2018 18:59
@jorgefilipecosta
Copy link
Member Author

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.

@jorgefilipecosta jorgefilipecosta added the Needs Design Feedback Needs general design feedback. label Jan 11, 2018
@ellatrix
Copy link
Member

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 Editable etc. Would that not make the code simpler? Or does the error notice need to appear outside the block edit boundary? I think the error makes sense to display as close to where the state lives, if that makes sense, not only code wise, but also visually. The error was triggered inside the upload part of the image block. Now it kind of feels like its a block on its own.

@ellatrix
Copy link
Member

Just ideas

screen shot 2018-01-15 at 13 25 37

screen shot 2018-01-15 at 13 27 11

@jorgefilipecosta
Copy link
Member Author

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 Editable etc. Would that not make the code simpler?

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.

The error was triggered inside the upload part of the image block. Now it kind of feels like its a block on its own.

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.

@ellatrix
Copy link
Member

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.

@jorgefilipecosta jorgefilipecosta force-pushed the fix/max-upload-size-error-message branch from 64c67b3 to 8a98a71 Compare January 15, 2018 22:43
@jorgefilipecosta
Copy link
Member Author

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.

@@ -62,6 +62,10 @@ registerBlockType( 'core/gallery', {
},
},

supports: {
notices: true,
Copy link
Member

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.


/** @inheritdoc */
render() {
if ( ! hasBlockSupport( this.props.name, 'notices' ) ) {
Copy link
Member

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?

Copy link
Member Author

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.

*
* @param {string} id Id of the notice to remove.
*/
removeNotice( id ) {
Copy link
Member

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.

Copy link
Member

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?

Copy link
Member Author

@jorgefilipecosta jorgefilipecosta Jan 18, 2018

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.

@karmatosed karmatosed removed the Needs Design Feedback Needs general design feedback. label Apr 28, 2018
@jorgefilipecosta jorgefilipecosta force-pushed the fix/max-upload-size-error-message branch 2 times, most recently from cf08e69 to 6c1c06f Compare May 1, 2018 09:47
@jorgefilipecosta
Copy link
Member Author

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 :)

* @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.
Copy link
Member

Choose a reason for hiding this comment

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

Interesting notation! :)

maxUploadFileSize,
onError = noop,
onFileChange,
} ) {
Copy link
Member

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: [],
Copy link
Member

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.

Copy link
Member Author

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 {
Copy link
Member

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?

Copy link
Member Author

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.

@@ -236,6 +247,7 @@ class GalleryBlock extends Component {
</PanelBody>
</InspectorControls>
<ul className={ `${ className } align${ align } columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }` }>
{ noticesUI }
Copy link
Member

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?

Copy link
Member Author

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!

@ellatrix
Copy link
Member

ellatrix commented May 1, 2018

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 notices object etc.

@jorgefilipecosta jorgefilipecosta force-pushed the fix/max-upload-size-error-message branch 2 times, most recently from 2c7ff1f to b704760 Compare May 1, 2018 15:55
@jorgefilipecosta
Copy link
Member Author

jorgefilipecosta commented May 1, 2018

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.

@gziolo gziolo added the [Status] Stale Gives the original author opportunity to update before closing. Can be reopened as needed. label May 10, 2018
@gziolo
Copy link
Member

gziolo commented May 10, 2018

@jorgefilipecosta - can you update this PR and make it mergeable? What are remaining blockers in here?

@jorgefilipecosta jorgefilipecosta force-pushed the fix/max-upload-size-error-message branch 2 times, most recently from f17dffb to 9ba0213 Compare May 10, 2018 10:00
@jorgefilipecosta jorgefilipecosta removed the [Status] Stale Gives the original author opportunity to update before closing. Can be reopened as needed. label May 10, 2018
@jorgefilipecosta
Copy link
Member Author

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).

Copy link
Member

@ellatrix ellatrix left a 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.

const classes = classnames( 'components-placeholder', className );

return (
<div { ...additionalProps } className={ classes }>
{ !! notices && notices }
Copy link
Member

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?

@@ -195,6 +198,13 @@ export default class GalleryEdit extends Component {
</BlockControls>
);

const noticesUI = notices.noticeList.length > 0 &&
<BlockNotices
Copy link
Member

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).

@jorgefilipecosta jorgefilipecosta force-pushed the fix/max-upload-size-error-message branch from 9ba0213 to caa931c Compare May 16, 2018 17:42
@jorgefilipecosta
Copy link
Member Author

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={
Copy link
Member

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?

Copy link
Member Author

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 }
Copy link
Member

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?

Copy link
Member Author

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.

@jorgefilipecosta jorgefilipecosta force-pushed the fix/max-upload-size-error-message branch from caa931c to 9092d69 Compare May 16, 2018 20:11
Copy link
Member

@ellatrix ellatrix left a 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!

@mirka mirka mentioned this pull request May 17, 2018
11 tasks
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.
@jorgefilipecosta jorgefilipecosta force-pushed the fix/max-upload-size-error-message branch from 9092d69 to ce37495 Compare May 22, 2018 14:29
@jorgefilipecosta jorgefilipecosta merged commit deabbc3 into master May 22, 2018
@jorgefilipecosta jorgefilipecosta deleted the fix/max-upload-size-error-message branch May 22, 2018 14:40
@danielbachhuber danielbachhuber added this to the 3.0 milestone May 22, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Blocks Overall functionality of blocks [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug Imageblock Image over Update Limit
6 participants