Skip to content

Commit

Permalink
Add: Bulk actions API and trash action.
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta authored and oandregal committed Dec 1, 2023
1 parent f987124 commit d0d1456
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 0 deletions.
66 changes: 66 additions & 0 deletions packages/edit-site/src/components/bulk-actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* WordPress dependencies
*/
import { trash } from '@wordpress/icons';
import { useMemo } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { useDispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';

export function useBulkTrashPostAction() {
const { createSuccessNotice, createErrorNotice } =
useDispatch( noticesStore );
const { deleteEntityRecord } = useDispatch( coreStore );
return useMemo(
() => ( {
id: 'move-to-trash',
label: __( 'Move to Trash' ),
isPrimary: true,
icon: trash,
isEligible( data, selection ) {
console.log( {
p: data.filter( ( post ) => selection.includes( post.id ) ),
} );
return ! data
.filter( ( post ) => selection.includes( post.id ) )
.some( ( post ) => post.status === 'trash' );
},
async callback( data, selection ) {
const postsToDelete = data.filter( ( post ) =>
selection.includes( post.id )
);
try {
await Promise.all(
postsToDelete.map( async ( post ) => {
deleteEntityRecord(
'postType',
post.type,
post.id,
{},
{ throwOnError: true }
);
} )
);
createSuccessNotice(
__( 'The selected posts were moved to the trash.' ),
{
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 posts to the trash.'
);

createErrorNotice( errorMessage, { type: 'snackbar' } );
}
},
} ),
[ createErrorNotice, createSuccessNotice, deleteEntityRecord ]
);
}
94 changes: 94 additions & 0 deletions packages/edit-site/src/components/dataviews/bulk-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* WordPress dependencies
*/
import {
ToolbarButton,
Toolbar,
ToolbarGroup,
ToolbarItem,
Popover,
} from '@wordpress/components';
import { useMemo } from '@wordpress/element';
import { __, _n, sprintf } from '@wordpress/i18n';

function PrimaryActionTrigger( { action, onClick } ) {
return (
<ToolbarButton
label={ action.label }
icon={ action.icon }
isDestructive={ action.isDestructive }
size="compact"
onClick={ onClick }
/>
);
}

const EMPTY_ARRAY = [];

export default function BulkActions( {
data,
selection,
bulkActions = EMPTY_ARRAY,
setSelection,
} ) {
const primaryActions = useMemo(
() =>
bulkActions.filter( ( action ) => {
return action.isPrimary && action.isEligible( data, selection );
} ),
[ bulkActions, data, selection ]
);
if (
( selection && selection.length === 0 ) ||
primaryActions.length === 0
) {
return null;
}
return (
<Popover
placement="top-middle"
className="dataviews-bulk-actions-popover"
>
<Toolbar label="Bulk actions">
<div className="dataviews-bulk-actions-toolbar-wrapper">
<ToolbarGroup>
<ToolbarButton onClick={ () => {} } disabled={ true }>
{
// translators: %s: Total number of selected items.
sprintf(
// translators: %s: Total number of selected items.
_n(
'%s item selected',
'%s items selected',
selection.length
),
selection.length
)
}
</ToolbarButton>
<ToolbarButton
onClick={ () => {
setSelection( EMPTY_ARRAY );
} }
>
{ __( 'Deselect' ) }
</ToolbarButton>
</ToolbarGroup>
<ToolbarGroup>
{ primaryActions.map( ( action ) => {
return (
<PrimaryActionTrigger
key={ action.id }
action={ action }
onClick={ () =>
action.callback( data, selection )
}
/>
);
} ) }
</ToolbarGroup>
</div>
</Toolbar>
</Popover>
);
}
16 changes: 16 additions & 0 deletions packages/edit-site/src/components/dataviews/dataviews.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import {
__experimentalVStack as VStack,
__experimentalHStack as HStack,
Popover,
} from '@wordpress/components';
import { useMemo } from '@wordpress/element';

Expand All @@ -15,6 +16,7 @@ import ViewActions from './view-actions';
import Filters from './filters';
import Search from './search';
import { VIEW_LAYOUTS } from './constants';
import BulkActions from './bulk-actions';

export default function DataViews( {
view,
Expand All @@ -28,6 +30,9 @@ export default function DataViews( {
isLoading = false,
paginationInfo,
supportedLayouts,
selection,
setSelection,
bulkActions,
} ) {
const ViewComponent = VIEW_LAYOUTS.find(
( v ) => v.type === view.type
Expand Down Expand Up @@ -72,12 +77,23 @@ export default function DataViews( {
data={ data }
getItemId={ getItemId }
isLoading={ isLoading }
selection={ selection }
setSelection={ setSelection }
/>

<div>
<Pagination
view={ view }
onChangeView={ onChangeView }
paginationInfo={ paginationInfo }
/>
<BulkActions
data={ data }
bulkActions={ bulkActions }
selection={ selection }
setSelection={ setSelection }
/>
</div>
</VStack>
</div>
);
Expand Down
11 changes: 11 additions & 0 deletions packages/edit-site/src/components/dataviews/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,14 @@
.dataviews-action-modal {
z-index: z-index(".dataviews-action-modal");
}

.dataviews-bulk-actions-popover .components-popover__content {
min-width: max-content;
}

.dataviews-bulk-actions-toolbar-wrapper {
display: flex;
flex-grow: 1;
width: 100%;
}

26 changes: 26 additions & 0 deletions packages/edit-site/src/components/page-pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
viewPostAction,
useEditPostAction,
} from '../actions';
import { useBulkTrashPostAction } from '../bulk-actions';
import SideEditor from './side-editor';
import Media from '../media';
import { unlock } from '../../lock-unlock';
Expand Down Expand Up @@ -164,6 +165,20 @@ export default function PagePages() {
totalPages,
} = useEntityRecords( 'postType', postType, queryArgs );

useEffect( () => {
if (
selection.some(
( id ) => ! pages?.some( ( page ) => page.id === id )
)
) {
setSelection(
selection.filter( ( id ) =>
pages?.some( ( page ) => page.id === id )
)
);
}
}, [ pages, selection ] );

const { records: authors, isResolving: isLoadingAuthors } =
useEntityRecords( 'root', 'user' );

Expand Down Expand Up @@ -271,6 +286,9 @@ export default function PagePages() {
const permanentlyDeletePostAction = usePermanentlyDeletePostAction();
const restorePostAction = useRestorePostAction();
const editPostAction = useEditPostAction();

const bulkTrashPostAction = useBulkTrashPostAction();

const actions = useMemo(
() => [
viewPostAction,
Expand All @@ -282,6 +300,11 @@ export default function PagePages() {
],
[ permanentlyDeletePostAction, restorePostAction, editPostAction ]
);

const bulkActions = useMemo(
() => [ bulkTrashPostAction ],
[ bulkTrashPostAction ]
);
const onChangeView = useCallback(
( viewUpdater ) => {
let updatedView =
Expand Down Expand Up @@ -310,11 +333,14 @@ export default function PagePages() {
paginationInfo={ paginationInfo }
fields={ fields }
actions={ actions }
bulkActions={ bulkActions }
data={ pages || EMPTY_ARRAY }
getItemId={ ( item ) => item.id }
isLoading={ isLoadingPages || isLoadingAuthors }
view={ view }
onChangeView={ onChangeView }
selection={ selection }
setSelection={ setSelection }
/>
</Page>
{ VIEW_LAYOUTS.find( ( v ) => v.type === view.type )?.supports
Expand Down

0 comments on commit d0d1456

Please sign in to comment.