Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Update: Move pattern actions to the editor package." #61611

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 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
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"@wordpress/widgets": "file:../widgets",
"@wordpress/wordcount": "file:../wordcount",
"change-case": "^4.1.2",
"client-zip": "^2.4.4",
"clsx": "^2.1.1",
"colord": "^2.9.2",
"fast-deep-equal": "^3.1.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
/**
* External dependencies
*/
import { paramCase as kebabCase } from 'change-case';
import { downloadZip } from 'client-zip';

/**
* WordPress dependencies
*/
import { downloadBlob } from '@wordpress/blob';
import { __, _x, sprintf } from '@wordpress/i18n';

import {
Button,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
__experimentalText as Text,
} from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
import { store as noticesStore } from '@wordpress/notices';
import { decodeEntities } from '@wordpress/html-entities';
import { store as reusableBlocksStore } from '@wordpress/reusable-blocks';
import { store as editorStore } from '@wordpress/editor';
import { privateApis as routerPrivateApis } from '@wordpress/router';
import { privateApis as patternsPrivateApis } from '@wordpress/patterns';

/**
* Internal dependencies
*/
import { unlock } from '../../lock-unlock';
import { store as editSiteStore } from '../../store';
import {
PATTERN_TYPES,
TEMPLATE_PART_POST_TYPE,
Expand All @@ -23,6 +39,235 @@ const { useHistory, useLocation } = unlock( routerPrivateApis );
const { CreatePatternModalContents, useDuplicatePatternProps } =
unlock( patternsPrivateApis );

function getJsonFromItem( item ) {
return JSON.stringify(
{
__file: item.type,
title: item.title || item.name,
content: item.patternPost.content.raw,
syncStatus: item.patternPost.wp_pattern_sync_status,
},
null,
2
);
}

export const exportJSONaction = {
id: 'export-pattern',
label: __( 'Export as JSON' ),
supportsBulk: true,
isEligible: ( item ) => item.type === PATTERN_TYPES.user,
callback: async ( items ) => {
if ( items.length === 1 ) {
return downloadBlob(
`${ kebabCase( items[ 0 ].title || items[ 0 ].name ) }.json`,
getJsonFromItem( items[ 0 ] ),
'application/json'
);
}
const nameCount = {};
const filesToZip = items.map( ( item ) => {
const name = kebabCase( item.title || item.name );
nameCount[ name ] = ( nameCount[ name ] || 0 ) + 1;
return {
name: `${
name +
( nameCount[ name ] > 1
? '-' + ( nameCount[ name ] - 1 )
: '' )
}.json`,
lastModified: new Date(),
input: getJsonFromItem( item ),
};
} );
return downloadBlob(
__( 'patterns-export' ) + '.zip',
await downloadZip( filesToZip ).blob(),
'application/zip'
);
},
};

const canDeleteOrReset = ( item ) => {
const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE;
const isUserPattern = item.type === PATTERN_TYPES.user;
return isUserPattern || ( isTemplatePart && item.isCustom );
};

export const deleteAction = {
id: 'delete-pattern',
label: __( 'Delete' ),
isEligible: ( item ) => {
const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE;
const hasThemeFile = isTemplatePart && item.templatePart.has_theme_file;
return canDeleteOrReset( item ) && ! hasThemeFile;
},
hideModalHeader: true,
supportsBulk: true,
RenderModal: ( { items, closeModal, onPerform } ) => {
const { __experimentalDeleteReusableBlock } =
useDispatch( reusableBlocksStore );
const { createErrorNotice, createSuccessNotice } =
useDispatch( noticesStore );
const { removeTemplates } = unlock( useDispatch( editorStore ) );

const deletePattern = async () => {
const promiseResult = await Promise.allSettled(
items.map( ( item ) => {
return __experimentalDeleteReusableBlock( item.id );
} )
);
// If all the promises were fulfilled with success.
if (
promiseResult.every( ( { status } ) => status === 'fulfilled' )
) {
let successMessage;
if ( promiseResult.length === 1 ) {
successMessage = sprintf(
/* translators: The posts's title. */
__( '"%s" deleted.' ),
items[ 0 ].title
);
} else {
successMessage = __( 'The patterns were deleted.' );
}
createSuccessNotice( successMessage, {
type: 'snackbar',
id: 'edit-site-page-trashed',
} );
} else {
// If there was at lease one failure.
let errorMessage;
// If we were trying to delete a single pattern.
if ( promiseResult.length === 1 ) {
if ( promiseResult[ 0 ].reason?.message ) {
errorMessage = promiseResult[ 0 ].reason.message;
} else {
errorMessage = __(
'An error occurred while deleting the pattern.'
);
}
// If we were trying to delete multiple patterns.
} else {
const errorMessages = new Set();
const failedPromises = promiseResult.filter(
( { status } ) => status === 'rejected'
);
for ( const failedPromise of failedPromises ) {
if ( failedPromise.reason?.message ) {
errorMessages.add( failedPromise.reason.message );
}
}
if ( errorMessages.size === 0 ) {
errorMessage = __(
'An error occurred while deleting the patterns.'
);
} else if ( errorMessages.size === 1 ) {
errorMessage = sprintf(
/* translators: %s: an error message */
__(
'An error occurred while deleting the patterns: %s'
),
[ ...errorMessages ][ 0 ]
);
} else {
errorMessage = sprintf(
/* translators: %s: a list of comma separated error messages */
__(
'Some errors occurred while deleting the patterns: %s'
),
[ ...errorMessages ].join( ',' )
);
}
createErrorNotice( errorMessage, {
type: 'snackbar',
} );
}
}
};
const deleteItem = () => {
if ( items[ 0 ].type === TEMPLATE_PART_POST_TYPE ) {
removeTemplates( items );
} else {
deletePattern();
}
if ( onPerform ) {
onPerform();
}
closeModal();
};
let questionMessage;
if ( items.length === 1 ) {
questionMessage = sprintf(
// translators: %s: The page's title.
__( 'Are you sure you want to delete "%s"?' ),
decodeEntities( items[ 0 ].title || items[ 0 ].name )
);
} else if (
items.length > 1 &&
items[ 0 ].type === TEMPLATE_PART_POST_TYPE
) {
questionMessage = sprintf(
// translators: %d: The number of template parts (2 or more).
__( 'Are you sure you want to delete %d template parts?' ),
items.length
);
} else {
questionMessage = sprintf(
// translators: %d: The number of patterns (2 or more).
__( 'Are you sure you want to delete %d patterns?' ),
items.length
);
}
return (
<VStack spacing="5">
<Text>{ questionMessage }</Text>
<HStack justify="right">
<Button variant="tertiary" onClick={ closeModal }>
{ __( 'Cancel' ) }
</Button>
<Button variant="primary" onClick={ deleteItem }>
{ __( 'Delete' ) }
</Button>
</HStack>
</VStack>
);
},
};

export const resetAction = {
id: 'reset-action',
label: __( 'Reset' ),
isEligible: ( item ) => {
const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE;
const hasThemeFile = isTemplatePart && item.templatePart.has_theme_file;
return canDeleteOrReset( item ) && hasThemeFile;
},
hideModalHeader: true,
RenderModal: ( { items, closeModal } ) => {
const [ item ] = items;
const { removeTemplate } = useDispatch( editSiteStore );
return (
<VStack spacing="5">
<Text>
{ __( 'Reset to default and clear all customizations?' ) }
</Text>
<HStack justify="right">
<Button variant="tertiary" onClick={ closeModal }>
{ __( 'Cancel' ) }
</Button>
<Button
variant="primary"
onClick={ () => removeTemplate( item ) }
>
{ __( 'Reset' ) }
</Button>
</HStack>
</VStack>
);
},
};

export const duplicatePatternAction = {
id: 'duplicate-pattern',
label: _x( 'Duplicate', 'action label' ),
Expand Down
18 changes: 14 additions & 4 deletions packages/edit-site/src/components/page-patterns/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ import {
OPERATOR_IS,
} from '../../utils/constants';
import {
exportJSONaction,
resetAction,
deleteAction,
duplicatePatternAction,
duplicateTemplatePartAction,
} from './dataviews-pattern-actions';
Expand Down Expand Up @@ -380,13 +383,20 @@ export default function DataviewsPatterns() {
if ( type === TEMPLATE_PART_POST_TYPE ) {
return [
editAction,
duplicateTemplatePartAction,
...templatePartActions,
duplicateTemplatePartAction,
resetAction,
deleteAction,
].filter( Boolean );
}
return [ editAction, duplicatePatternAction, ...patternActions ].filter(
Boolean
);
return [
editAction,
...patternActions,
duplicatePatternAction,
exportJSONaction,
resetAction,
deleteAction,
].filter( Boolean );
}, [ editAction, type, templatePartActions, patternActions ] );
const onChangeView = useCallback(
( newView ) => {
Expand Down
2 changes: 0 additions & 2 deletions packages/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@
"@wordpress/url": "file:../url",
"@wordpress/warning": "file:../warning",
"@wordpress/wordcount": "file:../wordcount",
"change-case": "^4.1.2",
"client-zip": "^2.4.4",
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"deepmerge": "^4.3.0",
Expand Down
Loading
Loading