diff --git a/package-lock.json b/package-lock.json index 68ee222ddb1be3..23e229d1fcf868 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53796,6 +53796,7 @@ "@wordpress/a11y": "file:../a11y", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", + "@wordpress/data": "file:../data", "@wordpress/element": "file:../element", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", @@ -68987,6 +68988,7 @@ "@wordpress/a11y": "file:../a11y", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", + "@wordpress/data": "file:../data", "@wordpress/element": "file:../element", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", diff --git a/packages/dataviews/package.json b/packages/dataviews/package.json index 394c41e35cea3c..b8d4e04c0c4e07 100644 --- a/packages/dataviews/package.json +++ b/packages/dataviews/package.json @@ -32,6 +32,7 @@ "@wordpress/a11y": "file:../a11y", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", + "@wordpress/data": "file:../data", "@wordpress/element": "file:../element", "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", diff --git a/packages/dataviews/src/bulk-actions.js b/packages/dataviews/src/bulk-actions.js index 5e4139fe0622e7..8509081673369a 100644 --- a/packages/dataviews/src/bulk-actions.js +++ b/packages/dataviews/src/bulk-actions.js @@ -8,6 +8,7 @@ import { } from '@wordpress/components'; import { __, sprintf, _n } from '@wordpress/i18n'; import { useMemo, useState, useCallback, useEffect } from '@wordpress/element'; +import { useRegistry } from '@wordpress/data'; /** * Internal dependencies @@ -52,6 +53,15 @@ function ActionWithModal( { const onCloseModal = useCallback( () => { setActionWithModal( undefined ); }, [ setActionWithModal ] ); + const actionWithCallbacks = useMemo( () => { + return { + ...action, + onActionPerformed: ( ...args ) => { + onMenuOpenChange( false ); + action.onActionPerformed?.( ...args ); + }, + }; + }, [ action, onMenuOpenChange ] ); return ( onMenuOpenChange( false ) } + action={ actionWithCallbacks } /> ); } function BulkActionItem( { action, selectedItems, setActionWithModal } ) { + const registry = useRegistry(); const eligibleItems = useMemo( () => { return selectedItems.filter( ( item ) => action.isEligible( item ) ); }, [ action, selectedItems ] ); @@ -84,7 +95,14 @@ function BulkActionItem( { action, selectedItems, setActionWithModal } ) { if ( shouldShowModal ) { setActionWithModal( action ); } else { - await action.callback( eligibleItems ); + const returnResult = await action.callback( eligibleItems ); + if ( typeof returnResult === 'function' ) { + await returnResult( { + registry, + select: registry.select, + dispatch: registry.dispatch, + } ); + } } } } suffix={ diff --git a/packages/dataviews/src/item-actions.js b/packages/dataviews/src/item-actions.js index db4da0d4924896..42fcfe756e89e3 100644 --- a/packages/dataviews/src/item-actions.js +++ b/packages/dataviews/src/item-actions.js @@ -10,6 +10,7 @@ import { import { __ } from '@wordpress/i18n'; import { useMemo, useState } from '@wordpress/element'; import { moreVertical } from '@wordpress/icons'; +import { useRegistry } from '@wordpress/data'; /** * Internal dependencies @@ -71,6 +72,7 @@ function ActionWithModal( { action, item, ActionTrigger } ) { setIsModalOpen( false ) } + action={ action } /> ) } @@ -79,6 +81,7 @@ function ActionWithModal( { action, item, ActionTrigger } ) { } function ActionsDropdownMenuGroup( { actions, item } ) { + const registry = useRegistry(); return ( { actions.map( ( action ) => { @@ -96,7 +99,18 @@ function ActionsDropdownMenuGroup( { actions, item } ) { action.callback( [ item ] ) } + onClick={ async () => { + const returnResult = await action.callback( [ + item, + ] ); + if ( typeof returnResult === 'function' ) { + await returnResult( { + registry, + select: registry.select, + dispatch: registry.dispatch, + } ); + } + } } /> ); } ) } @@ -105,6 +119,7 @@ function ActionsDropdownMenuGroup( { actions, item } ) { } export default function ItemActions( { item, actions, isCompact } ) { + const registry = useRegistry(); const { primaryActions, eligibleActions } = useMemo( () => { // If an action is eligible for all items, doesn't need // to provide the `isEligible` function. @@ -148,7 +163,18 @@ export default function ItemActions( { item, actions, isCompact } ) { action.callback( [ item ] ) } + onClick={ async () => { + const returnResult = await action.callback( [ + item, + ] ); + if ( typeof returnResult === 'function' ) { + await returnResult( { + registry, + select: registry.select, + dispatch: registry.dispatch, + } ); + } + } } /> ); } ) } diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index e98896ab2e8cc9..307761e91b2c29 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -34,7 +34,7 @@ import AddNewPageModal from '../add-new-page'; import Media from '../media'; import { unlock } from '../../lock-unlock'; -const { usePostActions } = unlock( editorPrivateApis ); +const { postActions } = unlock( editorPrivateApis ); const { useLocation, useHistory } = unlock( routerPrivateApis ); @@ -189,15 +189,15 @@ function FeaturedImage( { item, viewType } ) { ); } -const PAGE_ACTIONS = [ - 'edit-post', - 'view-post', - 'restore', - 'permanently-delete', - 'view-post-revisions', - 'rename-post', - 'move-to-trash', -]; +const { + editPostAction, + viewPostAction, + restorePostAction, + permanentlyDeletePostAction, + postRevisionsAction, + renamePostAction, + trashPostAction, +} = postActions; export default function PagePages() { const postType = 'page'; @@ -350,20 +350,33 @@ export default function PagePages() { ], [ authors, view.type ] ); - const onActionPerformed = useCallback( - ( actionId, items ) => { - if ( actionId === 'edit-post' ) { - const post = items[ 0 ]; - history.push( { - postId: post.id, - postType: post.type, - canvas: 'edit', - } ); - } - }, - [ history ] - ); - const actions = usePostActions( onActionPerformed, PAGE_ACTIONS ); + + const actions = useMemo( () => { + const onEditPostActionPerformed = ( items ) => { + const post = items[ 0 ]; + history.push( { + postId: post.id, + postType: post.type, + canvas: 'edit', + } ); + }; + return [ + { + ...editPostAction, + onActionPerformed: ( ...args ) => { + onEditPostActionPerformed( ...args ); + editPostAction.onActionPerformed?.( ...args ); + }, + }, + viewPostAction, + restorePostAction, + permanentlyDeletePostAction, + postRevisionsAction, + renamePostAction, + trashPostAction, + ]; + }, [ history ] ); + const onChangeView = useCallback( ( newView ) => { if ( newView.type !== view.type ) { diff --git a/packages/edit-site/src/components/page-patterns/index.js b/packages/edit-site/src/components/page-patterns/index.js index 102f1b3cd075e9..580749a28ed69b 100644 --- a/packages/edit-site/src/components/page-patterns/index.js +++ b/packages/edit-site/src/components/page-patterns/index.js @@ -67,7 +67,7 @@ import { useAddedBy } from '../page-templates/hooks'; const { ExperimentalBlockEditorProvider, useGlobalStyle } = unlock( blockEditorPrivateApis ); -const { usePostActions } = unlock( editorPrivateApis ); +const { postActions } = unlock( editorPrivateApis ); const { useHistory } = unlock( routerPrivateApis ); const EMPTY_ARRAY = []; @@ -252,6 +252,8 @@ function Title( { item, categoryId } ) { ); } +const { editPostAction, postRevisionsAction } = postActions; + export default function DataviewsPatterns() { const { categoryType, @@ -394,9 +396,9 @@ export default function DataviewsPatterns() { }, [ patterns, view, fields, type ] ); const history = useHistory(); - const onActionPerformed = useCallback( - ( actionId, items ) => { - if ( actionId === 'edit-post' ) { + const actions = useMemo( () => { + if ( type === TEMPLATE_PART_POST_TYPE ) { + const onEditPostActionPerformed = ( items ) => { const post = items[ 0 ]; history.push( { postId: post.id, @@ -405,21 +407,18 @@ export default function DataviewsPatterns() { categoryType: type, canvas: 'edit', } ); - } - }, - [ history, categoryId, type ] - ); - const [ editAction, viewRevisionsAction ] = usePostActions( - onActionPerformed, - [ 'edit-post', 'view-post-revisions' ] - ); - const actions = useMemo( () => { - if ( type === TEMPLATE_PART_POST_TYPE ) { + }; return [ - editAction, + { + ...editPostAction, + onActionPerformed: ( ...args ) => { + onEditPostActionPerformed( ...args ); + editPostAction.onActionPerformed?.( ...args ); + }, + }, renameAction, duplicateTemplatePartAction, - viewRevisionsAction, + postRevisionsAction, resetAction, deleteAction, ]; @@ -431,7 +430,7 @@ export default function DataviewsPatterns() { resetAction, deleteAction, ]; - }, [ type, editAction, viewRevisionsAction ] ); + }, [ type, history, categoryId ] ); const onChangeView = useCallback( ( newView ) => { if ( newView.type !== view.type ) { diff --git a/packages/edit-site/src/components/page-templates/index.js b/packages/edit-site/src/components/page-templates/index.js index a64cb63cfbc8c4..66fdb897ffdb03 100644 --- a/packages/edit-site/src/components/page-templates/index.js +++ b/packages/edit-site/src/components/page-templates/index.js @@ -45,7 +45,7 @@ import { import usePatternSettings from '../page-patterns/use-pattern-settings'; import { unlock } from '../../lock-unlock'; -const { usePostActions } = unlock( editorPrivateApis ); +const { postActions } = unlock( editorPrivateApis ); const { ExperimentalBlockEditorProvider, useGlobalStyle } = unlock( blockEditorPrivateApis @@ -187,13 +187,13 @@ function Preview( { item, viewType } ) { ); } -const TEMPLATE_ACTIONS = [ - 'edit-post', - 'reset-template', - 'rename-template', - 'view-post-revisions', - 'delete-template', -]; +const { + editPostAction, + resetTemplateAction, + renameTemplateAction, + postRevisionsAction, + deleteTemplateAction, +} = postActions; export default function PageTemplates() { const { params } = useLocation(); @@ -335,21 +335,29 @@ export default function PageTemplates() { return filterSortAndPaginate( records, view, fields ); }, [ records, view, fields ] ); - const onActionPerformed = useCallback( - ( actionId, items ) => { - if ( actionId === 'edit-post' ) { - const post = items[ 0 ]; - history.push( { - postId: post.id, - postType: post.type, - canvas: 'edit', - } ); - } - }, - [ history ] - ); - - const actions = usePostActions( onActionPerformed, TEMPLATE_ACTIONS ); + const actions = useMemo( () => { + const onEditPostActionPerformed = ( items ) => { + const post = items[ 0 ]; + history.push( { + postId: post.id, + postType: post.type, + canvas: 'edit', + } ); + }; + return [ + { + ...editPostAction, + onActionPerformed: ( ...args ) => { + onEditPostActionPerformed( ...args ); + editPostAction.onActionPerformed?.( ...args ); + }, + }, + resetTemplateAction, + renameTemplateAction, + postRevisionsAction, + deleteTemplateAction, + ]; + }, [ history ] ); const onChangeView = useCallback( ( newView ) => { diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 7b91c2c5c96e3e..da91f010712c97 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -8,7 +8,7 @@ import { decodeEntities } from '@wordpress/html-entities'; import { store as coreStore } from '@wordpress/core-data'; import { __, _n, sprintf } from '@wordpress/i18n'; import { store as noticesStore } from '@wordpress/notices'; -import { useMemo, useState } from '@wordpress/element'; +import { useState } from '@wordpress/element'; import { Button, @@ -33,7 +33,7 @@ function getItemTitle( item ) { return decodeEntities( item.title?.rendered || '' ); } -const trashPostAction = { +export const trashPostAction = { id: 'move-to-trash', label: __( 'Move to Trash' ), isPrimary: true, @@ -43,7 +43,7 @@ const trashPostAction = { }, supportsBulk: true, hideModalHeader: true, - RenderModal: ( { items: posts, closeModal, onActionPerformed } ) => { + RenderModal( { items: posts, closeModal, action } ) { const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore ); const { deleteEntityRecord } = useDispatch( coreStore ); @@ -158,9 +158,7 @@ const trashPostAction = { type: 'snackbar', } ); } - if ( onActionPerformed ) { - onActionPerformed( posts ); - } + action.onActionPerformed?.( posts ); closeModal(); } } > @@ -172,200 +170,176 @@ const trashPostAction = { }, }; -function usePermanentlyDeletePostAction() { - const { createSuccessNotice, createErrorNotice } = - useDispatch( noticesStore ); - const { deleteEntityRecord } = useDispatch( coreStore ); - - return useMemo( - () => ( { - id: 'permanently-delete', - label: __( 'Permanently delete' ), - supportsBulk: true, - isEligible( { status } ) { - return status === 'trash'; - }, - async callback( posts, onActionPerformed ) { - const promiseResult = await Promise.allSettled( - posts.map( ( post ) => { - return deleteEntityRecord( - 'postType', - post.type, - post.id, - { force: true }, - { throwOnError: true } - ); - } ) - ); - // 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" permanently deleted.' ), - getItemTitle( posts[ 0 ] ) - ); +export const permanentlyDeletePostAction = { + id: 'permanently-delete', + label: __( 'Permanently delete' ), + supportsBulk: true, + isEligible( { status } ) { + return status === 'trash'; + }, + callback( posts ) { + return async ( { dispatch } ) => { + const { createSuccessNotice, createErrorNotice } = + dispatch( noticesStore ); + const { deleteEntityRecord } = dispatch( coreStore ); + const promiseResult = await Promise.allSettled( + posts.map( ( post ) => { + return deleteEntityRecord( + 'postType', + post.type, + post.id, + { force: true }, + { throwOnError: true } + ); + } ) + ); + // 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" permanently deleted.' ), + getItemTitle( posts[ 0 ] ) + ); + } else { + successMessage = __( + 'The posts were permanently deleted.' + ); + } + createSuccessNotice( successMessage, { + type: 'snackbar', + id: 'permanently-delete-post-action', + } ); + this?.onActionPerformed?.( posts ); + } else { + // If there was at lease one failure. + let errorMessage; + // If we were trying to permanently delete a single post. + if ( promiseResult.length === 1 ) { + if ( promiseResult[ 0 ].reason?.message ) { + errorMessage = promiseResult[ 0 ].reason.message; } else { - successMessage = __( - 'The posts were permanently deleted.' + errorMessage = __( + 'An error occurred while permanently deleting the post.' ); } - createSuccessNotice( successMessage, { - type: 'snackbar', - id: 'permanently-delete-post-action', - } ); - if ( onActionPerformed ) { - onActionPerformed( posts ); - } + // If we were trying to permanently delete multiple posts } else { - // If there was at lease one failure. - let errorMessage; - // If we were trying to permanently delete a single post. - if ( promiseResult.length === 1 ) { - if ( promiseResult[ 0 ].reason?.message ) { - errorMessage = promiseResult[ 0 ].reason.message; - } else { - errorMessage = __( - 'An error occurred while permanently deleting the post.' - ); - } - // If we were trying to permanently delete multiple posts - } 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 permanently deleting the posts.' - ); - } else if ( errorMessages.size === 1 ) { - errorMessage = sprintf( - /* translators: %s: an error message */ - __( - 'An error occurred while permanently deleting the posts: %s' - ), - [ ...errorMessages ][ 0 ] - ); - } else { - errorMessage = sprintf( - /* translators: %s: a list of comma separated error messages */ - __( - 'Some errors occurred while permanently deleting the posts: %s' - ), - [ ...errorMessages ].join( ',' ) - ); + 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 ); } } - createErrorNotice( errorMessage, { - type: 'snackbar', - } ); - } - }, - } ), - [ createSuccessNotice, createErrorNotice, deleteEntityRecord ] - ); -} - -function useRestorePostAction() { - const { createSuccessNotice, createErrorNotice } = - useDispatch( noticesStore ); - const { editEntityRecord, saveEditedEntityRecord } = - useDispatch( coreStore ); - - return useMemo( - () => ( { - id: 'restore', - label: __( 'Restore' ), - isPrimary: true, - icon: backup, - supportsBulk: true, - isEligible( { status } ) { - return status === 'trash'; - }, - async callback( posts, onActionPerformed ) { - try { - for ( const post of posts ) { - await editEntityRecord( - 'postType', - post.type, - post.id, - { - status: 'draft', - } + if ( errorMessages.size === 0 ) { + errorMessage = __( + 'An error occurred while permanently deleting the posts.' ); - await saveEditedEntityRecord( - 'postType', - post.type, - post.id, - { throwOnError: true } + } else if ( errorMessages.size === 1 ) { + errorMessage = sprintf( + /* translators: %s: an error message */ + __( + 'An error occurred while permanently deleting the posts: %s' + ), + [ ...errorMessages ][ 0 ] + ); + } else { + errorMessage = sprintf( + /* translators: %s: a list of comma separated error messages */ + __( + 'Some errors occurred while permanently deleting the posts: %s' + ), + [ ...errorMessages ].join( ',' ) ); } + } + createErrorNotice( errorMessage, { + type: 'snackbar', + } ); + } + }; + }, +}; - createSuccessNotice( - posts.length > 1 - ? sprintf( - /* translators: The number of posts. */ - __( '%d posts have been restored.' ), - posts.length - ) - : sprintf( - /* translators: The number of posts. */ - __( '"%s" has been restored.' ), - getItemTitle( posts[ 0 ] ) - ), +export const restorePostAction = { + id: 'restore', + label: __( 'Restore' ), + isPrimary: true, + icon: backup, + supportsBulk: true, + isEligible( { status } ) { + return status === 'trash'; + }, + callback( posts ) { + return async ( { dispatch } ) => { + const { createSuccessNotice, createErrorNotice } = + dispatch( noticesStore ); + const { editEntityRecord, saveEditedEntityRecord } = + dispatch( coreStore ); + try { + for ( const post of posts ) { + await editEntityRecord( 'postType', post.type, post.id, { + status: 'draft', + } ); + await saveEditedEntityRecord( + 'postType', + post.type, + post.id, { - type: 'snackbar', - id: 'restore-post-action', + throwOnError: true, } ); - if ( onActionPerformed ) { - onActionPerformed( posts ); - } - } catch ( error ) { - let errorMessage; - if ( - error.message && - error.code !== 'unknown_error' && - error.message - ) { - errorMessage = error.message; - } else if ( posts.length > 1 ) { - errorMessage = __( - 'An error occurred while restoring the posts.' - ); - } else { - errorMessage = __( - 'An error occurred while restoring the post.' - ); - } + } - createErrorNotice( errorMessage, { type: 'snackbar' } ); + createSuccessNotice( + posts.length > 1 + ? sprintf( + /* translators: The number of posts. */ + __( '%d posts have been restored.' ), + posts.length + ) + : sprintf( + /* translators: The number of posts. */ + __( '"%s" has been restored.' ), + getItemTitle( posts[ 0 ] ) + ), + { + type: 'snackbar', + id: 'restore-post-action', + } + ); + this?.onActionPerformed?.( posts ); + } catch ( error ) { + let errorMessage; + if ( + error.message && + error.code !== 'unknown_error' && + error.message + ) { + errorMessage = error.message; + } else if ( posts.length > 1 ) { + errorMessage = __( + 'An error occurred while restoring the posts.' + ); + } else { + errorMessage = __( + 'An error occurred while restoring the post.' + ); } - }, - } ), - [ - createSuccessNotice, - createErrorNotice, - editEntityRecord, - saveEditedEntityRecord, - ] - ); -} -const viewPostAction = { + createErrorNotice( errorMessage, { type: 'snackbar' } ); + } + }; + }, +}; + +export const viewPostAction = { id: 'view-post', label: __( 'View' ), isPrimary: true, @@ -373,16 +347,14 @@ const viewPostAction = { isEligible( post ) { return post.status !== 'trash'; }, - callback( posts, onActionPerformed ) { + callback( posts ) { const post = posts[ 0 ]; window.open( post.link, '_blank' ); - if ( onActionPerformed ) { - onActionPerformed( posts ); - } + this?.onActionPerformed?.( posts ); }, }; -const editPostAction = { +export const editPostAction = { id: 'edit-post', label: __( 'Edit' ), isPrimary: true, @@ -390,13 +362,11 @@ const editPostAction = { isEligible( { status } ) { return status !== 'trash'; }, - callback( posts, onActionPerformed ) { - if ( onActionPerformed ) { - onActionPerformed( posts ); - } + callback( posts ) { + this?.onActionPerformed?.( posts ); }, }; -const postRevisionsAction = { +export const postRevisionsAction = { id: 'view-post-revisions', label: __( 'View revisions' ), isPrimary: false, @@ -410,25 +380,23 @@ const postRevisionsAction = { post?._links?.[ 'version-history' ]?.[ 0 ]?.count ?? 0; return lastRevisionId && revisionsCount > 1; }, - callback( posts, onActionPerformed ) { + callback( posts ) { const post = posts[ 0 ]; const href = addQueryArgs( 'revision.php', { revision: post?._links?.[ 'predecessor-version' ]?.[ 0 ]?.id, } ); document.location.href = href; - if ( onActionPerformed ) { - onActionPerformed( posts ); - } + this?.onActionPerformed?.( posts ); }, }; -const renamePostAction = { +export const renamePostAction = { id: 'rename-post', label: __( 'Rename' ), isEligible( post ) { return post.status !== 'trash'; }, - RenderModal: ( { items, closeModal, onActionPerformed } ) => { + RenderModal: ( { items, closeModal, action } ) => { const [ item ] = items; const originalTitle = decodeEntities( typeof item.title === 'string' ? item.title : item.title.rendered @@ -455,7 +423,7 @@ const renamePostAction = { createSuccessNotice( __( 'Name updated' ), { type: 'snackbar', } ); - onActionPerformed?.( items ); + action.onActionPerformed?.( items ); } catch ( error ) { const errorMessage = error.message && error.code !== 'unknown_error' @@ -500,13 +468,13 @@ const renamePostAction = { }, }; -const resetTemplateAction = { +export const resetTemplateAction = { id: 'reset-template', label: __( 'Reset' ), isEligible: isTemplateRevertable, supportsBulk: true, hideModalHeader: true, - RenderModal: ( { items, closeModal, onActionPerformed } ) => { + RenderModal: ( { items, closeModal, action } ) => { const { revertTemplate } = unlock( useDispatch( editorStore ) ); const { saveEditedEntityRecord } = useDispatch( coreStore ); const { createSuccessNotice, createErrorNotice } = @@ -541,6 +509,7 @@ const resetTemplateAction = { id: 'revert-template-action', } ); + action.onActionPerformed?.( items ); } catch ( error ) { let fallbackErrorMessage; if ( items[ 0 ].type === TEMPLATE_POST_TYPE ) { @@ -583,7 +552,7 @@ const resetTemplateAction = { variant="primary" onClick={ async () => { await onConfirm( items ); - onActionPerformed?.( items ); + this?.onActionPerformed?.( items ); closeModal(); } } > @@ -612,13 +581,13 @@ function isTemplateRemovable( template ) { ); } -const deleteTemplateAction = { +export const deleteTemplateAction = { id: 'delete-template', label: __( 'Delete' ), isEligible: isTemplateRemovable, supportsBulk: true, hideModalHeader: true, - RenderModal: ( { items: templates, closeModal, onActionPerformed } ) => { + RenderModal: ( { items: templates, closeModal, action } ) => { const { removeTemplates } = unlock( useDispatch( editorStore ) ); return ( @@ -651,7 +620,7 @@ const deleteTemplateAction = { await removeTemplates( templates, { allowUndo: false, } ); - onActionPerformed?.( templates ); + action.onActionPerformed?.( templates ); closeModal(); } } > @@ -663,7 +632,7 @@ const deleteTemplateAction = { }, }; -const renameTemplateAction = { +export const renameTemplateAction = { id: 'rename-template', label: __( 'Rename' ), isEligible: ( template ) => { @@ -677,7 +646,7 @@ const renameTemplateAction = { } return true; }, - RenderModal: ( { items: templates, closeModal, onActionPerformed } ) => { + RenderModal: ( { items: templates, closeModal, action } ) => { const template = templates[ 0 ]; const title = decodeEntities( template.title.rendered ); const [ editedTitle, setEditedTitle ] = useState( title ); @@ -719,7 +688,7 @@ const renameTemplateAction = { type: 'snackbar', } ); - onActionPerformed?.( templates ); + action.onActionPerformed?.( templates ); } catch ( error ) { const fallbackErrorMessage = template.type === TEMPLATE_POST_TYPE @@ -767,96 +736,3 @@ const renameTemplateAction = { ); }, }; - -export function usePostActions( onActionPerformed, actionIds = null ) { - const permanentlyDeletePostAction = usePermanentlyDeletePostAction(); - const restorePostAction = useRestorePostAction(); - return useMemo( - () => { - // By default, return all actions... - const defaultActions = [ - editPostAction, - resetTemplateAction, - viewPostAction, - restorePostAction, - deleteTemplateAction, - permanentlyDeletePostAction, - postRevisionsAction, - renamePostAction, - renameTemplateAction, - trashPostAction, - ]; - - // ... unless `actionIds` was specified, in which case we find the - // actions matching the given IDs. - const actions = actionIds - ? actionIds.map( ( actionId ) => - defaultActions.find( ( { id } ) => actionId === id ) - ) - : defaultActions; - - if ( onActionPerformed ) { - for ( let i = 0; i < actions.length; ++i ) { - if ( actions[ i ].callback ) { - const existingCallback = actions[ i ].callback; - actions[ i ] = { - ...actions[ i ], - callback: ( items, _onActionPerformed ) => { - existingCallback( items, ( _items ) => { - if ( _onActionPerformed ) { - _onActionPerformed( _items ); - } - onActionPerformed( - actions[ i ].id, - _items - ); - } ); - }, - }; - } - if ( actions[ i ].RenderModal ) { - const ExistingRenderModal = actions[ i ].RenderModal; - actions[ i ] = { - ...actions[ i ], - RenderModal: ( props ) => { - return ( - { - if ( props.onActionPerformed ) { - props.onActionPerformed( - _items - ); - } - onActionPerformed( - actions[ i ].id, - _items - ); - } } - /> - ); - }, - }; - } - } - } - return actions; - }, - - // Disable reason: if provided, `actionIds` is a shallow array of - // strings, and the strings themselves should be part of the useMemo - // dependencies. Two different disable statements are needed, as the - // first flags what it thinks are missing dependencies, and the second - // flags the array spread operation. - // - // eslint-disable-next-line react-hooks/exhaustive-deps - [ - // eslint-disable-next-line react-hooks/exhaustive-deps - ...( actionIds || [] ), - permanentlyDeletePostAction, - restorePostAction, - onActionPerformed, - ] - ); -} diff --git a/packages/editor/src/components/post-actions/index.js b/packages/editor/src/components/post-actions/index.js index 48d83f992e7056..acf9596359dd4e 100644 --- a/packages/editor/src/components/post-actions/index.js +++ b/packages/editor/src/components/post-actions/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { useSelect } from '@wordpress/data'; +import { useRegistry, useSelect } from '@wordpress/data'; import { useState, useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { @@ -15,7 +15,12 @@ import { moreVertical } from '@wordpress/icons'; * Internal dependencies */ import { unlock } from '../../lock-unlock'; -import { usePostActions } from './actions'; +import { + viewPostAction, + postRevisionsAction, + renamePostAction, + trashPostAction, +} from './actions'; import { store as editorStore } from '../../store'; import { TEMPLATE_POST_TYPE, @@ -31,13 +36,6 @@ const { kebabCase, } = unlock( componentsPrivateApis ); -const POST_ACTIONS_WHILE_EDITING = [ - 'view-post', - 'view-post-revisions', - 'rename-post', - 'move-to-trash', -]; - export default function PostActions( { onActionPerformed, buttonProps } ) { const { postType, item } = useSelect( ( select ) => { const { getCurrentPostType, getCurrentPost } = select( editorStore ); @@ -46,16 +44,26 @@ export default function PostActions( { onActionPerformed, buttonProps } ) { item: getCurrentPost(), }; } ); - const allActions = usePostActions( - onActionPerformed, - POST_ACTIONS_WHILE_EDITING - ); const actions = useMemo( () => { - return allActions.filter( ( action ) => { + const eligibleActions = [ + viewPostAction, + postRevisionsAction, + renamePostAction, + trashPostAction, + ].filter( ( action ) => { return ! action.isEligible || action.isEligible( item ); } ); - }, [ allActions, item ] ); + return eligibleActions.map( ( action ) => { + return { + ...action, + onActionPerformed: ( ...args ) => { + onActionPerformed?.( action.id, ...args ); + action.onActionPerformed?.( ...args ); + }, + }; + } ); + }, [ item, onActionPerformed ] ); if ( [ @@ -127,6 +135,7 @@ function ActionWithModal( { action, item, ActionTrigger } ) { setIsModalOpen( false ) } + action={ action } /> ) } @@ -136,6 +145,7 @@ function ActionWithModal( { action, item, ActionTrigger } ) { // Copied as is from packages/dataviews/src/item-actions.js function ActionsDropdownMenuGroup( { actions, item } ) { + const registry = useRegistry(); return ( { actions.map( ( action ) => { @@ -153,7 +163,18 @@ function ActionsDropdownMenuGroup( { actions, item } ) { action.callback( [ item ] ) } + onClick={ async () => { + const returnResult = await action.callback( [ + item, + ] ); + if ( typeof returnResult === 'function' ) { + await returnResult( { + registry, + select: registry.select, + dispatch: registry.dispatch, + } ); + } + } } /> ); } ) } diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index aae3762794b4d6..c66fc85760b01d 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -23,7 +23,7 @@ import PostViewLink from './components/post-view-link'; import PreviewDropdown from './components/preview-dropdown'; import PreferencesModal from './components/preferences-modal'; import PostActions from './components/post-actions'; -import { usePostActions } from './components/post-actions/actions'; +import * as postActions from './components/post-actions/actions'; import PostCardPanel from './components/post-card-panel'; import PostStatus from './components/post-status'; import ToolsMoreMenuGroup from './components/more-menu/tools-more-menu-group'; @@ -47,7 +47,7 @@ lock( privateApis, { PostViewLink, PreviewDropdown, PreferencesModal, - usePostActions, + postActions, PostCardPanel, PostStatus, ToolsMoreMenuGroup,