diff --git a/packages/edit-site/src/components/list/style.scss b/packages/edit-site/src/components/list/style.scss
index ca2c9894345862..f301d1b1ed340f 100644
--- a/packages/edit-site/src/components/list/style.scss
+++ b/packages/edit-site/src/components/list/style.scss
@@ -114,3 +114,9 @@
border-top: none;
}
}
+
+.edit-site-list.is-navigation-open .components-snackbar-list {
+ @include break-medium() {
+ margin-left: $nav-sidebar-width;
+ }
+}
diff --git a/packages/edit-site/src/components/list/table.js b/packages/edit-site/src/components/list/table.js
index e532023347caab..907163bddec7f2 100644
--- a/packages/edit-site/src/components/list/table.js
+++ b/packages/edit-site/src/components/list/table.js
@@ -12,6 +12,7 @@ import {
} from '@wordpress/components';
import { moreVertical } from '@wordpress/icons';
import { addQueryArgs } from '@wordpress/url';
+import { store as noticesStore } from '@wordpress/notices';
/**
* Internal dependencies
@@ -23,6 +24,9 @@ import isTemplateRevertable from '../../utils/is-template-revertable';
function Actions( { template } ) {
const { removeTemplate, revertTemplate } = useDispatch( editSiteStore );
const { saveEditedEntityRecord } = useDispatch( coreStore );
+ const { createSuccessNotice, createErrorNotice } = useDispatch(
+ noticesStore
+ );
const isRemovable = isTemplateRemovable( template );
const isRevertable = isTemplateRevertable( template );
@@ -32,8 +36,25 @@ function Actions( { template } ) {
}
async function revertAndSaveTemplate() {
- await revertTemplate( template, { allowUndo: false } );
- await saveEditedEntityRecord( 'postType', template.type, template.id );
+ try {
+ await revertTemplate( template, { allowUndo: false } );
+ await saveEditedEntityRecord(
+ 'postType',
+ template.type,
+ template.id
+ );
+
+ createSuccessNotice( __( 'Template reverted.' ), {
+ type: 'snackbar',
+ } );
+ } catch ( error ) {
+ const errorMessage =
+ error.message && error.code !== 'unknown_error'
+ ? error.message
+ : __( 'An error occurred while reverting the template.' );
+
+ createErrorNotice( errorMessage, { type: 'snackbar' } );
+ }
}
return (
diff --git a/packages/edit-site/src/components/navigation-sidebar/index.js b/packages/edit-site/src/components/navigation-sidebar/index.js
index 035160022b920c..4d6cbfc7a61705 100644
--- a/packages/edit-site/src/components/navigation-sidebar/index.js
+++ b/packages/edit-site/src/components/navigation-sidebar/index.js
@@ -1,13 +1,15 @@
/**
* WordPress dependencies
*/
-import { useEffect, useState } from '@wordpress/element';
+import { useEffect } from '@wordpress/element';
import { createSlotFill } from '@wordpress/components';
import { useViewportMatch } from '@wordpress/compose';
+import { useDispatch } from '@wordpress/data';
/**
* Internal dependencies
*/
+import { store as editSiteStore } from '../../store';
import NavigationPanel from './navigation-panel';
import NavigationToggle from './navigation-toggle';
@@ -21,33 +23,24 @@ export default function NavigationSidebar( {
activeTemplateType,
} ) {
const isDesktopViewport = useViewportMatch( 'medium' );
- const [ isNavigationOpen, setIsNavigationOpen ] = useState(
- isDefaultOpen && isDesktopViewport
- );
+ const { setIsNavigationPanelOpened } = useDispatch( editSiteStore );
useEffect( () => {
// When transitioning to desktop open the navigation if `isDefaultOpen` is true.
if ( isDefaultOpen && isDesktopViewport ) {
- setIsNavigationOpen( true );
+ setIsNavigationPanelOpened( true );
}
// When transitioning to mobile/tablet, close the navigation.
if ( ! isDesktopViewport ) {
- setIsNavigationOpen( false );
+ setIsNavigationPanelOpened( false );
}
- }, [ isDefaultOpen, isDesktopViewport ] );
+ }, [ isDefaultOpen, isDesktopViewport, setIsNavigationPanelOpened ] );
return (
<>
-
-
+
+
>
);
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/index.js b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/index.js
index e047ec0708012a..802c53c2b56545 100644
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/index.js
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/index.js
@@ -14,7 +14,7 @@ import {
__experimentalNavigationMenu as NavigationMenu,
} from '@wordpress/components';
import { store as coreDataStore } from '@wordpress/core-data';
-import { useSelect } from '@wordpress/data';
+import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { ESCAPE } from '@wordpress/keycodes';
@@ -25,36 +25,37 @@ import { addQueryArgs } from '@wordpress/url';
* Internal dependencies
*/
import MainDashboardButton from '../../main-dashboard-button';
+import { store as editSiteStore } from '../../../store';
const SITE_EDITOR_KEY = 'site-editor';
-const NavigationPanel = ( {
- isOpen,
- setIsOpen,
- activeItem = SITE_EDITOR_KEY,
-} ) => {
- const siteTitle = useSelect( ( select ) => {
+const NavigationPanel = ( { activeItem = SITE_EDITOR_KEY } ) => {
+ const { isNavigationOpen, siteTitle } = useSelect( ( select ) => {
const { getEntityRecord } = select( coreDataStore );
const siteData =
getEntityRecord( 'root', '__unstableBase', undefined ) || {};
- return siteData.name;
+ return {
+ siteTitle: siteData.name,
+ isNavigationOpen: select( editSiteStore ).isNavigationOpened(),
+ };
}, [] );
+ const { setIsNavigationPanelOpened } = useDispatch( editSiteStore );
// Ensures focus is moved to the panel area when it is activated
// from a separate component (such as document actions in the header).
const panelRef = useRef();
useEffect( () => {
- if ( isOpen ) {
+ if ( isNavigationOpen ) {
panelRef.current.focus();
}
- }, [ activeItem, isOpen ] );
+ }, [ activeItem, isNavigationOpen ] );
const closeOnEscape = ( event ) => {
if ( event.keyCode === ESCAPE && ! event.defaultPrevented ) {
event.preventDefault();
- setIsOpen( false );
+ setIsNavigationPanelOpened( false );
}
};
@@ -62,7 +63,7 @@ const NavigationPanel = ( {
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
{
- const { getEntityRecord, isResolving } = select( coreDataStore );
- const siteData =
- getEntityRecord( 'root', '__unstableBase', undefined ) || {};
+/**
+ * Internal dependencies
+ */
+import { store as editSiteStore } from '../../../store';
+
+function NavigationToggle( { icon } ) {
+ const { isNavigationOpen, isRequestingSiteIcon, siteIconUrl } = useSelect(
+ ( select ) => {
+ const { getEntityRecord, isResolving } = select( coreDataStore );
+ const siteData =
+ getEntityRecord( 'root', '__unstableBase', undefined ) || {};
- return {
- isRequestingSiteIcon: isResolving( 'core', 'getEntityRecord', [
- 'root',
- '__unstableBase',
- undefined,
- ] ),
- siteIconUrl: siteData.site_icon_url,
- };
- }, [] );
+ return {
+ isNavigationOpen: select( editSiteStore ).isNavigationOpened(),
+ isRequestingSiteIcon: isResolving( 'core', 'getEntityRecord', [
+ 'root',
+ '__unstableBase',
+ undefined,
+ ] ),
+ siteIconUrl: siteData.site_icon_url,
+ };
+ },
+ []
+ );
+ const { setIsNavigationPanelOpened } = useDispatch( editSiteStore );
const disableMotion = useReducedMotion();
- const toggleNavigationPanel = () => setIsOpen( ( open ) => ! open );
+ const toggleNavigationPanel = () =>
+ setIsNavigationPanelOpened( ! isNavigationOpen );
let buttonIcon = ;
@@ -60,7 +71,8 @@ function NavigationToggle( { icon, isOpen, setIsOpen } ) {
return (
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/index.js b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/index.js
index a85afafc572461..0d693733d019a3 100644
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/index.js
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/test/index.js
@@ -34,6 +34,7 @@ describe( 'NavigationToggle', () => {
site_icon_url: 'https://fakeUrl.com',
} ),
isResolving: () => false,
+ isNavigationOpened: () => false,
} ) );
} );
@@ -53,6 +54,7 @@ describe( 'NavigationToggle', () => {
site_icon_url: '',
} ),
isResolving: () => false,
+ isNavigationOpened: () => false,
} ) );
} );
diff --git a/packages/edit-site/src/index.js b/packages/edit-site/src/index.js
index 9b9a00a7a3e54c..4ed7f8ef3c5f8b 100644
--- a/packages/edit-site/src/index.js
+++ b/packages/edit-site/src/index.js
@@ -6,20 +6,21 @@ import {
registerCoreBlocks,
__experimentalRegisterExperimentalCoreBlocks,
} from '@wordpress/block-library';
-import { dispatch } from '@wordpress/data';
+import { dispatch, select } from '@wordpress/data';
import { render, unmountComponentAtNode } from '@wordpress/element';
import {
__experimentalFetchLinkSuggestions as fetchLinkSuggestions,
__experimentalFetchUrlData as fetchUrlData,
} from '@wordpress/core-data';
import { store as editorStore } from '@wordpress/editor';
+import { store as viewportStore } from '@wordpress/viewport';
/**
* Internal dependencies
*/
import './plugins';
import './hooks';
-import './store';
+import { store as editSiteStore } from './store';
import Editor from './components/editor';
import List from './components/list';
@@ -84,6 +85,13 @@ export function initializeList( id, templateType, settings ) {
defaultTemplatePartAreas: settings.defaultTemplatePartAreas,
} );
+ // Default the navigation panel to be opened when we're in a bigger screen.
+ // We update the store synchronously before rendering so that we won't
+ // trigger an unnecessary re-render with useEffect.
+ dispatch( editSiteStore ).setIsNavigationPanelOpened(
+ select( viewportStore ).isViewportMatch( 'medium' )
+ );
+
render(
, target );
}
diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js
index 7b3fb3d3a2cf77..1c056b47c2a840 100644
--- a/packages/edit-site/src/store/actions.js
+++ b/packages/edit-site/src/store/actions.js
@@ -5,7 +5,7 @@ import { parse, __unstableSerializeAndClean } from '@wordpress/blocks';
import { controls, dispatch } from '@wordpress/data';
import { apiFetch } from '@wordpress/data-controls';
import { addQueryArgs, getPathAndQueryString } from '@wordpress/url';
-import { __ } from '@wordpress/i18n';
+import { __, sprintf } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { store as coreStore } from '@wordpress/core-data';
import { store as interfaceStore } from '@wordpress/interface';
@@ -111,14 +111,51 @@ export function* addTemplate( template ) {
* @param {Object} template The template object.
*/
export function* removeTemplate( template ) {
- yield controls.dispatch(
- coreStore,
- 'deleteEntityRecord',
- 'postType',
- template.type,
- template.id,
- { force: true }
- );
+ try {
+ yield controls.dispatch(
+ coreStore,
+ 'deleteEntityRecord',
+ 'postType',
+ template.type,
+ template.id,
+ { force: true }
+ );
+
+ const lastError = yield controls.select(
+ coreStore,
+ 'getLastEntityDeleteError',
+ 'postType',
+ template.type,
+ template.id
+ );
+
+ if ( lastError ) {
+ throw lastError;
+ }
+
+ yield controls.dispatch(
+ noticesStore,
+ 'createSuccessNotice',
+ sprintf(
+ /* translators: The template/part's name. */
+ __( '"%s" removed.' ),
+ template.title.rendered
+ ),
+ { type: 'snackbar' }
+ );
+ } catch ( error ) {
+ const errorMessage =
+ error.message && error.code !== 'unknown_error'
+ ? error.message
+ : __( 'An error occurred while deleting the template.' );
+
+ yield controls.dispatch(
+ noticesStore,
+ 'createErrorNotice',
+ errorMessage,
+ { type: 'snackbar' }
+ );
+ }
}
/**
diff --git a/packages/edit-site/src/store/test/actions.js b/packages/edit-site/src/store/test/actions.js
index 5d45a0f0556cad..06ba5979b5023e 100644
--- a/packages/edit-site/src/store/test/actions.js
+++ b/packages/edit-site/src/store/test/actions.js
@@ -5,7 +5,6 @@ import {
toggleFeature,
setTemplate,
addTemplate,
- removeTemplate,
setTemplatePart,
setPage,
showHomepage,
@@ -76,29 +75,6 @@ describe( 'actions', () => {
} );
} );
- describe( 'removeTemplate', () => {
- it( 'should issue a deleteEntityRecord request', () => {
- const template = {
- id: 'tt1-blocks//general',
- type: 'wp_template_part',
- };
-
- const it = removeTemplate( template );
- expect( it.next().value ).toEqual( {
- actionName: 'deleteEntityRecord',
- args: [
- 'postType',
- 'wp_template_part',
- 'tt1-blocks//general',
- { force: true },
- ],
- storeKey: 'core',
- type: '@@data/DISPATCH',
- } );
- expect( it.next().done ).toBe( true );
- } );
- } );
-
describe( 'setTemplatePart', () => {
it( 'should return the SET_TEMPLATE_PART action', () => {
const templatePartId = 1;