From b4d0011651fbd4f7f11c2c18dc8c5904a28f7ee8 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Sat, 9 Sep 2023 00:37:55 +0800 Subject: [PATCH 01/10] Allow import/export patterns as JSON files --- .../src/components/add-new-pattern/index.js | 45 ++++++++++++- .../src/components/page-patterns/grid-item.js | 22 ++++++ .../src/components/create-pattern-modal.js | 8 +-- .../src/components/pattern-convert-button.js | 26 ++++++- packages/patterns/src/index.js | 3 +- packages/patterns/src/store/actions.js | 67 ++++++++++++------- 6 files changed, 136 insertions(+), 35 deletions(-) diff --git a/packages/edit-site/src/components/add-new-pattern/index.js b/packages/edit-site/src/components/add-new-pattern/index.js index 5e0f1626fc8fd..d586339b22221 100644 --- a/packages/edit-site/src/components/add-new-pattern/index.js +++ b/packages/edit-site/src/components/add-new-pattern/index.js @@ -2,12 +2,16 @@ * WordPress dependencies */ import { DropdownMenu } from '@wordpress/components'; -import { useState } from '@wordpress/element'; +import { useState, useRef } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { plus, symbol, symbolFilled } from '@wordpress/icons'; -import { useSelect } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { privateApis as routerPrivateApis } from '@wordpress/router'; -import { privateApis as editPatternsPrivateApis } from '@wordpress/patterns'; +import { + privateApis as editPatternsPrivateApis, + store as patternsStore, +} from '@wordpress/patterns'; +import { store as noticesStore } from '@wordpress/notices'; /** * Internal dependencies @@ -15,6 +19,7 @@ import { privateApis as editPatternsPrivateApis } from '@wordpress/patterns'; import CreateTemplatePartModal from '../create-template-part-modal'; import SidebarButton from '../sidebar-button'; import { unlock } from '../../lock-unlock'; +import { USER_PATTERN_CATEGORY } from '../page-patterns/utils'; import { store as editSiteStore } from '../../store'; const { useHistory } = unlock( routerPrivateApis ); @@ -29,6 +34,10 @@ export default function AddNewPattern() { const settings = select( editSiteStore ).getSettings(); return !! settings.supportsTemplatePartsMode; }, [] ); + const { __experimentalCreatePatternFromFile: createPatternFromFile } = + useDispatch( patternsStore ); + const { createErrorNotice } = useDispatch( noticesStore ); + const patternUploadInputRef = useRef(); function handleCreatePattern( { pattern, categoryId } ) { setShowPatternModal( false ); @@ -64,6 +73,13 @@ export default function AddNewPattern() { onClick: () => setShowPatternModal( true ), title: __( 'Create pattern' ), }, + { + icon: symbol, + onClick: () => { + patternUploadInputRef.current.click(); + }, + title: __( 'Import pattern from JSON' ), + }, ]; // Remove condition when command palette issues are resolved. @@ -101,6 +117,29 @@ export default function AddNewPattern() { onError={ handleError } /> ) } + + { + const file = event.target.files?.[ 0 ]; + if ( ! file ) return; + try { + const pattern = await createPatternFromFile( file ); + handleCreatePattern( { + pattern, + categoryId: USER_PATTERN_CATEGORY, + } ); + } catch ( err ) { + createErrorNotice( err.message, { + type: 'snackbar', + id: 'import-pattern-error', + } ); + } + } } + /> ); } diff --git a/packages/edit-site/src/components/page-patterns/grid-item.js b/packages/edit-site/src/components/page-patterns/grid-item.js index a9c6fdc2d9d1a..690df0bbb9a32 100644 --- a/packages/edit-site/src/components/page-patterns/grid-item.js +++ b/packages/edit-site/src/components/page-patterns/grid-item.js @@ -2,6 +2,8 @@ * External dependencies */ import classnames from 'classnames'; +import downloadjs from 'downloadjs'; +import { paramCase as kebabCase } from 'change-case'; /** * WordPress dependencies @@ -108,6 +110,20 @@ function GridItem( { categoryId, item, ...props } ) { }; const deleteItem = () => isTemplatePart ? removeTemplate( item ) : deletePattern(); + const exportAsJSON = () => { + const json = { + __file: item.type, + title: item.title, + content: item.reusableBlock.content.raw, + syncStatus: item.reusableBlock.wp_pattern_sync_status, + }; + + downloadjs( + JSON.stringify( json, null, 2 ), + `${ kebabCase( item.title ) }.json`, + 'application/json' + ); + }; // Only custom patterns or custom template parts can be renamed or deleted. const isCustomPattern = @@ -276,6 +292,12 @@ function GridItem( { categoryId, item, ...props } ) { onClose={ onClose } label={ __( 'Duplicate' ) } /> + { item.type === USER_PATTERNS && ( + exportAsJSON() }> + { __( 'Export as JSON' ) } + + ) } + { isCustomPattern && ( { @@ -74,12 +82,26 @@ export default function PatternConvertButton( { clientIds, rootClientId } ) { }, [ clientIds, rootClientId ] ); + const content = useSelect( + ( select ) => + serialize( + select( blockEditorStore ).getBlocksByClientId( clientIds ) + ), + [ clientIds ] + ); if ( ! canConvert ) { return null; } const handleSuccess = ( { pattern } ) => { + const newBlock = createBlock( 'core/block', { + ref: pattern.id, + } ); + + replaceBlocks( clientIds, newBlock ); + __experimentalSetEditingPattern( newBlock.clientId, true ); + createSuccessNotice( pattern.wp_pattern_sync_status === 'unsynced' ? sprintf( @@ -111,7 +133,7 @@ export default function PatternConvertButton( { clientIds, rootClientId } ) { { isModalOpen && ( { handleSuccess( pattern ); } } diff --git a/packages/patterns/src/index.js b/packages/patterns/src/index.js index ed74eba99ffae..38cbd8e95737d 100644 --- a/packages/patterns/src/index.js +++ b/packages/patterns/src/index.js @@ -1,6 +1,5 @@ /** * Internal dependencies */ -import './store'; - +export { store } from './store'; export * from './private-apis'; diff --git a/packages/patterns/src/store/actions.js b/packages/patterns/src/store/actions.js index 589dad326d3b6..1231f73f60146 100644 --- a/packages/patterns/src/store/actions.js +++ b/packages/patterns/src/store/actions.js @@ -2,7 +2,7 @@ * WordPress dependencies */ -import { parse, serialize, createBlock } from '@wordpress/blocks'; +import { parse } from '@wordpress/blocks'; import { store as coreStore } from '@wordpress/core-data'; import { store as blockEditorStore } from '@wordpress/block-editor'; @@ -14,14 +14,14 @@ import { PATTERN_SYNC_TYPES } from '../constants'; /** * Returns a generator converting one or more static blocks into a pattern, or creating a new empty pattern. * - * @param {string} title Pattern title. - * @param {'full'|'unsynced'} syncType They way block is synced, 'full' or 'unsynced'. - * @param {string[]|undefined} clientIds Optional client IDs of blocks to convert to pattern. - * @param {number[]|undefined} categories Ids of any selected categories. + * @param {string} title Pattern title. + * @param {'full'|'unsynced'} syncType They way block is synced, 'full' or 'unsynced'. + * @param {string|undefined} [content] Optional serialized content of blocks to convert to pattern. + * @param {number[]|undefined} [categories] Ids of any selected categories. */ export const createPattern = - ( title, syncType, clientIds, categories ) => - async ( { registry, dispatch } ) => { + ( title, syncType, content, categories ) => + async ( { registry } ) => { const meta = syncType === PATTERN_SYNC_TYPES.unsynced ? { @@ -31,13 +31,7 @@ export const createPattern = const reusableBlock = { title, - content: clientIds - ? serialize( - registry - .select( blockEditorStore ) - .getBlocksByClientId( clientIds ) - ) - : undefined, + content, status: 'publish', meta, wp_pattern_category: categories, @@ -47,18 +41,43 @@ export const createPattern = .dispatch( coreStore ) .saveEntityRecord( 'postType', 'wp_block', reusableBlock ); - if ( syncType === 'unsynced' || ! clientIds ) { - return updatedRecord; + return updatedRecord; + }; + +/** + * Create a pattern from a JSON file. + * @param {File} file The JSON file instance of the pattern. + */ +export const createPatternFromFile = + ( file ) => + async ( { dispatch } ) => { + const fileContent = await file.text(); + /** @type {import('./types').PatternJSON} */ + let parsedContent; + try { + parsedContent = JSON.parse( fileContent ); + } catch ( e ) { + throw new Error( 'Invalid JSON file' ); + } + if ( + parsedContent.__file !== 'wp_block' || + ! parsedContent.title || + ! parsedContent.content || + typeof parsedContent.title !== 'string' || + typeof parsedContent.content !== 'string' || + ( parsedContent.syncStatus && + typeof parsedContent.syncStatus !== 'string' ) + ) { + throw new Error( 'Invalid Pattern JSON file' ); } - const newBlock = createBlock( 'core/block', { - ref: updatedRecord.id, - } ); - registry - .dispatch( blockEditorStore ) - .replaceBlocks( clientIds, newBlock ); - dispatch.setEditingPattern( newBlock.clientId, true ); - return updatedRecord; + const pattern = await dispatch.__experimentalCreatePattern( + parsedContent.title, + parsedContent.syncStatus, + parsedContent.content + ); + + return pattern; }; /** From ad92048238c53ae08ba21b1adcd60f90d6ea1b81 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Mon, 11 Sep 2023 11:13:10 +0800 Subject: [PATCH 02/10] Add success notice --- .../src/components/add-new-pattern/index.js | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/edit-site/src/components/add-new-pattern/index.js b/packages/edit-site/src/components/add-new-pattern/index.js index d586339b22221..b1d791a8ea70b 100644 --- a/packages/edit-site/src/components/add-new-pattern/index.js +++ b/packages/edit-site/src/components/add-new-pattern/index.js @@ -3,7 +3,7 @@ */ import { DropdownMenu } from '@wordpress/components'; import { useState, useRef } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { plus, symbol, symbolFilled } from '@wordpress/icons'; import { useSelect, useDispatch } from '@wordpress/data'; import { privateApis as routerPrivateApis } from '@wordpress/router'; @@ -19,7 +19,6 @@ import { store as noticesStore } from '@wordpress/notices'; import CreateTemplatePartModal from '../create-template-part-modal'; import SidebarButton from '../sidebar-button'; import { unlock } from '../../lock-unlock'; -import { USER_PATTERN_CATEGORY } from '../page-patterns/utils'; import { store as editSiteStore } from '../../store'; const { useHistory } = unlock( routerPrivateApis ); @@ -36,7 +35,8 @@ export default function AddNewPattern() { }, [] ); const { __experimentalCreatePatternFromFile: createPatternFromFile } = useDispatch( patternsStore ); - const { createErrorNotice } = useDispatch( noticesStore ); + const { createSuccessNotice, createErrorNotice } = + useDispatch( noticesStore ); const patternUploadInputRef = useRef(); function handleCreatePattern( { pattern, categoryId } ) { @@ -128,10 +128,18 @@ export default function AddNewPattern() { if ( ! file ) return; try { const pattern = await createPatternFromFile( file ); - handleCreatePattern( { - pattern, - categoryId: USER_PATTERN_CATEGORY, - } ); + + createSuccessNotice( + sprintf( + // translators: %s: The imported pattern's title. + __( 'Imported "%s" from JSON.' ), + pattern.title.raw + ), + { + type: 'snackbar', + id: 'import-pattern-success', + } + ); } catch ( err ) { createErrorNotice( err.message, { type: 'snackbar', From 94a3440479bd6e9ed41c70ca76623d051a0e04a7 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Mon, 11 Sep 2023 11:33:00 +0800 Subject: [PATCH 03/10] Lazily evaluate content --- .../src/components/page-patterns/grid-item.js | 2 +- .../src/components/create-pattern-modal.js | 52 ++++++++----------- .../src/components/pattern-convert-button.js | 14 +++-- 3 files changed, 28 insertions(+), 40 deletions(-) diff --git a/packages/edit-site/src/components/page-patterns/grid-item.js b/packages/edit-site/src/components/page-patterns/grid-item.js index 690df0bbb9a32..8c4c8592c645d 100644 --- a/packages/edit-site/src/components/page-patterns/grid-item.js +++ b/packages/edit-site/src/components/page-patterns/grid-item.js @@ -118,7 +118,7 @@ function GridItem( { categoryId, item, ...props } ) { syncStatus: item.reusableBlock.wp_pattern_sync_status, }; - downloadjs( + return downloadjs( JSON.stringify( json, null, 2 ), `${ kebabCase( item.title ) }.json`, 'application/json' diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index b051e14b5a02c..805b297d3c8a2 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -10,7 +10,7 @@ import { ToggleControl, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useState, useCallback } from '@wordpress/element'; +import { useState } from '@wordpress/element'; import { useDispatch } from '@wordpress/data'; import { store as noticesStore } from '@wordpress/notices'; @@ -38,36 +38,26 @@ export default function CreatePatternModal( { const { createPattern } = useDispatch( store ); const { createErrorNotice } = useDispatch( noticesStore ); - const onCreate = useCallback( - async function ( patternTitle, sync ) { - try { - const newPattern = await createPattern( - patternTitle, - sync, - content, - categories - ); - onSuccess( { - pattern: newPattern, - categoryId: PATTERN_DEFAULT_CATEGORY, - } ); - } catch ( error ) { - createErrorNotice( error.message, { - type: 'snackbar', - id: 'convert-to-pattern-error', - } ); - onError(); - } - }, - [ - createPattern, - content, - categories, - onSuccess, - createErrorNotice, - onError, - ] - ); + async function onCreate( patternTitle, sync ) { + try { + const newPattern = await createPattern( + patternTitle, + sync, + typeof content === 'function' ? content() : content, + categories + ); + onSuccess( { + pattern: newPattern, + categoryId: PATTERN_DEFAULT_CATEGORY, + } ); + } catch ( error ) { + createErrorNotice( error.message, { + type: 'snackbar', + id: 'convert-to-pattern-error', + } ); + onError(); + } + } const handleCategorySelection = ( selectedCategories ) => { setCategories( selectedCategories.map( ( cat ) => cat.id ) ); diff --git a/packages/patterns/src/components/pattern-convert-button.js b/packages/patterns/src/components/pattern-convert-button.js index 03e52ace490ba..474b5aefccf8e 100644 --- a/packages/patterns/src/components/pattern-convert-button.js +++ b/packages/patterns/src/components/pattern-convert-button.js @@ -8,7 +8,7 @@ import { serialize, } from '@wordpress/blocks'; import { store as blockEditorStore } from '@wordpress/block-editor'; -import { useState } from '@wordpress/element'; +import { useState, useCallback } from '@wordpress/element'; import { MenuItem } from '@wordpress/components'; import { symbol } from '@wordpress/icons'; import { useSelect, useDispatch } from '@wordpress/data'; @@ -82,12 +82,10 @@ export default function PatternConvertButton( { clientIds, rootClientId } ) { }, [ clientIds, rootClientId ] ); - const content = useSelect( - ( select ) => - serialize( - select( blockEditorStore ).getBlocksByClientId( clientIds ) - ), - [ clientIds ] + const { getBlocksByClientId } = useSelect( blockEditorStore ); + const getContent = useCallback( + () => serialize( getBlocksByClientId( clientIds ) ), + [ getBlocksByClientId, clientIds ] ); if ( ! canConvert ) { @@ -133,7 +131,7 @@ export default function PatternConvertButton( { clientIds, rootClientId } ) { { isModalOpen && ( { handleSuccess( pattern ); } } From 33dbc9305079ceee6861b2a86c253a5bd25c9e59 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Tue, 12 Sep 2023 15:52:25 +0800 Subject: [PATCH 04/10] Use private selectors and actions --- .../edit-site/src/components/add-new-pattern/index.js | 3 +-- packages/patterns/src/components/create-pattern-modal.js | 5 +++-- .../patterns/src/components/pattern-convert-button.js | 7 +++++-- .../patterns/src/components/patterns-manage-button.js | 9 +++++++-- packages/patterns/src/store/index.js | 5 +++-- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/edit-site/src/components/add-new-pattern/index.js b/packages/edit-site/src/components/add-new-pattern/index.js index b1d791a8ea70b..16907006809f6 100644 --- a/packages/edit-site/src/components/add-new-pattern/index.js +++ b/packages/edit-site/src/components/add-new-pattern/index.js @@ -33,8 +33,7 @@ export default function AddNewPattern() { const settings = select( editSiteStore ).getSettings(); return !! settings.supportsTemplatePartsMode; }, [] ); - const { __experimentalCreatePatternFromFile: createPatternFromFile } = - useDispatch( patternsStore ); + const { createPatternFromFile } = unlock( useDispatch( patternsStore ) ); const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore ); const patternUploadInputRef = useRef(); diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 805b297d3c8a2..189004b6a046b 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -22,8 +22,9 @@ import { PATTERN_DEFAULT_CATEGORY, PATTERN_SYNC_TYPES } from '../constants'; /** * Internal dependencies */ -import { store } from '../store'; +import { store as patternsStore } from '../store'; import CategorySelector from './category-selector'; +import { unlock } from '../lock-unlock'; export default function CreatePatternModal( { onSuccess, @@ -35,7 +36,7 @@ export default function CreatePatternModal( { const [ syncType, setSyncType ] = useState( PATTERN_SYNC_TYPES.full ); const [ categories, setCategories ] = useState( [] ); const [ title, setTitle ] = useState( '' ); - const { createPattern } = useDispatch( store ); + const { createPattern } = unlock( useDispatch( patternsStore ) ); const { createErrorNotice } = useDispatch( noticesStore ); async function onCreate( patternTitle, sync ) { diff --git a/packages/patterns/src/components/pattern-convert-button.js b/packages/patterns/src/components/pattern-convert-button.js index 474b5aefccf8e..8434009133871 100644 --- a/packages/patterns/src/components/pattern-convert-button.js +++ b/packages/patterns/src/components/pattern-convert-button.js @@ -20,6 +20,7 @@ import { store as noticesStore } from '@wordpress/notices'; */ import { store as patternsStore } from '../store'; import CreatePatternModal from './create-pattern-modal'; +import { unlock } from '../lock-unlock'; /** * Menu control to convert block(s) to a pattern block. @@ -32,7 +33,9 @@ import CreatePatternModal from './create-pattern-modal'; export default function PatternConvertButton( { clientIds, rootClientId } ) { const { createSuccessNotice } = useDispatch( noticesStore ); const { replaceBlocks } = useDispatch( blockEditorStore ); - const { __experimentalSetEditingPattern } = useDispatch( patternsStore ); + // Ignore reason: false positive of the lint rule. + // eslint-disable-next-line @wordpress/no-unused-vars-before-return + const { setEditingPattern } = unlock( useDispatch( patternsStore ) ); const [ isModalOpen, setIsModalOpen ] = useState( false ); const canConvert = useSelect( ( select ) => { @@ -98,7 +101,7 @@ export default function PatternConvertButton( { clientIds, rootClientId } ) { } ); replaceBlocks( clientIds, newBlock ); - __experimentalSetEditingPattern( newBlock.clientId, true ); + setEditingPattern( newBlock.clientId, true ); createSuccessNotice( pattern.wp_pattern_sync_status === 'unsynced' diff --git a/packages/patterns/src/components/patterns-manage-button.js b/packages/patterns/src/components/patterns-manage-button.js index eae307f1838de..5f407682bea0f 100644 --- a/packages/patterns/src/components/patterns-manage-button.js +++ b/packages/patterns/src/components/patterns-manage-button.js @@ -12,7 +12,8 @@ import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies */ -import { store as editorStore } from '../store'; +import { store as patternsStore } from '../store'; +import { unlock } from '../lock-unlock'; function PatternsManageButton( { clientId } ) { const { canRemove, isVisible, innerBlockCount, managePatternsUrl } = @@ -51,7 +52,11 @@ function PatternsManageButton( { clientId } ) { [ clientId ] ); - const { convertSyncedPatternToStatic } = useDispatch( editorStore ); + // Ignore reason: false positive of the lint rule. + // eslint-disable-next-line @wordpress/no-unused-vars-before-return + const { convertSyncedPatternToStatic } = unlock( + useDispatch( patternsStore ) + ); if ( ! isVisible ) { return null; diff --git a/packages/patterns/src/store/index.js b/packages/patterns/src/store/index.js index 6293a7b33408e..af3da7f0ff498 100644 --- a/packages/patterns/src/store/index.js +++ b/packages/patterns/src/store/index.js @@ -10,6 +10,7 @@ import reducer from './reducer'; import * as actions from './actions'; import { STORE_NAME } from './constants'; import * as selectors from './selectors'; +import { unlock } from '../lock-unlock'; /** * Post editor data store configuration. @@ -20,8 +21,6 @@ import * as selectors from './selectors'; */ export const storeConfig = { reducer, - selectors, - actions, }; /** @@ -36,3 +35,5 @@ export const store = createReduxStore( STORE_NAME, { } ); register( store ); +unlock( store ).registerPrivateActions( actions ); +unlock( store ).registerPrivateSelectors( selectors ); From 768d534e39ea69e8e5539efa436f010861f63ebc Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Wed, 20 Sep 2023 11:09:09 +0800 Subject: [PATCH 05/10] Fix conflict error --- packages/edit-site/src/components/page-patterns/grid-item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/page-patterns/grid-item.js b/packages/edit-site/src/components/page-patterns/grid-item.js index 8c4c8592c645d..701d7ff603d69 100644 --- a/packages/edit-site/src/components/page-patterns/grid-item.js +++ b/packages/edit-site/src/components/page-patterns/grid-item.js @@ -292,7 +292,7 @@ function GridItem( { categoryId, item, ...props } ) { onClose={ onClose } label={ __( 'Duplicate' ) } /> - { item.type === USER_PATTERNS && ( + { item.type === PATTERN_TYPES.user && ( exportAsJSON() }> { __( 'Export as JSON' ) } From ea055a1242d129cf7cf20a30357876352117ff17 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Wed, 20 Sep 2023 14:10:46 +0800 Subject: [PATCH 06/10] Apply suggestions from code review Co-authored-by: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> --- packages/edit-site/src/components/page-patterns/grid-item.js | 4 ++-- packages/patterns/src/store/actions.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/edit-site/src/components/page-patterns/grid-item.js b/packages/edit-site/src/components/page-patterns/grid-item.js index 701d7ff603d69..f1da1f925229d 100644 --- a/packages/edit-site/src/components/page-patterns/grid-item.js +++ b/packages/edit-site/src/components/page-patterns/grid-item.js @@ -114,8 +114,8 @@ function GridItem( { categoryId, item, ...props } ) { const json = { __file: item.type, title: item.title, - content: item.reusableBlock.content.raw, - syncStatus: item.reusableBlock.wp_pattern_sync_status, + content: item.patternBlock.content.raw, + syncStatus: item.patternBlock.wp_pattern_sync_status, }; return downloadjs( diff --git a/packages/patterns/src/store/actions.js b/packages/patterns/src/store/actions.js index 1231f73f60146..f47ee45cd1b56 100644 --- a/packages/patterns/src/store/actions.js +++ b/packages/patterns/src/store/actions.js @@ -71,7 +71,7 @@ export const createPatternFromFile = throw new Error( 'Invalid Pattern JSON file' ); } - const pattern = await dispatch.__experimentalCreatePattern( + const pattern = await dispatch.createPattern( parsedContent.title, parsedContent.syncStatus, parsedContent.content From 1a230d15b23c856766b23721a6b1392b7485bf25 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Wed, 20 Sep 2023 14:15:02 +0800 Subject: [PATCH 07/10] Move import to last --- .../src/components/add-new-pattern/index.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/edit-site/src/components/add-new-pattern/index.js b/packages/edit-site/src/components/add-new-pattern/index.js index 16907006809f6..0953c80f0d58f 100644 --- a/packages/edit-site/src/components/add-new-pattern/index.js +++ b/packages/edit-site/src/components/add-new-pattern/index.js @@ -72,13 +72,6 @@ export default function AddNewPattern() { onClick: () => setShowPatternModal( true ), title: __( 'Create pattern' ), }, - { - icon: symbol, - onClick: () => { - patternUploadInputRef.current.click(); - }, - title: __( 'Import pattern from JSON' ), - }, ]; // Remove condition when command palette issues are resolved. @@ -91,6 +84,14 @@ export default function AddNewPattern() { } ); } + controls.push( { + icon: symbol, + onClick: () => { + patternUploadInputRef.current.click(); + }, + title: __( 'Import pattern from JSON' ), + } ); + return ( <> Date: Wed, 20 Sep 2023 14:36:29 +0800 Subject: [PATCH 08/10] Fix importing the same file --- packages/edit-site/src/components/add-new-pattern/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/edit-site/src/components/add-new-pattern/index.js b/packages/edit-site/src/components/add-new-pattern/index.js index 0953c80f0d58f..9592acc85d376 100644 --- a/packages/edit-site/src/components/add-new-pattern/index.js +++ b/packages/edit-site/src/components/add-new-pattern/index.js @@ -145,6 +145,8 @@ export default function AddNewPattern() { type: 'snackbar', id: 'import-pattern-error', } ); + } finally { + event.target.value = ''; } } } /> From 0dbb84b7140d19a8f6a6804eda0747e45cccacaa Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Wed, 20 Sep 2023 14:46:14 +0800 Subject: [PATCH 09/10] Fix navigating to all-patterns category --- .../src/components/add-new-pattern/index.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/add-new-pattern/index.js b/packages/edit-site/src/components/add-new-pattern/index.js index 9592acc85d376..4972c7447514b 100644 --- a/packages/edit-site/src/components/add-new-pattern/index.js +++ b/packages/edit-site/src/components/add-new-pattern/index.js @@ -20,12 +20,14 @@ import CreateTemplatePartModal from '../create-template-part-modal'; import SidebarButton from '../sidebar-button'; import { unlock } from '../../lock-unlock'; import { store as editSiteStore } from '../../store'; +import { PATTERN_TYPES, PATTERN_DEFAULT_CATEGORY } from '../../utils/constants'; -const { useHistory } = unlock( routerPrivateApis ); +const { useHistory, useLocation } = unlock( routerPrivateApis ); const { CreatePatternModal } = unlock( editPatternsPrivateApis ); export default function AddNewPattern() { const history = useHistory(); + const { params } = useLocation(); const [ showPatternModal, setShowPatternModal ] = useState( false ); const [ showTemplatePartModal, setShowTemplatePartModal ] = useState( false ); @@ -129,6 +131,18 @@ export default function AddNewPattern() { try { const pattern = await createPatternFromFile( file ); + // Navigate to the All patterns category for the newly created pattern. + if ( + params.categoryType !== PATTERN_TYPES.theme || + params.categoryId !== PATTERN_DEFAULT_CATEGORY + ) { + history.push( { + path: `/patterns`, + categoryType: PATTERN_TYPES.theme, + categoryId: PATTERN_DEFAULT_CATEGORY, + } ); + } + createSuccessNotice( sprintf( // translators: %s: The imported pattern's title. From 9a625d8476d5b3396b339a516cb2881294862bf5 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Wed, 20 Sep 2023 15:33:38 +0800 Subject: [PATCH 10/10] Auto assign category if users are on that category already --- .../src/components/add-new-pattern/index.js | 29 ++++++++++++++----- packages/patterns/src/store/actions.js | 8 +++-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/edit-site/src/components/add-new-pattern/index.js b/packages/edit-site/src/components/add-new-pattern/index.js index 4972c7447514b..e4b22031b1582 100644 --- a/packages/edit-site/src/components/add-new-pattern/index.js +++ b/packages/edit-site/src/components/add-new-pattern/index.js @@ -20,7 +20,12 @@ import CreateTemplatePartModal from '../create-template-part-modal'; import SidebarButton from '../sidebar-button'; import { unlock } from '../../lock-unlock'; import { store as editSiteStore } from '../../store'; -import { PATTERN_TYPES, PATTERN_DEFAULT_CATEGORY } from '../../utils/constants'; +import { + PATTERN_TYPES, + PATTERN_DEFAULT_CATEGORY, + TEMPLATE_PART_POST_TYPE, +} from '../../utils/constants'; +import usePatternCategories from '../sidebar-navigation-screen-patterns/use-pattern-categories'; const { useHistory, useLocation } = unlock( routerPrivateApis ); const { CreatePatternModal } = unlock( editPatternsPrivateApis ); @@ -39,6 +44,7 @@ export default function AddNewPattern() { const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore ); const patternUploadInputRef = useRef(); + const { patternCategories } = usePatternCategories(); function handleCreatePattern( { pattern, categoryId } ) { setShowPatternModal( false ); @@ -129,13 +135,22 @@ export default function AddNewPattern() { const file = event.target.files?.[ 0 ]; if ( ! file ) return; try { - const pattern = await createPatternFromFile( file ); + const currentCategoryId = + params.categoryType !== TEMPLATE_PART_POST_TYPE && + patternCategories.find( + ( category ) => + category.name === params.categoryId + )?.id; + const pattern = await createPatternFromFile( + file, + currentCategoryId + ? [ currentCategoryId ] + : undefined + ); - // Navigate to the All patterns category for the newly created pattern. - if ( - params.categoryType !== PATTERN_TYPES.theme || - params.categoryId !== PATTERN_DEFAULT_CATEGORY - ) { + // Navigate to the All patterns category for the newly created pattern + // if we're not on that page already. + if ( ! currentCategoryId ) { history.push( { path: `/patterns`, categoryType: PATTERN_TYPES.theme, diff --git a/packages/patterns/src/store/actions.js b/packages/patterns/src/store/actions.js index f47ee45cd1b56..2861e4ce2dac0 100644 --- a/packages/patterns/src/store/actions.js +++ b/packages/patterns/src/store/actions.js @@ -46,10 +46,11 @@ export const createPattern = /** * Create a pattern from a JSON file. - * @param {File} file The JSON file instance of the pattern. + * @param {File} file The JSON file instance of the pattern. + * @param {number[]|undefined} [categories] Ids of any selected categories. */ export const createPatternFromFile = - ( file ) => + ( file, categories ) => async ( { dispatch } ) => { const fileContent = await file.text(); /** @type {import('./types').PatternJSON} */ @@ -74,7 +75,8 @@ export const createPatternFromFile = const pattern = await dispatch.createPattern( parsedContent.title, parsedContent.syncStatus, - parsedContent.content + parsedContent.content, + categories ); return pattern;