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:
parent
1e92b0efaf
commit
4162a6ef89
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: fix
|
||||||
|
|
||||||
|
Fix review store error type
|
|
@ -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,
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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', () => {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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' ),
|
||||||
},
|
},
|
||||||
|
|
|
@ -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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 }
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: update
|
||||||
|
|
||||||
|
Wrap activity panels in error boundary
|
Loading…
Reference in New Issue