Skip to content

Commit

Permalink
[Data views]: Add quick actions (#55488)
Browse files Browse the repository at this point in the history
* [Data views]: Add quick actions

* address feedback part 1

* move all action to single file

* address feedback
  • Loading branch information
ntsekouras authored Oct 25, 2023
1 parent ff62185 commit d6352bd
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 89 deletions.
123 changes: 123 additions & 0 deletions packages/edit-site/src/components/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* WordPress dependencies
*/
import { external, trash } from '@wordpress/icons';
import { addQueryArgs } from '@wordpress/url';
import { useDispatch } from '@wordpress/data';
import { decodeEntities } from '@wordpress/html-entities';
import { store as coreStore } from '@wordpress/core-data';
import { __, sprintf } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { useMemo } from '@wordpress/element';
import { privateApis as routerPrivateApis } from '@wordpress/router';
/**
* Internal dependencies
*/
import { unlock } from '../../lock-unlock';

const { useHistory } = unlock( routerPrivateApis );

export function useTrashPostAction() {
const { createSuccessNotice, createErrorNotice } =
useDispatch( noticesStore );
const { deleteEntityRecord } = useDispatch( coreStore );

return useMemo(
() => ( {
id: 'move-to-trash',
label: __( 'Move to Trash' ),
isPrimary: true,
icon: trash,
isEligible( { status } ) {
return status !== 'trash';
},
async perform( post ) {
try {
await deleteEntityRecord(
'postType',
post.type,
post.id,
{},
{ throwOnError: true }
);
createSuccessNotice(
sprintf(
/* translators: The page's title. */
__( '"%s" moved to the Trash.' ),
decodeEntities( post.title.rendered )
),
{
type: 'snackbar',
id: 'edit-site-page-trashed',
}
);
} catch ( error ) {
const errorMessage =
error.message && error.code !== 'unknown_error'
? error.message
: __(
'An error occurred while moving the page to the trash.'
);

createErrorNotice( errorMessage, { type: 'snackbar' } );
}
},
} ),
[ createSuccessNotice, createErrorNotice, deleteEntityRecord ]
);
}

export const viewPostAction = {
id: 'view-post',
label: __( 'View' ),
isPrimary: true,
icon: external,
isEligible( post ) {
return post.status !== 'trash';
},
perform( post ) {
document.location.href = post.link;
},
};

export function useEditPostAction() {
const history = useHistory();
return useMemo(
() => ( {
id: 'edit-post',
label: __( 'Edit' ),
isEligible( { status } ) {
return status !== 'trash';
},
perform( post ) {
history.push( {
postId: post.id,
postType: post.type,
canvas: 'edit',
} );
},
} ),
[ history ]
);
}
export const postRevisionsAction = {
id: 'view-post-revisions',
label: __( 'View revisions' ),
isPrimary: false,
isEligible: ( post ) => {
if ( post.status === 'trash' ) {
return false;
}
const lastRevisionId =
post?._links?.[ 'predecessor-version' ]?.[ 0 ]?.id ?? null;
const revisionsCount =
post?._links?.[ 'version-history' ]?.[ 0 ]?.count ?? 0;
return lastRevisionId && revisionsCount > 1;
},
perform( post ) {
const href = addQueryArgs( 'revision.php', {
revision: post?._links?.[ 'predecessor-version' ]?.[ 0 ]?.id,
} );
document.location.href = href;
},
};
55 changes: 0 additions & 55 deletions packages/edit-site/src/components/actions/trash-post.js

This file was deleted.

28 changes: 0 additions & 28 deletions packages/edit-site/src/components/dataviews/field-actions.js

This file was deleted.

69 changes: 69 additions & 0 deletions packages/edit-site/src/components/dataviews/item-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* WordPress dependencies
*/
import {
DropdownMenu,
MenuGroup,
MenuItem,
Button,
__experimentalHStack as HStack,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useMemo } from '@wordpress/element';
import { moreVertical } from '@wordpress/icons';

export default function ItemActions( { item, actions } ) {
const { primaryActions, secondaryActions } = useMemo( () => {
return actions.reduce(
( accumulator, action ) => {
// If an action is eligible for all items, doesn't need
// to provide the `isEligible` function.
if ( action.isEligible && ! action.isEligible( item ) ) {
return accumulator;
}
if ( action.isPrimary && !! action.icon ) {
accumulator.primaryActions.push( action );
} else {
accumulator.secondaryActions.push( action );
}
return accumulator;
},
{ primaryActions: [], secondaryActions: [] }
);
}, [ actions, item ] );
if ( ! primaryActions.length && ! secondaryActions.length ) {
return null;
}
return (
<HStack justify="flex-end">
{ !! primaryActions.length &&
primaryActions.map( ( action ) => (
<Button
label={ action.label }
key={ action.id }
icon={ action.icon }
onClick={ () => action.perform( item ) }
isDestructive={ action.isDestructive }
size="compact"
/>
) ) }
{ !! secondaryActions.length && (
<DropdownMenu icon={ moreVertical } label={ __( 'Actions' ) }>
{ () => (
<MenuGroup>
{ secondaryActions.map( ( action ) => (
<MenuItem
key={ action.id }
onClick={ () => action.perform( item ) }
isDestructive={ action.isDestructive }
>
{ action.label }
</MenuItem>
) ) }
</MenuGroup>
) }
</DropdownMenu>
) }
</HStack>
);
}
4 changes: 2 additions & 2 deletions packages/edit-site/src/components/dataviews/view-grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
/**
* Internal dependencies
*/
import FieldActions from './field-actions';
import ItemActions from './item-actions';

export function ViewGrid( { data, fields, view, actions } ) {
const mediaField = fields.find(
Expand Down Expand Up @@ -50,7 +50,7 @@ export function ViewGrid( { data, fields, view, actions } ) {
) ) }
</VStack>
</FlexBlock>
<FieldActions item={ item } actions={ actions } />
<ItemActions item={ item } actions={ actions } />
</HStack>
</VStack>
);
Expand Down
4 changes: 2 additions & 2 deletions packages/edit-site/src/components/dataviews/view-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { useMemo, Children, Fragment } from '@wordpress/element';
* Internal dependencies
*/
import { unlock } from '../../lock-unlock';
import FieldActions from './field-actions';
import ItemActions from './item-actions';

