Wrap activity panels in error boundary (#48415)

* Fix review error type

* Add changelog

* Rename global error-boundary class to avoid conflict

* Rename global error-boundary class to avoid conflict

* Wrap panels in error boundary

* Remove console

* Reformat

* Fix test

* Fix test

* Add changelog
This commit is contained in:
Chi-Hsuan Huang 2024-06-17 13:05:11 +08:00 committed by GitHub
parent 1e92b0efaf
commit 4162a6ef89
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 85 additions and 87 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Fix review store error type

View File

@ -27,7 +27,7 @@ export function setReview( reviewId: number, reviewData: ReviewObject ) {
}; };
} }
export function setError( query: ReviewsQueryParams | string, error: unknown ) { export function setError( query: string, error: unknown ) {
return { return {
type: TYPES.SET_ERROR, type: TYPES.SET_ERROR,
query, query,

View File

@ -59,7 +59,7 @@ const reducer: Reducer< ReviewsState, Action > = (
...state, ...state,
errors: { errors: {
...state.errors, ...state.errors,
[ JSON.stringify( action.query ) ]: action.error, [ action.query ]: action.error,
}, },
}; };
case TYPES.SET_REVIEW_IS_UPDATING: case TYPES.SET_REVIEW_IS_UPDATING:

View File

@ -88,7 +88,7 @@ describe( 'reviews reducer', () => {
} ); } );
it( 'should handle SET_ERROR', () => { it( 'should handle SET_ERROR', () => {
const query = { status: 'spam' as const }; const query = JSON.stringify( { status: 'spam' as const } );
const error = 'Baaam!'; const error = 'Baaam!';
const state = reducer( defaultState, { const state = reducer( defaultState, {
type: TYPES.SET_ERROR, type: TYPES.SET_ERROR,
@ -96,8 +96,7 @@ describe( 'reviews reducer', () => {
error, error,
} ); } );
const stringifiedQuery = JSON.stringify( query ); expect( state.errors[ query ] ).toBe( error );
expect( state.errors[ stringifiedQuery ] ).toBe( error );
} ); } );
it( 'should handle SET_REVIEW', () => { it( 'should handle SET_REVIEW', () => {

View File

@ -53,17 +53,17 @@ export class ErrorBoundary extends Component<
render() { render() {
if ( this.state.hasError ) { if ( this.state.hasError ) {
return ( return (
<div className="woocommerce-error-boundary"> <div className="woocommerce-global-error-boundary">
<h1 className="woocommerce-error-boundary__heading"> <h1 className="woocommerce-global-error-boundary__heading">
{ __( 'Oops, something went wrong', 'woocommerce' ) } { __( 'Oops, something went wrong', 'woocommerce' ) }
</h1> </h1>
<p className="woocommerce-error-boundary__subheading"> <p className="woocommerce-global-error-boundary__subheading">
{ __( { __(
"We're sorry for the inconvenience. Please try reloading the page, or you can get support from the community forums.", "We're sorry for the inconvenience. Please try reloading the page, or you can get support from the community forums.",
'woocommerce' 'woocommerce'
) } ) }
</p> </p>
<div className="woocommerce-error-boundary__actions"> <div className="woocommerce-global-error-boundary__actions">
<Button <Button
variant="secondary" variant="secondary"
onClick={ this.handleOpenSupport } onClick={ this.handleOpenSupport }
@ -77,12 +77,12 @@ export class ErrorBoundary extends Component<
{ __( 'Reload Page', 'woocommerce' ) } { __( 'Reload Page', 'woocommerce' ) }
</Button> </Button>
</div> </div>
<details className="woocommerce-error-boundary__details"> <details className="woocommerce-global-error-boundary__details">
<summary> <summary>
{ __( 'Click for error details', 'woocommerce' ) } { __( 'Click for error details', 'woocommerce' ) }
</summary> </summary>
<div className="woocommerce-error-boundary__details-content"> <div className="woocommerce-global-error-boundary__details-content">
<strong className="woocommerce-error-boundary__error"> <strong className="woocommerce-global-error-boundary__error">
{ this.state.error && { this.state.error &&
this.state.error.toString() } this.state.error.toString() }
</strong> </strong>

View File

@ -1,11 +1,11 @@
.woocommerce-error-boundary { .woocommerce-global-error-boundary {
min-height: 100vh; min-height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 70px 20px 0; padding: 70px 20px 0;
box-sizing: border-box; box-sizing: border-box;
.woocommerce-error-boundary__heading { .woocommerce-global-error-boundary__heading {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@ -18,11 +18,11 @@
text-align: center; text-align: center;
} }
.woocommerce-error-boundary__subheading { .woocommerce-global-error-boundary__subheading {
text-align: center; text-align: center;
} }
.woocommerce-error-boundary__actions { .woocommerce-global-error-boundary__actions {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin-top: 48px; margin-top: 48px;
@ -32,7 +32,7 @@
} }
} }
.woocommerce-error-boundary__details { .woocommerce-global-error-boundary__details {
white-space: pre-wrap; white-space: pre-wrap;
text-align: left; text-align: left;
margin: 32px auto; margin: 32px auto;
@ -46,7 +46,7 @@
text-align: center; text-align: center;
} }
.woocommerce-error-boundary__details-content { .woocommerce-global-error-boundary__details-content {
padding: 16px 24px; padding: 16px 24px;
} }

View File

@ -333,25 +333,8 @@ function OrdersPanel( { unreadOrdersCount, orderStatuses } ) {
); );
} }
const title = __( throw new Error(
'There was an error getting your orders. Please try again.', 'Failed to load orders, raise error to trigger ErrorBoundary'
'woocommerce'
);
const actionLabel = __( 'Reload', 'woocommerce' );
const actionCallback = () => {
// @todo Add tracking for how often an error is displayed, and the reload action is clicked.
window.location.reload();
};
return (
<>
<EmptyContent
title={ title }
actionLabel={ actionLabel }
actionURL={ null }
actionCallback={ actionCallback }
/>
</>
); );
} }
const customerList = customerItems const customerList = customerItems

View File

@ -2,6 +2,7 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { __experimentalErrorBoundary as ErrorBoundary } from '@woocommerce/components';
/** /**
* Internal dependencies * Internal dependencies
@ -33,10 +34,23 @@ export function getAllPanels( {
id: 'orders-panel', id: 'orders-panel',
initialOpen: false, initialOpen: false,
panel: ( panel: (
<ErrorBoundary
errorMessage={
<>
{ __(
'There was an error getting your orders.',
'woocommerce'
) }
<br />
{ __( 'Please try again.', 'woocommerce' ) }
</>
}
>
<OrdersPanel <OrdersPanel
unreadOrdersCount={ unreadOrdersCount } unreadOrdersCount={ unreadOrdersCount }
orderStatuses={ orderStatuses } orderStatuses={ orderStatuses }
/> />
</ErrorBoundary>
), ),
title: __( 'Orders', 'woocommerce' ), title: __( 'Orders', 'woocommerce' ),
}, },
@ -49,9 +63,22 @@ export function getAllPanels( {
initialOpen: false, initialOpen: false,
collapsible: lowStockProductsCount !== 0, collapsible: lowStockProductsCount !== 0,
panel: ( panel: (
<ErrorBoundary
errorMessage={
<>
{ __(
'There was an error getting your low stock products.',
'woocommerce'
) }
<br />
{ __( 'Please try again.', 'woocommerce' ) }
</>
}
>
<StockPanel <StockPanel
lowStockProductsCount={ lowStockProductsCount } lowStockProductsCount={ lowStockProductsCount }
/> />
</ErrorBoundary>
), ),
title: __( 'Stock', 'woocommerce' ), title: __( 'Stock', 'woocommerce' ),
}, },
@ -64,9 +91,22 @@ export function getAllPanels( {
initialOpen: false, initialOpen: false,
collapsible: unapprovedReviewsCount !== 0, collapsible: unapprovedReviewsCount !== 0,
panel: ( panel: (
<ErrorBoundary
errorMessage={
<>
{ __(
'There was an error getting your reviews.',
'woocommerce'
) }
<br />
{ __( 'Please try again.', 'woocommerce' ) }
</>
}
>
<ReviewsPanel <ReviewsPanel
hasUnapprovedReviews={ unapprovedReviewsCount > 0 } hasUnapprovedReviews={ unapprovedReviewsCount > 0 }
/> />
</ErrorBoundary>
), ),
title: __( 'Reviews', 'woocommerce' ), title: __( 'Reviews', 'woocommerce' ),
}, },

View File

@ -12,7 +12,6 @@ import StarIcon from 'gridicons/dist/star';
import StarOutlineIcon from 'gridicons/dist/star-outline'; import StarOutlineIcon from 'gridicons/dist/star-outline';
import interpolateComponents from '@automattic/interpolate-components'; import interpolateComponents from '@automattic/interpolate-components';
import { import {
EmptyContent,
Link, Link,
ReviewRating, ReviewRating,
ProductImage, ProductImage,
@ -307,25 +306,8 @@ class ReviewsPanel extends Component {
const { isRequesting, isError, reviews } = this.props; const { isRequesting, isError, reviews } = this.props;
if ( isError ) { if ( isError ) {
const title = __( throw new Error(
'There was an error getting your reviews. Please try again.', 'Failed to load reviews, Raise error to trigger ErrorBoundary'
'woocommerce'
);
const actionLabel = __( 'Reload', 'woocommerce' );
const actionCallback = () => {
// @todo Add tracking for how often an error is displayed, and the reload action is clicked.
window.location.reload();
};
return (
<Fragment>
<EmptyContent
title={ title }
actionLabel={ actionLabel }
actionURL={ null }
actionCallback={ actionCallback }
/>
</Fragment>
); );
} }

View File

@ -1,12 +1,11 @@
/** /**
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element'; import { Component } from '@wordpress/element';
import { compose } from '@wordpress/compose'; import { compose } from '@wordpress/compose';
import { withDispatch, withSelect } from '@wordpress/data'; import { withDispatch, withSelect } from '@wordpress/data';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { EmptyContent, Section } from '@woocommerce/components'; import { Section } from '@woocommerce/components';
import { ITEMS_STORE_NAME } from '@woocommerce/data'; import { ITEMS_STORE_NAME } from '@woocommerce/data';
/** /**
@ -77,23 +76,8 @@ export class StockPanel extends Component {
this.props; this.props;
if ( isError ) { if ( isError ) {
const title = __( throw new Error(
'There was an error getting your low stock products. Please try again.', 'Failed to load low stock products, Raise error to trigger ErrorBoundary'
'woocommerce'
);
const actionLabel = __( 'Reload', 'woocommerce' );
const actionCallback = () => {
// @todo Add tracking for how often an error is displayed, and the reload action is clicked.
window.location.reload();
};
return (
<EmptyContent
title={ title }
actionLabel={ actionLabel }
actionURL={ null }
actionCallback={ actionCallback }
/>
); );
} }

View File

@ -125,7 +125,9 @@
} }
.wp-toolbar .is-wp-toolbar-disabled, .wp-toolbar .is-wp-toolbar-disabled,
.wp-toolbar:has(> .woocommerce-admin-full-screen .woocommerce-error-boundary) { .wp-toolbar:has(
> .woocommerce-admin-full-screen .woocommerce-global-error-boundary
) {
margin-top: -$adminbar-height; margin-top: -$adminbar-height;
@include breakpoint("<600px") { @include breakpoint("<600px") {
margin-top: -$adminbar-height-mobile; margin-top: -$adminbar-height-mobile;

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
Wrap activity panels in error boundary