From 57a247c64bd21cff84d6a14ba0eefa059077c129 Mon Sep 17 00:00:00 2001 From: Kelly Dwan Date: Mon, 7 Sep 2020 13:05:35 -0400 Subject: [PATCH] Block Directory: Update UI --- .../src/components/block-ratings/index.js | 21 +-- .../src/components/block-ratings/stars.js | 7 +- .../src/components/block-ratings/style.scss | 14 +- .../downloadable-block-author-info/index.js | 47 ------ .../downloadable-block-author-info/style.scss | 8 - .../downloadable-block-header/index.js | 50 ------- .../downloadable-block-header/style.scss | 17 --- .../test/fixtures/index.js | 20 --- .../downloadable-block-header/test/index.js | 76 ---------- .../downloadable-block-icon/index.js | 23 +-- .../downloadable-block-icon/style.scss | 18 +-- .../test/__snapshots__/index.js.snap | 29 ++-- .../downloadable-block-icon/test/index.js | 16 +- .../downloadable-block-info/index.js | 58 -------- .../downloadable-block-info/style.scss | 21 --- .../downloadable-block-info/test/index.js | 44 ------ .../downloadable-block-list-item/index.js | 138 +++++++++++------- .../downloadable-block-list-item/style.scss | 101 +++++++------ .../test/__snapshots__/index.js.snap | 61 -------- .../test/fixtures/index.js | 19 --- .../test/index.js | 57 ++++++-- .../downloadable-block-notice/index.js | 26 +--- .../downloadable-block-notice/style.scss | 7 +- .../test/__snapshots__/index.js.snap | 22 --- .../test/fixtures/index.js | 3 - .../downloadable-block-notice/test/index.js | 64 -------- .../downloadable-blocks-list/index.js | 23 ++- .../downloadable-blocks-list/style.scss | 7 - .../test/__snapshots__/index.js.snap | 57 -------- .../downloadable-blocks-list/test/index.js | 35 +++-- .../downloadable-blocks-panel/index.js | 81 +++++----- .../inserter-panel.js | 55 +++++++ .../downloadable-blocks-panel/no-results.js | 19 +++ .../downloadable-blocks-panel/style.scss | 45 ++++-- .../test/fixtures/index.js | 10 +- .../index.js | 12 +- packages/block-directory/src/store/actions.js | 19 ++- .../block-directory/src/store/test/actions.js | 22 ++- packages/block-directory/src/style.scss | 4 - packages/e2e-test-utils/src/inserter.js | 2 +- .../plugins/block-directory-add.test.js | 4 +- 41 files changed, 481 insertions(+), 881 deletions(-) delete mode 100644 packages/block-directory/src/components/downloadable-block-author-info/index.js delete mode 100644 packages/block-directory/src/components/downloadable-block-author-info/style.scss delete mode 100644 packages/block-directory/src/components/downloadable-block-header/index.js delete mode 100644 packages/block-directory/src/components/downloadable-block-header/style.scss delete mode 100644 packages/block-directory/src/components/downloadable-block-header/test/fixtures/index.js delete mode 100644 packages/block-directory/src/components/downloadable-block-header/test/index.js delete mode 100644 packages/block-directory/src/components/downloadable-block-info/index.js delete mode 100644 packages/block-directory/src/components/downloadable-block-info/style.scss delete mode 100644 packages/block-directory/src/components/downloadable-block-info/test/index.js delete mode 100644 packages/block-directory/src/components/downloadable-block-list-item/test/__snapshots__/index.js.snap delete mode 100644 packages/block-directory/src/components/downloadable-block-list-item/test/fixtures/index.js delete mode 100644 packages/block-directory/src/components/downloadable-block-notice/test/__snapshots__/index.js.snap delete mode 100644 packages/block-directory/src/components/downloadable-block-notice/test/fixtures/index.js delete mode 100644 packages/block-directory/src/components/downloadable-block-notice/test/index.js delete mode 100644 packages/block-directory/src/components/downloadable-blocks-list/style.scss delete mode 100644 packages/block-directory/src/components/downloadable-blocks-list/test/__snapshots__/index.js.snap create mode 100644 packages/block-directory/src/components/downloadable-blocks-panel/inserter-panel.js create mode 100644 packages/block-directory/src/components/downloadable-blocks-panel/no-results.js rename packages/block-directory/src/components/{downloadable-blocks-list => }/test/fixtures/index.js (79%) diff --git a/packages/block-directory/src/components/block-ratings/index.js b/packages/block-directory/src/components/block-ratings/index.js index c04f6c0fd7c5c..878c5b9890b08 100644 --- a/packages/block-directory/src/components/block-ratings/index.js +++ b/packages/block-directory/src/components/block-ratings/index.js @@ -1,27 +1,12 @@ -/** - * WordPress dependencies - */ -import { _n, sprintf } from '@wordpress/i18n'; - /** * Internal dependencies */ import Stars from './stars'; -export const BlockRatings = ( { rating, ratingCount } ) => ( -
+export const BlockRatings = ( { rating } ) => ( + - - ({ ratingCount }) - -
+ ); export default BlockRatings; diff --git a/packages/block-directory/src/components/block-ratings/stars.js b/packages/block-directory/src/components/block-ratings/stars.js index a2d13b0aacb51..96c03f36e1be5 100644 --- a/packages/block-directory/src/components/block-ratings/stars.js +++ b/packages/block-directory/src/components/block-ratings/stars.js @@ -17,7 +17,7 @@ function Stars( { rating } ) { const emptyStarCount = 5 - ( fullStarCount + halfStarCount ); return ( -
( @@ -34,6 +35,7 @@ function Stars( { rating } ) { { times( halfStarCount, ( i ) => ( @@ -41,11 +43,12 @@ function Stars( { rating } ) { { times( emptyStarCount, ( i ) => ( ) ) } -
+ ); } diff --git a/packages/block-directory/src/components/block-ratings/style.scss b/packages/block-directory/src/components/block-ratings/style.scss index f4333b19a9739..26314337f597d 100644 --- a/packages/block-directory/src/components/block-ratings/style.scss +++ b/packages/block-directory/src/components/block-ratings/style.scss @@ -1,15 +1,15 @@ .block-directory-block-ratings { - display: flex; - > div { - line-height: 1; + + > span { display: flex; } - .block-directory-block-ratings__rating-count { - font-size: ms(-2); + svg { + fill: $gray-900; + margin-left: -4px; } - svg { - fill: #ffb900; + .block-directory-block-ratings__star-empty { + fill: $gray-400; } } diff --git a/packages/block-directory/src/components/downloadable-block-author-info/index.js b/packages/block-directory/src/components/downloadable-block-author-info/index.js deleted file mode 100644 index 862c2dde446ce..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-author-info/index.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * WordPress dependencies - */ -import { Fragment } from '@wordpress/element'; -import { __, _n, sprintf } from '@wordpress/i18n'; - -function DownloadableBlockAuthorInfo( { - author, - authorBlockCount, - authorBlockRating, -} ) { - return ( - - - { sprintf( - /* translators: %s: author name. */ - __( 'Authored by %s' ), - author - ) } - - - { authorBlockRating > 0 - ? sprintf( - /* translators: 1: number of blocks. 2: average rating. */ - _n( - 'This author has %1$d block, with an average rating of %2$.1f.', - 'This author has %1$d blocks, with an average rating of %2$.1f.', - authorBlockCount - ), - authorBlockCount, - authorBlockRating - ) - : sprintf( - /* translators: 1: number of blocks. */ - _n( - 'This author has %1$d block.', - 'This author has %1$d blocks.', - authorBlockCount - ), - authorBlockCount - ) } - - - ); -} - -export default DownloadableBlockAuthorInfo; diff --git a/packages/block-directory/src/components/downloadable-block-author-info/style.scss b/packages/block-directory/src/components/downloadable-block-author-info/style.scss deleted file mode 100644 index 69c2cef0d7a7c..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-author-info/style.scss +++ /dev/null @@ -1,8 +0,0 @@ -.block-directory-downloadable-block-author-info__content { - font-size: 12px; -} - -.block-directory-downloadable-block-author-info__content-author { - margin-bottom: 4px; - font-size: $default-font-size; -} diff --git a/packages/block-directory/src/components/downloadable-block-header/index.js b/packages/block-directory/src/components/downloadable-block-header/index.js deleted file mode 100644 index 1917e68c14ee7..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-header/index.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/components'; -import { decodeEntities } from '@wordpress/html-entities'; - -/** - * Internal dependencies - */ -import BlockRatings from '../block-ratings'; -import DownloadableBlockIcon from '../downloadable-block-icon'; - -function DownloadableBlockHeader( { - icon, - title, - rating, - ratingCount, - isLoading = false, - isInstallable = true, - onClick, -} ) { - return ( -
- - -
-

- { decodeEntities( title ) } -

- -
- -
- ); -} - -export default DownloadableBlockHeader; diff --git a/packages/block-directory/src/components/downloadable-block-header/style.scss b/packages/block-directory/src/components/downloadable-block-header/style.scss deleted file mode 100644 index 37fe76f218319..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-header/style.scss +++ /dev/null @@ -1,17 +0,0 @@ -.block-directory-downloadable-block-header__row { - display: flex; - flex-grow: 1; - - .block-directory-downloadable-block-header__column { - display: flex; - flex-direction: column; - flex-grow: 1; - padding-left: $grid-unit-15; - } -} - -.block-directory-downloadable-block-header__title { - margin: 0; - font-size: $default-font-size; - color: currentColor; -} diff --git a/packages/block-directory/src/components/downloadable-block-header/test/fixtures/index.js b/packages/block-directory/src/components/downloadable-block-header/test/fixtures/index.js deleted file mode 100644 index 5c3f6cc9f234a..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-header/test/fixtures/index.js +++ /dev/null @@ -1,20 +0,0 @@ -const pluginBase = { - name: 'boxer/boxer', - title: 'Boxer', - description: - 'Boxer is a Block that puts your WordPress posts into boxes on a page.', - id: 'boxer-block', - rating: 5, - rating_count: 1, - active_installs: 0, - author_block_rating: 5, - author_block_count: '1', - author: 'CK Lee', - assets: [ - 'http://plugins.svn.wordpress.org/boxer-block/trunk/build/index.js', - 'http://plugins.svn.wordpress.org/boxer-block/trunk/build/view.js', - ], - humanized_updated: '3 months ago', -}; - -export const pluginWithIcon = { ...pluginBase, icon: 'block-default' }; diff --git a/packages/block-directory/src/components/downloadable-block-header/test/index.js b/packages/block-directory/src/components/downloadable-block-header/test/index.js deleted file mode 100644 index 5eecbf48effe4..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-header/test/index.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * External dependencies - */ -import { shallow } from 'enzyme'; - -/** - * WordPress dependencies - */ -import { Button } from '@wordpress/components'; - -/** - * Internal dependencies - */ -import DownloadableBlockHeader from '../index'; -import { pluginWithIcon } from './fixtures'; - -const getContainer = ( - { icon, title, rating, ratingCount }, - onClick = jest.fn(), - isLoading = false, - isInstallable = true -) => { - return shallow( - - ); -}; - -describe( 'DownloadableBlockHeader', () => { - describe( 'user interaction', () => { - test( 'should trigger the onClick function', () => { - const onClickMock = jest.fn(); - const wrapper = getContainer( pluginWithIcon, onClickMock ); - const event = { - preventDefault: jest.fn(), - }; - wrapper.find( Button ).simulate( 'click', event ); - expect( onClickMock ).toHaveBeenCalledTimes( 1 ); - expect( event.preventDefault ).toHaveBeenCalled(); - } ); - - test( 'should not trigger the onClick function if loading', () => { - const onClickMock = jest.fn(); - const wrapper = getContainer( pluginWithIcon, onClickMock, true ); - const event = { - preventDefault: jest.fn(), - }; - wrapper.find( Button ).simulate( 'click', event ); - expect( event.preventDefault ).toHaveBeenCalled(); - expect( onClickMock ).toHaveBeenCalledTimes( 0 ); - } ); - - test( 'should not trigger the onClick function if not installable', () => { - const onClickMock = jest.fn(); - const wrapper = getContainer( - pluginWithIcon, - onClickMock, - false, - false - ); - const event = { - preventDefault: jest.fn(), - }; - wrapper.find( Button ).simulate( 'click', event ); - expect( onClickMock ).toHaveBeenCalledTimes( 0 ); - expect( event.preventDefault ).toHaveBeenCalled(); - } ); - } ); -} ); diff --git a/packages/block-directory/src/components/downloadable-block-icon/index.js b/packages/block-directory/src/components/downloadable-block-icon/index.js index 77913c6aa3ae1..4e41e95e8dcb5 100644 --- a/packages/block-directory/src/components/downloadable-block-icon/index.js +++ b/packages/block-directory/src/components/downloadable-block-icon/index.js @@ -1,25 +1,14 @@ /** * WordPress dependencies */ -import { __, sprintf } from '@wordpress/i18n'; import { BlockIcon } from '@wordpress/block-editor'; -function DownloadableBlockIcon( { icon, title } ) { - return ( -
- { icon.match( /\.(jpeg|jpg|gif|png|svg)(?:\?.*)?$/ ) !== null ? ( - { - ) : ( - - ) } -
+function DownloadableBlockIcon( { icon } ) { + const className = 'block-directory-downloadable-block-icon'; + return icon.match( /\.(jpeg|jpg|gif|png|svg)(?:\?.*)?$/ ) !== null ? ( + + ) : ( + ); } diff --git a/packages/block-directory/src/components/downloadable-block-icon/style.scss b/packages/block-directory/src/components/downloadable-block-icon/style.scss index 58e39c686870e..57a792b3f7f6e 100644 --- a/packages/block-directory/src/components/downloadable-block-icon/style.scss +++ b/packages/block-directory/src/components/downloadable-block-icon/style.scss @@ -1,15 +1,7 @@ .block-directory-downloadable-block-icon { - width: $button-size; - height: $button-size; - - .block-editor-block-icon { - width: $button-size; - height: $button-size; - font-size: $button-size; - background-color: $gray-300; - } - - > img { - width: 100%; - } + min-width: $button-size * 1.5; + width: $button-size * 1.5; + height: $button-size * 1.5; + vertical-align: middle; + border: 1px solid $gray-300; } diff --git a/packages/block-directory/src/components/downloadable-block-icon/test/__snapshots__/index.js.snap b/packages/block-directory/src/components/downloadable-block-icon/test/__snapshots__/index.js.snap index 00929ab18290d..746888855f18c 100644 --- a/packages/block-directory/src/components/downloadable-block-icon/test/__snapshots__/index.js.snap +++ b/packages/block-directory/src/components/downloadable-block-icon/test/__snapshots__/index.js.snap @@ -1,33 +1,32 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Downloadable Block Icon icon rendering should render a component 1`] = ` -
- +
+ + +
`; exports[`Downloadable Block Icon icon rendering should render an tag 1`] = ` -
+
Block Name block icon
`; exports[`Downloadable Block Icon icon rendering should render an tag if icon URL has query string 1`] = ` -
+
Block Name block icon
diff --git a/packages/block-directory/src/components/downloadable-block-icon/test/index.js b/packages/block-directory/src/components/downloadable-block-icon/test/index.js index 063f4a49fddab..26e9c28e4cd9c 100644 --- a/packages/block-directory/src/components/downloadable-block-icon/test/index.js +++ b/packages/block-directory/src/components/downloadable-block-icon/test/index.js @@ -1,41 +1,41 @@ /** * External dependencies */ -import { shallow } from 'enzyme'; +import { render } from '@testing-library/react'; /** * Internal dependencies */ -import DownloadableBlockIcon from '../index'; +import DownloadableBlockIcon from '../'; const IMAGE_URL = 'https://ps.w.org/listicles/assets/icon-128x128.png'; describe( 'Downloadable Block Icon', () => { describe( 'icon rendering', () => { test( 'should render an tag', () => { - const wrapper = shallow( + const { container } = render( ); - expect( wrapper ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); test( 'should render an tag if icon URL has query string', () => { - const wrapper = shallow( + const { container } = render( ); - expect( wrapper ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); test( 'should render a component', () => { - const wrapper = shallow( + const { container } = render( ); - expect( wrapper ).toMatchSnapshot(); + expect( container ).toMatchSnapshot(); } ); } ); } ); diff --git a/packages/block-directory/src/components/downloadable-block-info/index.js b/packages/block-directory/src/components/downloadable-block-info/index.js deleted file mode 100644 index aabfcfc050b24..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-info/index.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * WordPress dependencies - */ -import { __, sprintf } from '@wordpress/i18n'; -import { decodeEntities } from '@wordpress/html-entities'; -import { Fragment } from '@wordpress/element'; -import { Icon, update, chartLine } from '@wordpress/icons'; - -function DownloadableBlockInfo( { - activeInstalls, - description, - humanizedUpdated, -} ) { - let activeInstallsString; - - if ( activeInstalls > 1000000 ) { - activeInstallsString = sprintf( - /* translators: %d: number of active installations. */ - __( '%d+ Million active installations' ), - Math.floor( activeInstalls / 1000000 ) - ); - } else if ( 0 === activeInstalls ) { - activeInstallsString = __( 'Less than 10 active installations' ); - } else { - activeInstallsString = sprintf( - /* translators: %d: number of active installations. */ - __( '%d+ active installations' ), - activeInstalls - ); - } - - return ( - -

- { decodeEntities( description ) } -

-
- - { activeInstallsString } -
-
- - { - // translators: %s: Humanized date of last update e.g: "2 months ago". - sprintf( __( 'Updated %s' ), humanizedUpdated ) - } -
-
- ); -} - -export default DownloadableBlockInfo; diff --git a/packages/block-directory/src/components/downloadable-block-info/style.scss b/packages/block-directory/src/components/downloadable-block-info/style.scss deleted file mode 100644 index fb63e381983cb..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-info/style.scss +++ /dev/null @@ -1,21 +0,0 @@ -.block-directory-downloadable-block-info__content { - margin: 0 0 $grid-unit-20; - font-size: $default-font-size; -} - -.block-directory-downloadable-block-info__meta { - display: flex; - align-items: center; - margin-bottom: 2px; - color: $gray-700; - font-size: 12px; -} - -.block-directory-downloadable-block-info__meta:last-child { - margin-bottom: 0; -} - -.block-directory-downloadable-block-info__icon { - margin-right: 4px; - fill: $gray-700; -} diff --git a/packages/block-directory/src/components/downloadable-block-info/test/index.js b/packages/block-directory/src/components/downloadable-block-info/test/index.js deleted file mode 100644 index e5972f1e61991..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-info/test/index.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * External dependencies - */ -import { shallow } from 'enzyme'; - -/** - * Internal dependencies - */ -import DownloadableBlockInfo from '../index'; - -describe( 'DownloadableBlockInfo', () => { - const metaSelector = '.block-directory-downloadable-block-info__meta'; - describe( 'Active Installs Count', () => { - it( 'should display the correct count for over a million installs', () => { - const wrapper = shallow( - - ); - - const count = wrapper.find( metaSelector ).first().text(); - - expect( count ).toContain( '10+ Million' ); - } ); - - it( 'should display the correct count for 0 installs', () => { - const wrapper = shallow( - - ); - - const count = wrapper.find( metaSelector ).first().text(); - - expect( count ).toContain( 'Less than 10 active installations' ); - } ); - - it( 'should display the correct count for 10+ and less than a Million installs', () => { - const wrapper = shallow( - - ); - - const count = wrapper.find( metaSelector ).first().text(); - - expect( count ).toContain( '100+ active installations' ); - } ); - } ); -} ); diff --git a/packages/block-directory/src/components/downloadable-block-list-item/index.js b/packages/block-directory/src/components/downloadable-block-list-item/index.js index 8a88e8593f0ad..959237b29afe8 100644 --- a/packages/block-directory/src/components/downloadable-block-list-item/index.js +++ b/packages/block-directory/src/components/downloadable-block-list-item/index.js @@ -1,79 +1,117 @@ /** * WordPress dependencies */ +import { __, sprintf } from '@wordpress/i18n'; +import { + Button, + Spinner, + VisuallyHidden, + __unstableCompositeItem as CompositeItem, +} from '@wordpress/components'; +import { createInterpolateElement } from '@wordpress/element'; +import { decodeEntities } from '@wordpress/html-entities'; +import { getBlockType } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ -import DownloadableBlockAuthorInfo from '../downloadable-block-author-info'; -import DownloadableBlockHeader from '../downloadable-block-header'; -import DownloadableBlockInfo from '../downloadable-block-info'; +import BlockRatings from '../block-ratings'; +import DownloadableBlockIcon from '../downloadable-block-icon'; import DownloadableBlockNotice from '../downloadable-block-notice'; import { store as blockDirectoryStore } from '../../store'; -export default function DownloadableBlockListItem( { item, onClick } ) { - const { isLoading, isInstallable } = useSelect( +function DownloadableBlockListItem( { composite, item, onClick } ) { + const { author, description, icon, rating, title } = item; + // getBlockType returns a block object if this block exists, or null if not. + const isInstalled = !! getBlockType( item.name ); + + const { hasNotice, isInstalling, isInstallable } = useSelect( ( select ) => { - const { isInstalling, getErrorNoticeForBlock } = select( - blockDirectoryStore - ); + const { + getErrorNoticeForBlock, + isInstalling: isBlockInstalling, + } = select( blockDirectoryStore ); const notice = getErrorNoticeForBlock( item.id ); const hasFatal = notice && notice.isFatal; return { - isLoading: isInstalling( item.id ), + hasNotice: !! notice, + isInstalling: isBlockInstalling( item.id ), isInstallable: ! hasFatal, }; }, [ item ] ); - const { - icon, - title, - description, - rating, - activeInstalls, - ratingCount, - author, - humanizedUpdated, - authorBlockCount, - authorBlockRating, - } = item; + let statusText = ''; + if ( isInstalled ) { + statusText = __( 'Installed!' ); + } else if ( isInstalling ) { + statusText = __( 'Installing…' ); + } return ( -
  • -
    -
    - -
    -
    + { + event.preventDefault(); + onClick(); + } } + isBusy={ isInstalling } + disabled={ isInstalling || ! isInstallable } + > +
    + + { isInstalling ? ( + + + + ) : ( + + ) } +
    + + + { createInterpolateElement( + sprintf( + /* translators: %1$s: block title, %2$s: author name. */ + __( '%1$s by %2$s' ), + decodeEntities( title ), + author + ), + { + span: ( + + ), + } + ) } + + { hasNotice ? ( - -
    -
    - -
    -
    -
  • + ) : ( + <> + + { !! statusText + ? statusText + : decodeEntities( description ) } + + { isInstallable && + ! ( isInstalled || isInstalling ) && ( + + { __( 'Install block' ) } + + ) } + + ) } + + ); } + +export default DownloadableBlockListItem; diff --git a/packages/block-directory/src/components/downloadable-block-list-item/style.scss b/packages/block-directory/src/components/downloadable-block-list-item/style.scss index c2de59768c54f..61b292788a03a 100644 --- a/packages/block-directory/src/components/downloadable-block-list-item/style.scss +++ b/packages/block-directory/src/components/downloadable-block-list-item/style.scss @@ -1,61 +1,78 @@ .block-directory-downloadable-block-list-item { + padding: $grid-unit-15; width: 100%; - padding: 0; - margin: 0; - display: flex; - flex-direction: row; - font-size: $default-font-size; - color: $gray-900; - align-items: flex-start; - justify-content: center; - background: transparent; - word-break: break-word; - border-top: $border-width solid $gray-300; - border-bottom: $border-width solid $gray-300; - transition: all 0.05s ease-in-out; - @include reduce-motion("transition"); - position: relative; + height: auto; text-align: left; - overflow: hidden; + display: grid; + grid-template-columns: auto 1fr; - & + .block-directory-downloadable-block-list-item { - border-top: none; + &:hover { + box-shadow: 0 0 0 $border-width-focus var(--wp-admin-theme-color); + } + + &.is-busy { + background: transparent; + + .block-directory-downloadable-block-list-item__author { + border: 0; + clip: rect(1px, 1px, 1px, 1px); + -webkit-clip-path: inset(50%); + clip-path: inset(50%); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + word-wrap: normal !important; + } } -} -.block-directory-downloadable-block-list-item:last-child:not(:only-of-type) { - border-top: 0; + &:disabled, + &[aria-disabled] { + opacity: 1; + } } -.block-directory-downloadable-block-list-item:last-child { - border-bottom: 0; +.block-directory-downloadable-block-list-item__icon { + position: relative; + margin-right: $grid-unit-20; + align-self: flex-start; + + .block-directory-downloadable-block-list-item__spinner { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: rgba(255, 255, 255, 0.75); + display: flex; + align-items: center; + justify-content: center; + } } -.block-directory-downloadable-block-list-item__panel { - display: flex; - flex-grow: 1; - flex-direction: column; +.block-directory-block-ratings { + display: block; + margin-top: $grid-unit-05; } -.block-directory-downloadable-block-list-item__header { - display: flex; - flex-direction: column; - padding: $grid-unit-20 $grid-unit-20 0; +.block-directory-downloadable-block-list-item__details { + color: $gray-900; } -.block-directory-downloadable-block-list-item__body { - display: flex; - flex-direction: column; - padding: $grid-unit-20; +.block-directory-downloadable-block-list-item__title { + display: block; + font-weight: 600; } -.block-directory-downloadable-block-list-item__footer { - display: flex; - flex-direction: column; - padding: $grid-unit-20; - background-color: $gray-100; +.block-directory-downloadable-block-list-item__author { + display: block; + margin-top: $grid-unit-05; + font-weight: normal; } -.block-directory-downloadable-block-list-item__content { - color: $gray-700; +.block-directory-downloadable-block-list-item__desc { + display: block; + margin-top: $grid-unit-10; } diff --git a/packages/block-directory/src/components/downloadable-block-list-item/test/__snapshots__/index.js.snap b/packages/block-directory/src/components/downloadable-block-list-item/test/__snapshots__/index.js.snap deleted file mode 100644 index 59ec11f93e6da..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-list-item/test/__snapshots__/index.js.snap +++ /dev/null @@ -1,61 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DownloadableBlockListItem should render a block item 1`] = ` -
  • -
    -
    - -
    -
    - - -
    -
    - -
    -
    -
  • -`; diff --git a/packages/block-directory/src/components/downloadable-block-list-item/test/fixtures/index.js b/packages/block-directory/src/components/downloadable-block-list-item/test/fixtures/index.js deleted file mode 100644 index f54e9e81b1bc2..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-list-item/test/fixtures/index.js +++ /dev/null @@ -1,19 +0,0 @@ -export const item = { - name: 'boxer/boxer', - title: 'Boxer', - description: - 'Boxer is a Block that puts your WordPress posts into boxes on a page.', - id: 'boxer-block', - icon: 'block-default', - rating: 5, - rating_count: 1, - active_installs: 0, - author_block_rating: 5, - author_block_count: '1', - author: 'CK Lee', - assets: [ - 'http://plugins.svn.wordpress.org/boxer-block/trunk/build/index.js', - 'http://plugins.svn.wordpress.org/boxer-block/trunk/build/view.js', - ], - humanized_updated: '3 months ago', -}; diff --git a/packages/block-directory/src/components/downloadable-block-list-item/test/index.js b/packages/block-directory/src/components/downloadable-block-list-item/test/index.js index ef96da905e083..8d9b1b60401e4 100644 --- a/packages/block-directory/src/components/downloadable-block-list-item/test/index.js +++ b/packages/block-directory/src/components/downloadable-block-list-item/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { shallow } from 'enzyme'; +import { render, fireEvent } from '@testing-library/react'; /** * WordPress dependencies @@ -11,9 +11,8 @@ import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ -import DownloadableBlockListItem from '../index'; -import DownloadableBlockHeader from '../../downloadable-block-header'; -import { item } from './fixtures'; +import DownloadableBlockListItem from '../'; +import { plugin } from '../../test/fixtures'; jest.mock( '@wordpress/data/src/components/use-select', () => { // This allows us to tweak the returned value on each test @@ -24,26 +23,58 @@ jest.mock( '@wordpress/data/src/components/use-select', () => { describe( 'DownloadableBlockListItem', () => { it( 'should render a block item', () => { useSelect.mockImplementation( () => ( { - isLoading: false, + isInstalling: false, isInstallable: true, } ) ); - const wrapper = shallow( - + const { queryByText } = render( + ); + const author = queryByText( `by ${ plugin.author }` ); + const description = queryByText( plugin.description ); + expect( author ).not.toBeNull(); + expect( description ).not.toBeNull(); + } ); + + it( 'should show installing status when installing the block', () => { + useSelect.mockImplementation( () => ( { + isInstalling: true, + isInstallable: true, + } ) ); - expect( wrapper ).toMatchSnapshot(); + const { queryByText } = render( + + ); + const statusLabel = queryByText( 'Installing…' ); + expect( statusLabel ).not.toBeNull(); + } ); + + it( "should be disabled when a plugin can't be installed", () => { + useSelect.mockImplementation( () => ( { + isInstalling: false, + isInstallable: false, + } ) ); + + const { getByRole } = render( + + ); + const button = getByRole( 'option' ); + expect( button.disabled ).toBe( true ); + expect( button.getAttribute( 'aria-disabled' ) ).toBe( 'true' ); } ); it( 'should try to install the block plugin', () => { + useSelect.mockImplementation( () => ( { + isInstalling: false, + isInstallable: true, + } ) ); const onClick = jest.fn(); - const wrapper = shallow( - + const { getByRole } = render( + ); - wrapper - .find( DownloadableBlockHeader ) - .simulate( 'click', { event: {} } ); + const button = getByRole( 'option' ); + fireEvent.click( button ); expect( onClick ).toHaveBeenCalledTimes( 1 ); } ); diff --git a/packages/block-directory/src/components/downloadable-block-notice/index.js b/packages/block-directory/src/components/downloadable-block-notice/index.js index f24545954e63a..79d9731049039 100644 --- a/packages/block-directory/src/components/downloadable-block-notice/index.js +++ b/packages/block-directory/src/components/downloadable-block-notice/index.js @@ -1,8 +1,6 @@ /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; -import { Button, Notice } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; /** @@ -10,7 +8,7 @@ import { useSelect } from '@wordpress/data'; */ import { store as blockDirectoryStore } from '../../store'; -export const DownloadableBlockNotice = ( { block, onClick } ) => { +export const DownloadableBlockNotice = ( { block } ) => { const errorNotice = useSelect( ( select ) => select( blockDirectoryStore ).getErrorNoticeForBlock( block.id ), @@ -22,29 +20,11 @@ export const DownloadableBlockNotice = ( { block, onClick } ) => { } return ( - +
    { errorNotice.message }
    - - +
    ); }; diff --git a/packages/block-directory/src/components/downloadable-block-notice/style.scss b/packages/block-directory/src/components/downloadable-block-notice/style.scss index aeb5b00964000..44c876cc0610a 100644 --- a/packages/block-directory/src/components/downloadable-block-notice/style.scss +++ b/packages/block-directory/src/components/downloadable-block-notice/style.scss @@ -1,8 +1,9 @@ .block-directory-downloadable-block-notice { - margin: 0 0 16px; + margin: $grid-unit-10 0 0; + color: $alert-red; } .block-directory-downloadable-block-notice__content { - padding-right: 12px; - margin-bottom: 8px; + padding-right: $grid-unit-15; + margin-bottom: $grid-unit-10; } diff --git a/packages/block-directory/src/components/downloadable-block-notice/test/__snapshots__/index.js.snap b/packages/block-directory/src/components/downloadable-block-notice/test/__snapshots__/index.js.snap deleted file mode 100644 index 0e283e5ec1a1a..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-notice/test/__snapshots__/index.js.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DownloadableBlockNotice Rendering should return something when there are error notices 1`] = ` - -
    - Plugin not found. -
    - - Retry - -
    -`; diff --git a/packages/block-directory/src/components/downloadable-block-notice/test/fixtures/index.js b/packages/block-directory/src/components/downloadable-block-notice/test/fixtures/index.js deleted file mode 100644 index c91c7b0c58695..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-notice/test/fixtures/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export const plugin = { - id: 'boxer-block', -}; diff --git a/packages/block-directory/src/components/downloadable-block-notice/test/index.js b/packages/block-directory/src/components/downloadable-block-notice/test/index.js deleted file mode 100644 index 32b3bb8c6023a..0000000000000 --- a/packages/block-directory/src/components/downloadable-block-notice/test/index.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * External dependencies - */ -import { shallow } from 'enzyme'; - -/** - * WordPress dependencies - */ -import { Button } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { DownloadableBlockNotice } from '../index'; -import { plugin } from './fixtures'; - -jest.mock( '@wordpress/data/src/components/use-select', () => { - // This allows us to tweak the returned value on each test - const mock = jest.fn(); - return mock; -} ); - -describe( 'DownloadableBlockNotice', () => { - describe( 'Rendering', () => { - it( 'should return null when there are no error notices', () => { - useSelect.mockImplementation( () => false ); - const wrapper = shallow( - - ); - expect( wrapper.isEmptyRender() ).toBe( true ); - } ); - - it( 'should return something when there are error notices', () => { - useSelect.mockImplementation( () => { - return { message: 'Plugin not found.', isFatal: false }; - } ); - const wrapper = shallow( - - ); - expect( wrapper ).toMatchSnapshot(); - } ); - } ); - - describe( 'Behavior', () => { - it( 'should trigger the callback on button click', () => { - useSelect.mockImplementation( () => 'Plugin not found.' ); - const onClick = jest.fn(); - const wrapper = shallow( - - ); - - wrapper.find( Button ).simulate( 'click', { event: {} } ); - - expect( onClick ).toHaveBeenCalledTimes( 1 ); - } ); - } ); -} ); diff --git a/packages/block-directory/src/components/downloadable-blocks-list/index.js b/packages/block-directory/src/components/downloadable-blocks-list/index.js index 377bac14f208d..da1ae64838867 100644 --- a/packages/block-directory/src/components/downloadable-blocks-list/index.js +++ b/packages/block-directory/src/components/downloadable-blocks-list/index.js @@ -6,6 +6,11 @@ import { noop } from 'lodash'; /** * WordPress dependencies */ +import { __ } from '@wordpress/i18n'; +import { + __unstableComposite as Composite, + __unstableUseCompositeState as useCompositeState, +} from '@wordpress/components'; import { useDispatch } from '@wordpress/data'; import { store as editPostStore } from '@wordpress/edit-post'; @@ -16,6 +21,7 @@ import DownloadableBlockListItem from '../downloadable-block-list-item'; import { store as blockDirectoryStore } from '../../store'; function DownloadableBlocksList( { items, onHover = noop, onSelect } ) { + const composite = useCompositeState(); const { installBlockType } = useDispatch( blockDirectoryStore ); const { setIsInserterOpened } = useDispatch( editPostStore ); @@ -24,16 +30,17 @@ function DownloadableBlocksList( { items, onHover = noop, onSelect } ) { } return ( - /* - * Disable reason: The `list` ARIA role is redundant but - * Safari+VoiceOver won't announce the list otherwise. - */ - /* eslint-disable jsx-a11y/no-redundant-roles */ -
      + { items.map( ( item ) => { return ( { installBlockType( item ).then( ( success ) => { if ( success ) { @@ -43,12 +50,12 @@ function DownloadableBlocksList( { items, onHover = noop, onSelect } ) { } ); onHover( null ); } } + onHover={ onHover } item={ item } /> ); } ) } -
    - /* eslint-enable jsx-a11y/no-redundant-roles */ + ); } diff --git a/packages/block-directory/src/components/downloadable-blocks-list/style.scss b/packages/block-directory/src/components/downloadable-blocks-list/style.scss deleted file mode 100644 index f879d3d2346d7..0000000000000 --- a/packages/block-directory/src/components/downloadable-blocks-list/style.scss +++ /dev/null @@ -1,7 +0,0 @@ -.block-directory-downloadable-blocks-list { - list-style: none; - margin: 0; - overflow: hidden; - display: flex; - flex-wrap: wrap; -} diff --git a/packages/block-directory/src/components/downloadable-blocks-list/test/__snapshots__/index.js.snap b/packages/block-directory/src/components/downloadable-blocks-list/test/__snapshots__/index.js.snap deleted file mode 100644 index f7d6a077d7e52..0000000000000 --- a/packages/block-directory/src/components/downloadable-blocks-list/test/__snapshots__/index.js.snap +++ /dev/null @@ -1,57 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DownloadableBlocksList List rendering should render plugins items into the list 1`] = ` -
      - - -
    -`; diff --git a/packages/block-directory/src/components/downloadable-blocks-list/test/index.js b/packages/block-directory/src/components/downloadable-blocks-list/test/index.js index c93197b5d4856..1926a700a8d12 100644 --- a/packages/block-directory/src/components/downloadable-blocks-list/test/index.js +++ b/packages/block-directory/src/components/downloadable-blocks-list/test/index.js @@ -1,13 +1,24 @@ /** * External dependencies */ -import { shallow } from 'enzyme'; +import { render } from '@testing-library/react'; + +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ -import DownloadableBlocksList from '../index'; -import { items } from './fixtures'; +import DownloadableBlocksList from '../'; +import { items } from '../../test/fixtures'; + +jest.mock( '@wordpress/data/src/components/use-select', () => { + // This allows us to tweak the returned value on each test + const mock = jest.fn(); + return mock; +} ); jest.mock( '@wordpress/data/src/components/use-dispatch', () => ( { useDispatch: () => ( { installBlockType: jest.fn() } ), @@ -15,28 +26,34 @@ jest.mock( '@wordpress/data/src/components/use-dispatch', () => ( { describe( 'DownloadableBlocksList', () => { describe( 'List rendering', () => { + useSelect.mockImplementation( () => ( { + isLoading: false, + isInstallable: true, + } ) ); + it( 'should render and empty list', () => { - const wrapper = shallow( + const { container } = render( ); - expect( wrapper.isEmptyRender() ).toBe( true ); + + expect( container.firstChild ).toBe( null ); } ); it( 'should render plugins items into the list', () => { - const wrapper = shallow( + const { getAllByRole } = render( ); - expect( wrapper ).toMatchSnapshot(); + const downloadableBlocks = getAllByRole( 'option' ); + + expect( downloadableBlocks ).toHaveLength( items.length ); } ); } ); } ); diff --git a/packages/block-directory/src/components/downloadable-blocks-panel/index.js b/packages/block-directory/src/components/downloadable-blocks-panel/index.js index 2929e5dc439a5..3a2d70c207bb7 100644 --- a/packages/block-directory/src/components/downloadable-blocks-panel/index.js +++ b/packages/block-directory/src/components/downloadable-blocks-panel/index.js @@ -1,79 +1,70 @@ /** * WordPress dependencies */ -import { Fragment } from '@wordpress/element'; -import { compose, useDebounce } from '@wordpress/compose'; -import { withSelect } from '@wordpress/data'; -import { __, _n, sprintf } from '@wordpress/i18n'; +import { __ } from '@wordpress/i18n'; import { Spinner } from '@wordpress/components'; -import { speak } from '@wordpress/a11y'; +import { compose } from '@wordpress/compose'; import { store as blockEditorStore } from '@wordpress/block-editor'; +import { withSelect } from '@wordpress/data'; /** * Internal dependencies */ import DownloadableBlocksList from '../downloadable-blocks-list'; +import DownloadableBlocksInserterPanel from './inserter-panel'; +import DownloadableBlocksNoResults from './no-results'; import { store as blockDirectoryStore } from '../../store'; function DownloadableBlocksPanel( { downloadableItems, onSelect, onHover, + hasLocalBlocks, hasPermission, isLoading, - isWaiting, + isTyping, } ) { - const debouncedSpeak = useDebounce( speak, 500 ); - - if ( false === hasPermission ) { - debouncedSpeak( __( 'No blocks found in your library.' ) ); + if ( typeof hasPermission === 'undefined' || isLoading || isTyping ) { return ( -

    - { __( 'No blocks found in your library.' ) } -

    + <> + { hasPermission && ! hasLocalBlocks && ( + <> +

    + { __( + 'No results available from your installed blocks.' + ) } +

    +
    + + ) } +
    + +
    + ); } - if ( typeof hasPermission === 'undefined' || isLoading || isWaiting ) { - return ( -

    - -

    - ); - } + if ( false === hasPermission ) { + if ( ! hasLocalBlocks ) { + return ; + } - if ( ! downloadableItems.length ) { - return ( -

    - { __( 'No blocks found in your library.' ) } -

    - ); + return null; } - const resultsFoundMessage = sprintf( - /* translators: %s: number of available blocks. */ - _n( - 'No blocks found in your library. We did find %d block available for download.', - 'No blocks found in your library. We did find %d blocks available for download.', - downloadableItems.length - ), - downloadableItems.length - ); - - debouncedSpeak( resultsFoundMessage ); - return ( - -

    - { __( - 'No blocks found in your library. These blocks can be downloaded and installed:' - ) } -

    + return !! downloadableItems.length ? ( + -
    + + ) : ( + ! hasLocalBlocks && ); } diff --git a/packages/block-directory/src/components/downloadable-blocks-panel/inserter-panel.js b/packages/block-directory/src/components/downloadable-blocks-panel/inserter-panel.js new file mode 100644 index 0000000000000..133c39fb6c980 --- /dev/null +++ b/packages/block-directory/src/components/downloadable-blocks-panel/inserter-panel.js @@ -0,0 +1,55 @@ +/** + * WordPress dependencies + */ +import { __, _n, sprintf } from '@wordpress/i18n'; +import { useEffect } from '@wordpress/element'; +import { speak } from '@wordpress/a11y'; + +function DownloadableBlocksInserterPanel( { + children, + downloadableItems, + hasLocalBlocks, +} ) { + const count = downloadableItems.length; + useEffect( () => { + speak( + sprintf( + /* translators: %d: number of available blocks. */ + _n( + '%d additional block is available to install.', + '%d additional blocks are available to install.', + count + ), + count + ) + ); + }, [ count ] ); + + return ( + <> + { ! hasLocalBlocks && ( +

    + { __( 'No results available from your installed blocks.' ) } +

    + ) } + +
    + +
    +
    +

    + { __( 'Available to install' ) } +

    +

    + { __( + 'Select a block to install and add it to your post.' + ) } +

    +
    + { children } +
    + + ); +} + +export default DownloadableBlocksInserterPanel; diff --git a/packages/block-directory/src/components/downloadable-blocks-panel/no-results.js b/packages/block-directory/src/components/downloadable-blocks-panel/no-results.js new file mode 100644 index 0000000000000..0b97b4abe0b9b --- /dev/null +++ b/packages/block-directory/src/components/downloadable-blocks-panel/no-results.js @@ -0,0 +1,19 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Icon, blockDefault } from '@wordpress/icons'; + +function DownloadableBlocksNoResults() { + return ( +
    + +

    { __( 'No results found.' ) }

    +
    + ); +} + +export default DownloadableBlocksNoResults; diff --git a/packages/block-directory/src/components/downloadable-blocks-panel/style.scss b/packages/block-directory/src/components/downloadable-blocks-panel/style.scss index f6b9b5bde951f..ff3fdb9ea8e31 100644 --- a/packages/block-directory/src/components/downloadable-blocks-panel/style.scss +++ b/packages/block-directory/src/components/downloadable-blocks-panel/style.scss @@ -1,20 +1,37 @@ -.block-directory-downloadable-blocks-panel__description { - font-style: italic; +.block-directory-downloadable-blocks-panel { padding: $grid-unit-20; - margin: 0; - text-align: left; - color: $gray-700; + + &.has-blocks-loading { + $no-result-padding: $grid-unit-20 * 7; + font-style: normal; + padding: 0; + margin: $no-result-padding 0; + text-align: center; + color: $gray-700; + + .components-spinner { + float: inherit; + } + } } -.block-directory-downloadable-blocks-panel__description.has-no-results { - $no-result-padding: $grid-unit-20 * 7; - font-style: normal; - padding: 0; - margin: $no-result-padding 0; - text-align: center; +.block-directory-downloadable-blocks-panel__no-local { + margin: $grid-unit-60 0; + padding: 0 $grid-unit-40 * 2; color: $gray-700; - .components-spinner { - float: inherit; - } + text-align: center; +} + +.block-directory-downloadable-blocks-panel__title { + margin: 0 0 $grid-unit-05; + font-size: 14px; +} + +.block-directory-downloadable-blocks-panel__description { + margin-top: 0; +} + +.block-directory-downloadable-blocks-panel button { + margin-top: $grid-unit-05; } diff --git a/packages/block-directory/src/components/downloadable-blocks-list/test/fixtures/index.js b/packages/block-directory/src/components/test/fixtures/index.js similarity index 79% rename from packages/block-directory/src/components/downloadable-blocks-list/test/fixtures/index.js rename to packages/block-directory/src/components/test/fixtures/index.js index 899f7f663bac0..1dc66947f09e5 100644 --- a/packages/block-directory/src/components/downloadable-blocks-list/test/fixtures/index.js +++ b/packages/block-directory/src/components/test/fixtures/index.js @@ -6,16 +6,16 @@ export const plugin = { id: 'boxer-block', icon: 'block-default', rating: 5, - rating_count: 1, - active_installs: 0, - author_block_rating: 5, - author_block_count: '1', + ratingCount: 1, + activeInstalls: 0, + authorBlockRating: 5, + authorBlockCount: '1', author: 'CK Lee', assets: [ 'http://plugins.svn.wordpress.org/boxer-block/trunk/build/index.js', 'http://plugins.svn.wordpress.org/boxer-block/trunk/build/view.js', ], - humanized_updated: '3 months ago', + humanizedUpdated: '3 months ago', }; export const items = [ diff --git a/packages/block-directory/src/plugins/inserter-menu-downloadable-blocks-panel/index.js b/packages/block-directory/src/plugins/inserter-menu-downloadable-blocks-panel/index.js index fa96d684791c4..d6528715e0343 100644 --- a/packages/block-directory/src/plugins/inserter-menu-downloadable-blocks-panel/index.js +++ b/packages/block-directory/src/plugins/inserter-menu-downloadable-blocks-panel/index.js @@ -16,7 +16,6 @@ import DownloadableBlocksPanel from '../../components/downloadable-blocks-panel' function InserterMenuDownloadableBlocksPanel() { const [ debouncedFilterValue, setFilterValue ] = useState( '' ); - const debouncedSetFilterValue = debounce( setFilterValue, 400 ); return ( @@ -28,21 +27,22 @@ function InserterMenuDownloadableBlocksPanel() { hasItems, rootClientId, } ) => { - if ( hasItems || ! filterValue ) { - return null; - } - if ( debouncedFilterValue !== filterValue ) { debouncedSetFilterValue( filterValue ); } + if ( ! debouncedFilterValue ) { + return null; + } + return ( ); } } diff --git a/packages/block-directory/src/store/actions.js b/packages/block-directory/src/store/actions.js index ee143492ab7b5..e6b4867c930f3 100644 --- a/packages/block-directory/src/store/actions.js +++ b/packages/block-directory/src/store/actions.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { store as blocksStore } from '@wordpress/blocks'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { controls } from '@wordpress/data'; import { apiFetch } from '@wordpress/data-controls'; import { store as noticesStore } from '@wordpress/notices'; @@ -96,6 +96,19 @@ export function* installBlockType( block ) { ); } + yield controls.dispatch( + noticesStore, + 'createInfoNotice', + sprintf( + // translators: %s is the block title. + __( 'Block %s installed and added.' ), + block.title + ), + { + speak: true, + type: 'snackbar', + } + ); success = true; } catch ( error ) { let message = error.message || __( 'An error occurred.' ); @@ -119,6 +132,10 @@ export function* installBlockType( block ) { } yield setErrorNotice( id, message, isFatal ); + yield controls.dispatch( noticesStore, 'createErrorNotice', message, { + speak: true, + isDismissible: true, + } ); } yield setIsInstalling( block.id, false ); return success; diff --git a/packages/block-directory/src/store/test/actions.js b/packages/block-directory/src/store/test/actions.js index 0b40494b44d83..d076b8752bfa6 100644 --- a/packages/block-directory/src/store/test/actions.js +++ b/packages/block-directory/src/store/test/actions.js @@ -90,7 +90,13 @@ describe( 'actions', () => { type: '@@data/SELECT', } ); - expect( generator.next( [ block ] ).value ).toEqual( { + expect( generator.next( [ block ] ).value ).toMatchObject( { + type: '@@data/DISPATCH', + actionName: 'createInfoNotice', + storeKey: noticesStore, + } ); + + expect( generator.next().value ).toEqual( { type: 'SET_INSTALLING_BLOCK', blockId: block.id, isInstalling: false, @@ -152,7 +158,13 @@ describe( 'actions', () => { type: '@@data/SELECT', } ); - expect( generator.next( [ inactiveBlock ] ).value ).toEqual( { + expect( generator.next( [ inactiveBlock ] ).value ).toMatchObject( { + type: '@@data/DISPATCH', + actionName: 'createInfoNotice', + storeKey: noticesStore, + } ); + + expect( generator.next().value ).toEqual( { type: 'SET_INSTALLING_BLOCK', blockId: inactiveBlock.id, isInstalling: false, @@ -196,6 +208,12 @@ describe( 'actions', () => { blockId: block.id, } ); + expect( generator.next().value ).toMatchObject( { + type: '@@data/DISPATCH', + actionName: 'createErrorNotice', + storeKey: noticesStore, + } ); + expect( generator.next().value ).toEqual( { type: 'SET_INSTALLING_BLOCK', blockId: block.id, diff --git a/packages/block-directory/src/style.scss b/packages/block-directory/src/style.scss index 82cc67442872a..8d2ab7148756b 100644 --- a/packages/block-directory/src/style.scss +++ b/packages/block-directory/src/style.scss @@ -1,11 +1,7 @@ @import "./components/block-ratings/style.scss"; @import "./components/compact-list/style.scss"; -@import "./components/downloadable-block-author-info/style.scss"; -@import "./components/downloadable-block-header/style.scss"; @import "./components/downloadable-block-icon/style.scss"; -@import "./components/downloadable-block-info/style.scss"; @import "./components/downloadable-block-list-item/style.scss"; @import "./components/downloadable-block-notice/style.scss"; -@import "./components/downloadable-blocks-list/style.scss"; @import "./components/downloadable-blocks-panel/style.scss"; @import "./plugins/installed-blocks-pre-publish-panel/style.scss"; diff --git a/packages/e2e-test-utils/src/inserter.js b/packages/e2e-test-utils/src/inserter.js index 0b58f730f9bfb..4763e99f3f10e 100644 --- a/packages/e2e-test-utils/src/inserter.js +++ b/packages/e2e-test-utils/src/inserter.js @@ -188,7 +188,7 @@ export async function insertBlockDirectoryBlock( searchTerm ) { // Grab the first block in the list const insertButton = await page.waitForSelector( - '.block-directory-downloadable-blocks-list li:first-child button' + '.block-directory-downloadable-blocks-list button:first-child' ); await insertButton.click(); // We should wait until the inserter closes and the focus moves to the content. diff --git a/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js b/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js index dde952f627477..a659716602715 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js +++ b/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js @@ -171,7 +171,9 @@ describe( 'adding blocks from block directory', () => { document.querySelector( '.block-editor-inserter__main-area' ) .innerHTML ); - expect( selectorContent ).toContain( 'has-no-results' ); + expect( selectorContent ).toContain( + 'block-editor-inserter__no-results' + ); } ); it( 'Should be able to add (the first) block.', async () => {