Skip to content

Commit

Permalink
Add success and error snackbars to the templates list page (#36808)
Browse files Browse the repository at this point in the history
* Add success and error snackbars to the list page

* Fix Unit Test error

* Apply 'is-navigation-open' to interface skeleton

* Fix NavigationToggle unit test

* Apply suggestions from code review

Co-authored-by: Robert Anderson <robert@noisysocks.com>

* Use deleting

* Remove snackbars for creation

* Add notices for reverting

* Fix test

* Add getLastEntityDeleteError

* Add comment

Co-authored-by: George Mamadashvili <georgemamadashvili@gmail.com>
Co-authored-by: Robert Anderson <robert@noisysocks.com>
  • Loading branch information
3 people committed Nov 26, 2021
1 parent 9aeb7d7 commit 63bd2bf
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 128 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/edit-site/package.json
Expand Up @@ -52,6 +52,7 @@
"@wordpress/primitives": "file:../primitives",
"@wordpress/reusable-blocks": "file:../reusable-blocks",
"@wordpress/url": "file:../url",
"@wordpress/viewport": "file:../viewport",
"classnames": "^2.3.1",
"downloadjs": "^1.4.7",
"file-saver": "^2.0.2",
Expand Down
Expand Up @@ -7,9 +7,12 @@ import { kebabCase } from 'lodash';
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { Button } from '@wordpress/components';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';

/**
* Internal dependencies
Expand All @@ -18,31 +21,43 @@ import CreateTemplatePartModal from '../create-template-part-modal';

export default function NewTemplatePart( { postType } ) {
const [ isModalOpen, setIsModalOpen ] = useState( false );
const { createErrorNotice } = useDispatch( noticesStore );

async function createTemplatePart( { title, area } ) {
if ( ! title ) {
createErrorNotice( __( 'Title is not defined.' ), {
type: 'snackbar',
} );
return;
}

const templatePart = await apiFetch( {
path: '/wp/v2/template-parts',
method: 'POST',
data: {
slug: kebabCase( title ),
title,
content: '',
area,
},
} );
try {
const templatePart = await apiFetch( {
path: '/wp/v2/template-parts',
method: 'POST',
data: {
slug: kebabCase( title ),
title,
content: '',
area,
},
} );

// Navigate to the created template part editor.
window.location.href = addQueryArgs( window.location.href, {
postId: templatePart.id,
postType: 'wp_template_part',
} );
// Navigate to the created template part editor.
window.location.href = addQueryArgs( window.location.href, {
postId: templatePart.id,
postType: 'wp_template_part',
} );
} catch ( error ) {
const errorMessage =
error.message && error.code !== 'unknown_error'
? error.message
: __(
'An error occurred while creating the template part.'
);

// Wait for async navigation to happen before closing the modal.
await new Promise( () => {} );
createErrorNotice( errorMessage, { type: 'snackbar' } );
}
}

return (
Expand Down
55 changes: 37 additions & 18 deletions packages/edit-site/src/components/add-new-template/new-template.js
Expand Up @@ -12,11 +12,13 @@ import {
MenuItem,
NavigableMenu,
} from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { store as editorStore } from '@wordpress/editor';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';

const DEFAULT_TEMPLATE_SLUGS = [
'front-page',
Expand All @@ -42,27 +44,44 @@ export default function NewTemplate( { postType } ) {
} ),
[]
);
const { createErrorNotice } = useDispatch( noticesStore );

async function createTemplate( { slug } ) {
const { title, description } = find( defaultTemplateTypes, { slug } );
try {
const { title, description } = find( defaultTemplateTypes, {
slug,
} );

const template = await apiFetch( {
path: '/wp/v2/templates',
method: 'POST',
data: {
excerpt: description,
// Slugs need to be strings, so this is for template `404`
slug: slug.toString(),
status: 'publish',
title,
},
} );
const template = await apiFetch( {
path: '/wp/v2/templates',
method: 'POST',
data: {
excerpt: description,
// Slugs need to be strings, so this is for template `404`
slug: slug.toString(),
status: 'publish',
title,
},
} );

// Navigate to the created template editor.
window.location.href = addQueryArgs( window.location.href, {
postId: template.id,
postType: 'wp_template',
} );
// Navigate to the created template editor.
window.location.href = addQueryArgs( window.location.href, {
postId: template.id,
postType: 'wp_template',
} );

// Wait for async navigation to happen before closing the modal.
await new Promise( () => {} );
} catch ( error ) {
const errorMessage =
error.message && error.code !== 'unknown_error'
? error.message
: __( 'An error occurred while creating the template.' );

createErrorNotice( errorMessage, {
type: 'snackbar',
} );
}
}

const existingTemplateSlugs = map( templates, 'slug' );
Expand Down
38 changes: 27 additions & 11 deletions packages/edit-site/src/components/list/index.js
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
Expand All @@ -6,6 +11,7 @@ import { useSelect } from '@wordpress/data';
import { InterfaceSkeleton } from '@wordpress/interface';
import { __, sprintf } from '@wordpress/i18n';
import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
import { EditorSnackbars } from '@wordpress/editor';

/**
* Internal dependencies
Expand All @@ -14,20 +20,27 @@ import useRegisterShortcuts from './use-register-shortcuts';
import Header from './header';
import NavigationSidebar from '../navigation-sidebar';
import Table from './table';
import { store as editSiteStore } from '../../store';

export default function List( { templateType } ) {
useRegisterShortcuts();

const { previousShortcut, nextShortcut } = useSelect( ( select ) => {
return {
previousShortcut: select(
keyboardShortcutsStore
).getAllShortcutKeyCombinations( 'core/edit-site/previous-region' ),
nextShortcut: select(
keyboardShortcutsStore
).getAllShortcutKeyCombinations( 'core/edit-site/next-region' ),
};
}, [] );
const { previousShortcut, nextShortcut, isNavigationOpen } = useSelect(
( select ) => {
return {
previousShortcut: select(
keyboardShortcutsStore
).getAllShortcutKeyCombinations(
'core/edit-site/previous-region'
),
nextShortcut: select(
keyboardShortcutsStore
).getAllShortcutKeyCombinations( 'core/edit-site/next-region' ),
isNavigationOpen: select( editSiteStore ).isNavigationOpened(),
};
},
[]
);

const postType = useSelect(
( select ) => select( coreStore ).getPostType( templateType ),
Expand All @@ -54,7 +67,9 @@ export default function List( { templateType } ) {

return (
<InterfaceSkeleton
className="edit-site-list"
className={ classnames( 'edit-site-list', {
'is-navigation-open': isNavigationOpen,
} ) }
labels={ {
drawer: __( 'Navigation Sidebar' ),
...detailedRegionLabels,
Expand All @@ -66,6 +81,7 @@ export default function List( { templateType } ) {
isDefaultOpen
/>
}
notices={ <EditorSnackbars /> }
content={
<main className="edit-site-list-main">
<Table templateType={ templateType } />
Expand Down
6 changes: 6 additions & 0 deletions packages/edit-site/src/components/list/style.scss
Expand Up @@ -114,3 +114,9 @@
border-top: none;
}
}

.edit-site-list.is-navigation-open .components-snackbar-list {
@include break-medium() {
margin-left: $nav-sidebar-width;
}
}
25 changes: 23 additions & 2 deletions packages/edit-site/src/components/list/table.js
Expand Up @@ -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
Expand All @@ -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 );
Expand All @@ -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 (
Expand Down
25 changes: 9 additions & 16 deletions 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';

Expand All @@ -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 (
<>
<NavigationToggle
isOpen={ isNavigationOpen }
setIsOpen={ setIsNavigationOpen }
/>
<NavigationPanel
isOpen={ isNavigationOpen }
setIsOpen={ setIsNavigationOpen }
activeItem={ activeTemplateType }
/>
<NavigationToggle />
<NavigationPanel activeItem={ activeTemplateType } />
<NavigationPanelPreviewSlot />
</>
);
Expand Down

0 comments on commit 63bd2bf

Please sign in to comment.