Skip to content

Commit

Permalink
Site Editor: Add error boundary (#33921)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mamaduka authored Aug 9, 2021
1 parent e9611ea commit 4a6d006
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 82 deletions.
161 changes: 82 additions & 79 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ import NavigationSidebar from '../navigation-sidebar';
import URLQueryController from '../url-query-controller';
import InserterSidebar from '../secondary-sidebar/inserter-sidebar';
import ListViewSidebar from '../secondary-sidebar/list-view-sidebar';
import ErrorBoundary from '../error-boundary';
import { store as editSiteStore } from '../../store';

const interfaceLabels = {
secondarySidebar: __( 'Block Library' ),
drawer: __( 'Navigation Sidebar' ),
};

function Editor( { initialSettings } ) {
function Editor( { initialSettings, onError } ) {
const {
isInserterOpen,
isListViewOpen,
Expand Down Expand Up @@ -179,8 +180,6 @@ function Editor( { initialSettings } ) {
return (
<>
<URLQueryController />
<FullscreenMode isActive />
<UnsavedChangesWarning />
<SlotFillProvider>
<EntityProvider kind="root" type="site">
<EntityProvider
Expand All @@ -201,85 +200,89 @@ function Editor( { initialSettings } ) {
settings.__experimentalGlobalStylesBaseStyles
}
>
<KeyboardShortcuts.Register />
<SidebarComplementaryAreaFills />
<InterfaceSkeleton
labels={ interfaceLabels }
drawer={ <NavigationSidebar /> }
secondarySidebar={ secondarySidebar() }
sidebar={
sidebarIsOpened && (
<ComplementaryArea.Slot scope="core/edit-site" />
)
}
header={
<Header
openEntitiesSavedStates={
openEntitiesSavedStates
}
/>
}
notices={ <EditorSnackbars /> }
content={
<>
<EditorNotices />
{ template && (
<BlockEditor
setIsInserterOpen={
setIsInserterOpened
}
/>
) }
{ templateResolved &&
! template &&
settings?.siteUrl &&
entityId && (
<Notice
status="warning"
isDismissible={
false
<ErrorBoundary onError={ onError }>
<FullscreenMode isActive />
<UnsavedChangesWarning />
<KeyboardShortcuts.Register />
<SidebarComplementaryAreaFills />
<InterfaceSkeleton
labels={ interfaceLabels }
drawer={ <NavigationSidebar /> }
secondarySidebar={ secondarySidebar() }
sidebar={
sidebarIsOpened && (
<ComplementaryArea.Slot scope="core/edit-site" />
)
}
header={
<Header
openEntitiesSavedStates={
openEntitiesSavedStates
}
/>
}
notices={ <EditorSnackbars /> }
content={
<>
<EditorNotices />
{ template && (
<BlockEditor
setIsInserterOpen={
setIsInserterOpened
}
>
{ __(
"You attempted to edit an item that doesn't exist. Perhaps it was deleted?"
) }
</Notice>
/>
) }
<KeyboardShortcuts />
</>
}
actions={
<>
{ isEntitiesSavedStatesOpen ? (
<EntitiesSavedStates
close={
closeEntitiesSavedStates
}
/>
) : (
<div className="edit-site-editor__toggle-save-panel">
<Button
variant="secondary"
className="edit-site-editor__toggle-save-panel-button"
onClick={
openEntitiesSavedStates
{ templateResolved &&
! template &&
settings?.siteUrl &&
entityId && (
<Notice
status="warning"
isDismissible={
false
}
>
{ __(
"You attempted to edit an item that doesn't exist. Perhaps it was deleted?"
) }
</Notice>
) }
<KeyboardShortcuts />
</>
}
actions={
<>
{ isEntitiesSavedStatesOpen ? (
<EntitiesSavedStates
close={
closeEntitiesSavedStates
}
aria-expanded={
false
}
>
{ __(
'Open save panel'
) }
</Button>
</div>
) }
</>
}
footer={ <BlockBreadcrumb /> }
/>
<Popover.Slot />
<PluginArea />
/>
) : (
<div className="edit-site-editor__toggle-save-panel">
<Button
variant="secondary"
className="edit-site-editor__toggle-save-panel-button"
onClick={
openEntitiesSavedStates
}
aria-expanded={
false
}
>
{ __(
'Open save panel'
) }
</Button>
</div>
) }
</>
}
footer={ <BlockBreadcrumb /> }
/>
<Popover.Slot />
<PluginArea />
</ErrorBoundary>
</GlobalStylesProvider>
</BlockContextProvider>
</EntityProvider>
Expand Down
64 changes: 64 additions & 0 deletions packages/edit-site/src/components/error-boundary/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { Warning } from '@wordpress/block-editor';
import { useCopyToClipboard } from '@wordpress/compose';

function CopyButton( { text, children } ) {
const ref = useCopyToClipboard( text );
return (
<Button variant="secondary" ref={ ref }>
{ children }
</Button>
);
}

export default class ErrorBoundary extends Component {
constructor() {
super( ...arguments );

this.reboot = this.reboot.bind( this );

this.state = {
error: null,
};
}

static getDerivedStateFromError( error ) {
return { error };
}

reboot() {
this.props.onError();
}

render() {
const { error } = this.state;
if ( ! error ) {
return this.props.children;
}

return (
<Warning
className="editor-error-boundary"
actions={ [
<Button
key="recovery"
onClick={ this.reboot }
variant="secondary"
>
{ __( 'Attempt Recovery' ) }
</Button>,
<CopyButton key="copy-error" text={ error.stack }>
{ __( 'Copy Error' ) }
</CopyButton>,
] }
>
{ __( 'The editor has encountered an unexpected error.' ) }
</Warning>
);
}
}
26 changes: 23 additions & 3 deletions packages/edit-site/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
registerCoreBlocks,
__experimentalRegisterExperimentalCoreBlocks,
} from '@wordpress/block-library';
import { render } from '@wordpress/element';
import { render, unmountComponentAtNode } from '@wordpress/element';
import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data';

/**
Expand All @@ -16,6 +16,23 @@ import './hooks';
import './store';
import Editor from './components/editor';

/**
* Reinitializes the editor after the user chooses to reboot the editor after
* an unhandled error occurs, replacing previously mounted editor element using
* an initial state from prior to the crash.
*
* @param {Element} target DOM node in which editor is rendered.
* @param {?Object} settings Editor settings object.
*/
export function reinitializeEditor( target, settings ) {
unmountComponentAtNode( target );
const reboot = reinitializeEditor.bind( null, target, settings );
render(
<Editor initialSettings={ settings } onError={ reboot } />,
target
);
}

/**
* Initializes the site editor screen.
*
Expand All @@ -27,6 +44,9 @@ export function initialize( id, settings ) {
fetchLinkSuggestions( search, searchOptions, settings );
settings.__experimentalSpotlightEntityBlocks = [ 'core/template-part' ];

const target = document.getElementById( id );
const reboot = reinitializeEditor.bind( null, target, settings );

registerCoreBlocks();
if ( process.env.GUTENBERG_PHASE === 2 ) {
__experimentalRegisterExperimentalCoreBlocks( {
Expand All @@ -35,8 +55,8 @@ export function initialize( id, settings ) {
}

render(
<Editor initialSettings={ settings } />,
document.getElementById( id )
<Editor initialSettings={ settings } onError={ reboot } />,
target
);
}

Expand Down

0 comments on commit 4a6d006

Please sign in to comment.