const {
DropdownMenuV2,
Expand Down Expand Up @@ -160,7 +160,7 @@ function ViewList( {
id: 'actions',
cell: ( props ) => {
return (
<FieldActions
<ItemActions
item={ props.row.original }
actions={ actions }
/>
Expand Down
18 changes: 16 additions & 2 deletions packages/edit-site/src/components/page-pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ import { dateI18n, getDate, getSettings } from '@wordpress/date';
import Page from '../page';
import Link from '../routes/link';
import { DataViews } from '../dataviews';
import useTrashPostAction from '../actions/trash-post';
import {
useTrashPostAction,
postRevisionsAction,
viewPostAction,
useEditPostAction,
} from '../actions';
import Media from '../media';
import DataviewsContext from '../dataviews/context';
import { DEFAULT_STATUSES } from '../dataviews/provider';
Expand Down Expand Up @@ -208,7 +213,16 @@ export default function PagePages() {
] );

const trashPostAction = useTrashPostAction();
const actions = useMemo( () => [ trashPostAction ], [ trashPostAction ] );
const editPostAction = useEditPostAction();
const actions = useMemo(
() => [
viewPostAction,
trashPostAction,
editPostAction,
postRevisionsAction,
],
[ trashPostAction, editPostAction ]
);
const onChangeView = useCallback(
( viewUpdater ) => {
let updatedView =
Expand Down

0 comments on commit d6352bd

Please sign in to comment.