Skip to content

Commit

Permalink
Patterns: Add renaming, duplication, and deletion options (#52270)
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronrobertshaw authored and tellthemachines committed Jul 10, 2023
1 parent 8b10e6a commit 3e5bc99
Show file tree
Hide file tree
Showing 6 changed files with 421 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@ import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { store as noticesStore } from '@wordpress/notices';
import { useDispatch } from '@wordpress/data';
import { serialize } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { SYNC_TYPES, USER_PATTERN_CATEGORY } from '../page-patterns/utils';

export default function CreatePatternModal( {
blocks = [],
closeModal,
onCreate,
onError,
title,
} ) {
const [ name, setName ] = useState( '' );
const [ syncType, setSyncType ] = useState( SYNC_TYPES.unsynced );
Expand Down Expand Up @@ -52,7 +55,7 @@ export default function CreatePatternModal( {
'wp_block',
{
title: name || __( 'Untitled Pattern' ),
content: '',
content: blocks?.length ? serialize( blocks ) : '',
status: 'publish',
meta:
syncType === SYNC_TYPES.unsynced
Expand All @@ -76,7 +79,7 @@ export default function CreatePatternModal( {

return (
<Modal
title={ __( 'Create pattern' ) }
title={ title || __( 'Create pattern' ) }
onRequestClose={ closeModal }
overlayClassName="edit-site-create-pattern-modal"
>
Expand Down
196 changes: 196 additions & 0 deletions packages/edit-site/src/components/page-patterns/duplicate-menu-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/**
* WordPress dependencies
*/
import { MenuItem } from '@wordpress/components';
import { store as coreStore } from '@wordpress/core-data';
import { useDispatch } from '@wordpress/data';
import { __, sprintf } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { privateApis as routerPrivateApis } from '@wordpress/router';

/**
* Internal dependencies
*/
import {
TEMPLATE_PARTS,
PATTERNS,
SYNC_TYPES,
USER_PATTERNS,
USER_PATTERN_CATEGORY,
} from './utils';
import {
useExistingTemplateParts,
getUniqueTemplatePartTitle,
getCleanTemplatePartSlug,
} from '../../utils/template-part-create';
import { unlock } from '../../lock-unlock';

const { useHistory } = unlock( routerPrivateApis );

function getPatternMeta( item ) {
if ( item.type === PATTERNS ) {
return { wp_pattern_sync_status: SYNC_TYPES.unsynced };
}

const syncStatus = item.reusableBlock.wp_pattern_sync_status;
const isUnsynced = syncStatus === SYNC_TYPES.unsynced;

return {
...item.reusableBlock.meta,
wp_pattern_sync_status: isUnsynced ? syncStatus : undefined,
};
}

export default function DuplicateMenuItem( {
categoryId,
item,
label = __( 'Duplicate' ),
onClose,
} ) {
const { saveEntityRecord } = useDispatch( coreStore );
const { createErrorNotice, createSuccessNotice } =
useDispatch( noticesStore );

const history = useHistory();
const existingTemplateParts = useExistingTemplateParts();

async function createTemplatePart() {
try {
const copiedTitle = sprintf(
/* translators: %s: Existing template part title */
__( '%s (Copy)' ),
item.title
);
const title = getUniqueTemplatePartTitle(
copiedTitle,
existingTemplateParts
);
const slug = getCleanTemplatePartSlug( title );
const { area, content } = item.templatePart;

const result = await saveEntityRecord(
'postType',
'wp_template_part',
{ slug, title, content, area },
{ throwOnError: true }
);

createSuccessNotice(
sprintf(
// translators: %s: The new template part's title e.g. 'Call to action (copy)'.
__( '"%s" created.' ),
title
),
{
type: 'snackbar',
id: 'edit-site-patterns-success',
actions: [
{
label: __( 'Edit' ),
onClick: () =>
history.push( {
postType: TEMPLATE_PARTS,
postId: result?.id,
categoryType: TEMPLATE_PARTS,
categoryId,
} ),
},
],
}
);

onClose();
} catch ( error ) {
const errorMessage =
error.message && error.code !== 'unknown_error'
? error.message
: __(
'An error occurred while creating the template part.'
);

createErrorNotice( errorMessage, {
type: 'snackbar',
id: 'edit-site-patterns-error',
} );
onClose();
}
}

async function createPattern() {
try {
const isThemePattern = item.type === PATTERNS;
const title = sprintf(
/* translators: %s: Existing pattern title */
__( '%s (Copy)' ),
item.title
);

const result = await saveEntityRecord(
'postType',
'wp_block',
{
content: isThemePattern
? item.content
: item.reusableBlock.content,
meta: getPatternMeta( item ),
status: 'publish',
title,
},
{ throwOnError: true }
);

const actionLabel = isThemePattern
? __( 'View my patterns' )
: __( 'Edit' );

const newLocation = isThemePattern
? {
categoryType: USER_PATTERNS,
categoryId: USER_PATTERN_CATEGORY,
path: '/patterns',
}
: {
categoryType: USER_PATTERNS,
categoryId: USER_PATTERN_CATEGORY,
postType: USER_PATTERNS,
postId: result?.id,
};

createSuccessNotice(
sprintf(
// translators: %s: The new pattern's title e.g. 'Call to action (copy)'.
__( '"%s" added to my patterns.' ),
title
),
{
type: 'snackbar',
id: 'edit-site-patterns-success',
actions: [
{
label: actionLabel,
onClick: () => history.push( newLocation ),
},
],
}
);

onClose();
} catch ( error ) {
const errorMessage =
error.message && error.code !== 'unknown_error'
? error.message
: __( 'An error occurred while creating the pattern.' );

createErrorNotice( errorMessage, {
type: 'snackbar',
id: 'edit-site-patterns-error',
} );
onClose();
}
}

const createItem =
item.type === TEMPLATE_PARTS ? createTemplatePart : createPattern;

return <MenuItem onClick={ createItem }>{ label }</MenuItem>;
}
Loading

0 comments on commit 3e5bc99

Please sign in to comment.