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

Add: Bulk actions to dataviews with the new design. #57255

Merged
merged 32 commits into from
Jan 11, 2024

Conversation

jorgefilipecosta
Copy link
Member

@jorgefilipecosta jorgefilipecosta commented Dec 20, 2023

Supersedes: #56476, #56615

This PR proposes a bulk actions implementation using the DropDownMenuV2 component trying to follow the design proposed at #56476 (comment).

For now, bulk actions are implemented only for templates.
If multiple items are selected, each one supporting different bulk actions, we show the number of elements the action applies to and only apply the action to the eligible elements.

The actions API was expanded with a supportsBulk option. We need to know if the action supports a bulk option or one to decide if it appears in the bulk edit menu. E.g.: A see revisions action would not make sense under bulk edit.

The actions API callback and Render modal were also changed so the items are an array (support multiple items instead of just one).

Screenshots or screencast

Screenshot 2023-12-20 at 10 56 51

@jorgefilipecosta jorgefilipecosta added [Type] Experimental Experimental feature or API. [Feature] DataViews Work surrounding upgrading and evolving views in the site editor and beyond labels Dec 20, 2023
Copy link

github-actions bot commented Dec 20, 2023

Size Change: +2.16 kB (0%)

Total Size: 1.7 MB

Filename Size Change
build/components/index.min.js 235 kB +66 B (0%)
build/edit-site/index.min.js 197 kB +1.72 kB (+1%)
build/edit-site/style-rtl.css 15.2 kB +183 B (+1%)
build/edit-site/style.css 15.3 kB +186 B (+1%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 964 B
build/annotations/index.min.js 2.71 kB
build/api-fetch/index.min.js 2.29 kB
build/autop/index.min.js 2.11 kB
build/blob/index.min.js 590 B
build/block-directory/index.min.js 7.25 kB
build/block-directory/style-rtl.css 1.04 kB
build/block-directory/style.css 1.04 kB
build/block-editor/content-rtl.css 4.31 kB
build/block-editor/content.css 4.31 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-editor/index.min.js 247 kB
build/block-editor/style-rtl.css 15.3 kB
build/block-editor/style.css 15.3 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 138 B
build/block-library/blocks/audio/theme.css 138 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 419 B
build/block-library/blocks/button/editor.css 417 B
build/block-library/blocks/button/style-rtl.css 632 B
build/block-library/blocks/button/style.css 631 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 421 B
build/block-library/blocks/columns/style.css 421 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 647 B
build/block-library/blocks/cover/editor.css 650 B
build/block-library/blocks/cover/style-rtl.css 1.7 kB
build/block-library/blocks/cover/style.css 1.69 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 98 B
build/block-library/blocks/details/style.css 98 B
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 138 B
build/block-library/blocks/embed/theme.css 138 B
build/block-library/blocks/file/editor-rtl.css 316 B
build/block-library/blocks/file/editor.css 316 B
build/block-library/blocks/file/style-rtl.css 280 B
build/block-library/blocks/file/style.css 281 B
build/block-library/blocks/file/view.min.js 322 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 229 B
build/block-library/blocks/form-input/editor.css 228 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 343 B
build/block-library/blocks/form-submission-notification/editor.css 342 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 452 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 957 B
build/block-library/blocks/gallery/editor.css 962 B
build/block-library/blocks/gallery/style-rtl.css 1.75 kB
build/block-library/blocks/gallery/style.css 1.75 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 189 B
build/block-library/blocks/heading/style.css 189 B
build/block-library/blocks/html/editor-rtl.css 340 B
build/block-library/blocks/html/editor.css 341 B
build/block-library/blocks/image/editor-rtl.css 834 B
build/block-library/blocks/image/editor.css 833 B
build/block-library/blocks/image/style-rtl.css 1.61 kB
build/block-library/blocks/image/style.css 1.6 kB
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/image/view.min.js 2.02 kB
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 505 B
build/block-library/blocks/media-text/style.css 503 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 671 B
build/block-library/blocks/navigation-link/editor.css 672 B
build/block-library/blocks/navigation-link/style-rtl.css 103 B
build/block-library/blocks/navigation-link/style.css 103 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation/editor-rtl.css 2.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.25 kB
build/block-library/blocks/navigation/style.css 2.23 kB
build/block-library/blocks/navigation/view.min.js 1.1 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 401 B
build/block-library/blocks/page-list/editor.css 401 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 508 B
build/block-library/blocks/post-comments-form/style.css 508 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 666 B
build/block-library/blocks/post-featured-image/editor.css 662 B
build/block-library/blocks/post-featured-image/style-rtl.css 345 B
build/block-library/blocks/post-featured-image/style.css 345 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 409 B
build/block-library/blocks/post-template/style.css 408 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 335 B
build/block-library/blocks/pullquote/style.css 335 B
build/block-library/blocks/pullquote/theme-rtl.css 168 B
build/block-library/blocks/pullquote/theme.css 168 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/style-rtl.css 312 B
build/block-library/blocks/query/style.css 308 B
build/block-library/blocks/query/view.min.js 647 B
build/block-library/blocks/quote/style-rtl.css 237 B
build/block-library/blocks/quote/style.css 237 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 140 B
build/block-library/blocks/read-more/style.css 140 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 602 B
build/block-library/blocks/search/style.css 602 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 475 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 234 B
build/block-library/blocks/separator/style.css 234 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 329 B
build/block-library/blocks/shortcode/editor.css 329 B
build/block-library/blocks/site-logo/editor-rtl.css 760 B
build/block-library/blocks/site-logo/editor.css 760 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 682 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/social-links/style-rtl.css 1.49 kB
build/block-library/blocks/social-links/style.css 1.49 kB
build/block-library/blocks/spacer/editor-rtl.css 359 B
build/block-library/blocks/spacer/editor.css 359 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 395 B
build/block-library/blocks/table/editor.css 395 B
build/block-library/blocks/table/style-rtl.css 646 B
build/block-library/blocks/table/style.css 645 B
build/block-library/blocks/table/theme-rtl.css 157 B
build/block-library/blocks/table/theme.css 157 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 403 B
build/block-library/blocks/template-part/editor.css 403 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 191 B
build/block-library/blocks/video/style.css 191 B
build/block-library/blocks/video/theme-rtl.css 139 B
build/block-library/blocks/video/theme.css 139 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.11 kB
build/block-library/common.css 1.11 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 12.3 kB
build/block-library/editor.css 12.3 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 215 kB
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 14.7 kB
build/block-library/style.css 14.7 kB
build/block-library/theme-rtl.css 700 B
build/block-library/theme.css 705 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.6 kB
build/commands/index.min.js 15.5 kB
build/commands/style-rtl.css 947 B
build/commands/style.css 942 B
build/components/style-rtl.css 12.1 kB
build/components/style.css 12.1 kB
build/compose/index.min.js 12.8 kB
build/core-commands/index.min.js 2.73 kB
build/core-data/index.min.js 72.7 kB
build/customize-widgets/index.min.js 12.1 kB
build/customize-widgets/style-rtl.css 1.36 kB
build/customize-widgets/style.css 1.36 kB
build/data-controls/index.min.js 651 B
build/data/index.min.js 8.94 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 462 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.68 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/index.min.js 27.9 kB
build/edit-post/style-rtl.css 6.29 kB
build/edit-post/style.css 6.27 kB
build/edit-widgets/index.min.js 17.3 kB
build/edit-widgets/style-rtl.css 4.72 kB
build/edit-widgets/style.css 4.72 kB
build/editor/index.min.js 59.1 kB
build/editor/style-rtl.css 5.21 kB
build/editor/style.css 5.21 kB
build/element/index.min.js 4.87 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 7.98 kB
build/format-library/style-rtl.css 500 B
build/format-library/style.css 500 B
build/hooks/index.min.js 1.57 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.61 kB
build/interactivity/file.min.js 442 B
build/interactivity/image.min.js 2.15 kB
build/interactivity/index.min.js 12.5 kB
build/interactivity/navigation.min.js 1.23 kB
build/interactivity/query.min.js 791 B
build/interactivity/search.min.js 610 B
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.76 kB
build/keycodes/index.min.js 1.49 kB
build/list-reusable-blocks/index.min.js 2.11 kB
build/list-reusable-blocks/style-rtl.css 865 B
build/list-reusable-blocks/style.css 865 B
build/media-utils/index.min.js 2.92 kB
build/modules/importmap-polyfill.min.js 12.2 kB
build/notices/index.min.js 964 B
build/nux/index.min.js 2.01 kB
build/nux/style-rtl.css 775 B
build/nux/style.css 771 B
build/patterns/index.min.js 5.37 kB
build/patterns/style-rtl.css 564 B
build/patterns/style.css 564 B
build/plugins/index.min.js 1.81 kB
build/preferences-persistence/index.min.js 2.07 kB
build/preferences/index.min.js 1.26 kB
build/primitives/index.min.js 994 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 1 kB
build/react-i18n/index.min.js 631 B
build/react-refresh-entry/index.min.js 9.46 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.71 kB
build/reusable-blocks/index.min.js 2.74 kB
build/reusable-blocks/style-rtl.css 265 B
build/reusable-blocks/style.css 265 B
build/rich-text/index.min.js 10.4 kB
build/router/index.min.js 1.79 kB
build/server-side-render/index.min.js 1.96 kB
build/shortcode/index.min.js 1.4 kB
build/style-engine/index.min.js 2.06 kB
build/token-list/index.min.js 587 B
build/url/index.min.js 3.83 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 967 B
build/warning/index.min.js 259 B
build/widgets/index.min.js 7.22 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.18 kB
build/wordcount/index.min.js 1.03 kB

compressed-size-action

@jameskoster
Copy link
Contributor

I think the work here can pave the way for more elaborate designs in the future, but for now this feels like a good starting point that is lightweight and accessible.

Visually the menu doesn't seem to match the latest DropdownMenuV2 designs, perhaps that will be fixed by a rebase?

Could we try moving the 'Bulk edit' button to the right, just left of the 'View options' button?

For now, bulk actions are implemented only for templates.

I'm seeing the selection controls on the Pages list, should those be disabled altogether if there are no actions?

@jorgefilipecosta jorgefilipecosta force-pushed the add/bulk-actions-to-dataviews branch from 35605cc to 69257e6 Compare December 29, 2023 19:27
@youknowriad
Copy link
Contributor

I was kind of surprised to see the checkboxes and bulk actions kind of visible by default. I think I've expected to have to first click "bulk edit" to show the checkboxes and the bulk actions menu. Just wondering if this is something that has been discussed?

@youknowriad
Copy link
Contributor

In the "pages" dataviews, I can see the checkboxes and the bulk selection menu even though I don't see any bulk actions to perform.

@youknowriad
Copy link
Contributor

Probably a follow-up but did we think about the UI for bulk selection in "list" and "grid" layouts?

@youknowriad
Copy link
Contributor

Maybe I'm doing something wrong but clicking the "reset" or "delete template" bulk actions does nothing for me.

@jorgefilipecosta jorgefilipecosta force-pushed the add/bulk-actions-to-dataviews branch 2 times, most recently from 9bce3f4 to 1e1a01c Compare January 3, 2024 17:18
@jorgefilipecosta
Copy link
Member Author

Maybe I'm doing something wrong but clicking the "reset" or "delete template" bulk actions does nothing for me.

Sorry, I missed pushing a post-rebase fix I had locally (onSelect -> onClick on a component that changed) it should be working now.

@jorgefilipecosta
Copy link
Member Author

Probably a follow-up but did we think about the UI for bulk selection in "list" and "grid" layouts?

I will implement the other views bulk actions in separate PRs to keep this one smaller. As far as I know, there are no mockups yet. I expect both for list and grid pressing shift plus a click would trigger multi selection of elements that seems to be a common pattern. But I'm to other options.

@jorgefilipecosta
Copy link
Member Author

jorgefilipecosta commented Jan 3, 2024

I was kind of surprised to see the checkboxes and bulk actions kind of visible by default. I think I've expected to have to first click "bulk edit" to show the checkboxes and the bulk actions menu. Just wondering if this is something that has been discussed?

I believe we haven't discussed this option yet. The Bulk Edit menu triggers a dropdown, which could make it a bit confusing to display checkboxes as well. To use this option, we would first need to click on "Bulk edit", which would display the checkboxes along with an actions menu. When we click on the actions menu, the current dropdown will appear with the actions and options to select all or deselect all. We would also need a button like stop bulk edit to hide checkboxes again.

We can also consider another option where we hide the checkboxes to reduce visual clutter, but display them when we hover the mouse over a row.

@jorgefilipecosta
Copy link
Member Author

I think the work here can pave the way for more elaborate designs in the future, but for now this feels like a good starting point that is lightweight and accessible.

Visually the menu doesn't seem to match the latest DropdownMenuV2 designs, perhaps that will be fixed by a rebase?

Could we try moving the 'Bulk edit' button to the right, just left of the 'View options' button?

I added a secondary style to the bulk edit button, it should now have a similar style to the story book sample.
I also changed the position as suggested.

For now, bulk actions are implemented only for templates.

I'm seeing the selection controls on the Pages list, should those be disabled altogether if there are no actions?

The issue was fixed.

@jorgefilipecosta
Copy link
Member Author

In the "pages" dataviews, I can see the checkboxes and the bulk selection menu even though I don't see any bulk actions to perform.

Fixed 👍

@jameskoster
Copy link
Contributor

Just wondering if this is something that has been discussed?

A 'bulk edit' mode was explored early on (similar to the media library in wp-admin) but it didn't feel super compelling, mostly due to the friction it adds to the selection process. It was quite difficult to answer: "why not make those controls permanently available"? It also raised questions about other table features when such a mode was active, e.g. would it still be possible to perform inline edits/actions, filtering, etc? In short it solves some issues while introducing others.

I would say that the checkboxes themselves feel quite prominent visually, and that perhaps overemphasises bulk actions. This could be a detail to visit separately, and there are a few options to explore there:

  • Reduce checkbox visual size (most design systems use ≤16px, checkboxes in Gutenberg are currently 20px).
  • Only show checkbox on row hover/selection.
  • Include a view option to hide checkbox column. This would effectively allow users to create a custom "bulk edit" view if they wanted to, kind of similar to the 'bulk edit mode' that was explored initially.

@youknowriad
Copy link
Contributor

"why not make those controls permanently available"

I guess for me the answer to this is that I don't see bulk editing as the primary action on the lists, and something you'd rarely don, only for advanced use-cases. So it seems counter intuitive for me for these controls to be so prominent.

@youknowriad
Copy link
Contributor

Screenshot 2024-01-04 at 4 29 05 PM

This button is not well spaced.

Also, I noticed that there's a focus loss issue on both actions, maybe a good approach would be to focus the "bulk edit" button once the action is performed.

Other than that, this seems fine to land as v1

@jorgefilipecosta jorgefilipecosta force-pushed the add/bulk-actions-to-dataviews branch from 6408593 to 1e37b3e Compare January 4, 2024 23:22
@jorgefilipecosta
Copy link
Member Author

Screenshot 2024-01-04 at 4 29 05 PM This button is not well spaced.

Also, I noticed that there's a focus loss issue on both actions, maybe a good approach would be to focus the "bulk edit" button once the action is performed.

Other than that, this seems fine to land as v1

Hi @youknowriad thank you for catching these issues, I think both of them were fixed.

.dataviews__filters-custom-menu-radio-item-prefix {
display: block;
width: 24px;
}

.dataviews-bulk-edit-button.components-button.is-secondary {
padding-right: $grid-unit-15 + 2px;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need a special padding in the first place. For me, the issue seems to be that the flex behavior is "shrinking" the width of the button so instead of a custom padding (which result in a wrong balance for me btw), we need to use flex-string: 0

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good one flex-shrink did the trick. I did not find the root cause of why the button was cut on the right and the padding was like a last resource to address the issue.

action,
selectedItems,
setActionWithModal,
bulkActionsButtonRef,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this prop. In general I don't like passing refs and Dom elements as props because: Which can of ref is this, an object, a function?... Also, they're subject to timing changes and mutations.

A better API here could be onPerform or something like that. Something to be called when the action is done for instance.

That said, I do wonder: I believe modals and popover have a built-in behavior to restore the focus to the caller (button that opened the popover/modal), in this case it doesn't work natively, so I'm curious to know why the "focus return" don't work by default when the dropdown get closed. cc @ciampo

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe modals and popover have a built-in behavior to restore the focus to the caller

The Modal, when closed, will try to restore focus on the element that was last focused before opening the modal — ie. the menu item. Similarly, the DropdownMenu will try to restore focus on the menu trigger when closed.

Therefore, if we want to focus the dropdown menu trigger when closing the modal, that may be something that needs to be implemented in a custom way. An alternative that we could consider is to leave the dropdown menu open — in theory, the modal component should be able to restore focus correctly on the menu item when closed (see storybook example).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Modal, when closed, will try to restore focus on the element that was last focused before opening the modal — ie. the menu item. Similarly, the DropdownMenu will try to restore focus on the menu trigger when closed.

I guess in my mind, when I click the trigger it should get focused and then open the modal so it's the last item that was focused before the modal is opened.

But now that you bring this up, I remember some discrepancies between browsers and not all of them have the "focus on click" behavior. Which means that maybe it's because of me testing on Safari which makes me wonder whether we should bother about fixing this issue (should we just revert the commit?) as this is the expected behavior there. I'll check in chrome (before the commit) to confirm.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and tried to implement an alternative solution that doesn't rely on bulkActionsButtonRef at all (and keeps the dropdown menu open in the background when rendering the modal). Could this work?

Click to expand
diff --git a/packages/dataviews/src/bulk-actions.js b/packages/dataviews/src/bulk-actions.js
index 9613ff37ee..3fa5db3d76 100644
--- a/packages/dataviews/src/bulk-actions.js
+++ b/packages/dataviews/src/bulk-actions.js
@@ -25,7 +25,7 @@ function ActionWithModal( {
 	action,
 	selectedItems,
 	setActionWithModal,
-	bulkActionsButtonRef,
+	onMenuOpenChange,
 } ) {
 	const eligibleItems = useMemo( () => {
 		return selectedItems.filter( ( item ) => action.isEligible( item ) );
@@ -33,11 +33,10 @@ function ActionWithModal( {
 	const { RenderModal, hideModalHeader } = action;
 	const onCloseModal = useCallback( () => {
 		setActionWithModal( undefined );
-		// Focus the bulk actions button.
-		if ( bulkActionsButtonRef?.current?.focus ) {
-			bulkActionsButtonRef.current.focus();
-		}
-	}, [ setActionWithModal, bulkActionsButtonRef ] );
+		// Close dropdownmenu
+		// TODO: should be called only if the primary action of the modal is clicked
+		onMenuOpenChange( false );
+	}, [ setActionWithModal, onMenuOpenChange ] );
 	return (
 		<Modal
 			title={ ! hideModalHeader && action.label }
@@ -50,31 +49,23 @@ function ActionWithModal( {
 	);
 }
 
-function BulkActionItem( {
-	action,
-	selectedItems,
-	onMenuOpenChange,
-	setActionWithModal,
-	bulkActionsButtonRef,
-} ) {
+function BulkActionItem( { action, selectedItems, setActionWithModal } ) {
 	const eligibleItems = useMemo( () => {
 		return selectedItems.filter( ( item ) => action.isEligible( item ) );
 	}, [ action, selectedItems ] );
+
+	const shouldShowModal = !! action.RenderModal;
+
 	return (
 		<DropdownMenuItem
 			key={ action.id }
 			disabled={ eligibleItems.length === 0 }
-			onClick={ async ( event ) => {
-				event.preventDefault();
-				if ( !! action.RenderModal ) {
-					onMenuOpenChange( false );
+			hideOnClick={ ! shouldShowModal }
+			onClick={ async () => {
+				if ( shouldShowModal ) {
 					setActionWithModal( action );
 				} else {
 					await action.callback( eligibleItems );
-					// Click the bulk actions button to close the dropdown and focus the button.
-					if ( bulkActionsButtonRef?.current?.click ) {
-						bulkActionsButtonRef.current.click();
-					}
 				}
 			} }
 			suffix={
@@ -86,13 +77,7 @@ function BulkActionItem( {
 	);
 }
 
-function ActionsMenuGroup( {
-	actions,
-	selectedItems,
-	onMenuOpenChange,
-	setActionWithModal,
-	bulkActionsButtonRef,
-} ) {
+function ActionsMenuGroup( { actions, selectedItems, setActionWithModal } ) {
 	return (
 		<>
 			<DropdownMenuGroup>
@@ -101,9 +86,7 @@ function ActionsMenuGroup( {
 						key={ action.id }
 						action={ action }
 						selectedItems={ selectedItems }
-						onMenuOpenChange={ onMenuOpenChange }
 						setActionWithModal={ setActionWithModal }
-						bulkActionsButtonRef={ bulkActionsButtonRef }
 					/>
 				) ) }
 			</DropdownMenuGroup>
@@ -131,7 +114,7 @@ export default function BulkActions( {
 			selection.includes( getItemId( item ) )
 		);
 	}, [ selection, data, getItemId ] );
-	const bulkActionsButtonRef = useRef();
+
 	if ( bulkActions.length === 0 ) {
 		return null;
 	}
@@ -143,7 +126,6 @@ export default function BulkActions( {
 				label={ __( 'Filters' ) }
 				trigger={
 					<Button
-						ref={ bulkActionsButtonRef }
 						className="dataviews-bulk-edit-button"
 						__next40pxDefaultSize
 						variant="secondary"
@@ -164,19 +146,14 @@ export default function BulkActions( {
 			>
 				<ActionsMenuGroup
 					actions={ bulkActions }
-					data={ data }
-					selection={ selection }
-					getItemId={ getItemId }
-					onMenuOpenChange={ onMenuOpenChange }
 					setActionWithModal={ setActionWithModal }
 					selectedItems={ selectedItems }
-					bulkActionsButtonRef={ bulkActionsButtonRef }
 				/>
 				<DropdownMenuGroup>
 					<DropdownMenuItem
 						disabled={ areAllSelected }
-						onClick={ ( event ) => {
-							event.preventDefault();
+						hideOnClick={ false }
+						onClick={ () => {
 							onSelectionChange( data );
 						} }
 						suffix={ data.length }
@@ -185,8 +162,8 @@ export default function BulkActions( {
 					</DropdownMenuItem>
 					<DropdownMenuItem
 						disabled={ selection.length === 0 }
-						onClick={ ( event ) => {
-							event.preventDefault();
+						hideOnClick={ false }
+						onClick={ () => {
 							onSelectionChange( [] );
 						} }
 					>
@@ -199,7 +176,7 @@ export default function BulkActions( {
 					action={ actionWithModal }
 					selectedItems={ selectedItems }
 					setActionWithModal={ setActionWithModal }
-					bulkActionsButtonRef={ bulkActionsButtonRef }
+					onMenuOpenChange={ onMenuOpenChange }
 				/>
 			) }
 		</>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I just did more testing and here's my findings:

First issue

For the "reset template" action, there's no modal, but what's happening there is that the "dropdown" stays open but the action become "disabled" which means there's a focus loss. I believe there are two things we should do here:

  • The simple solution is to just close the dropdown when the action is done onActionPerformed or something which should in theory restore the focus to the trigger.
  • The second thing that we need to do IMO (even if it's probably not necessary once the first solution is implemented) is that "disabled" menu items in the dropdown menu shouldn't be "disabled" entirely, they should use the aria-disabled trick. (Equivalent to the __experimentalIsFocusable prop on the Button component). This will allow the buttons to stay focusable and prevent focus loss even though the action is disabled.

Second issue

For the "delete template" action, there's a modal, so there are nested dialogs basically. And in this case, everything closes and there's a focus loss. I'm not entirely sure what's happening here so I have no solutions to offer for this case yet, but my guess is that with the "aria-disabled" trick that I suggest above, there's a small chance of this issue being fixed as well.


I guess what I'm saying is that we shouldn't try to add custom code to solve these focus loss issues for this particular UI, instead we should try first to address the systemic issues that I raise above. Does that make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And for the second issue, you're right as well, the popover is closed when the modal is opened. I'm not entirely sure if we do this on purpose or not but could this be the result of "focus loss". Since the focus is not on the popover anymore, it just closes itself. In other words, our popovers/dropdowns might not support nested dialogs being focused properly yet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • It actually becomes a "div" and not a button anymore. Weird. So it's a similar issue but different trigger. so yes, not the aria-disabled trick.
  • The activeElement is the dropdown wrapper in my tests, so it seems there's some code in place already that handle a focus fallback or something.

I think all dropdown menu items are actually div[role="menuitem"] elements.

Regarding the activeElement:

  • when using the keyboard to click the "Deselect" item, focus stays on the item
  • when using the mouse, focus moves to the menu wrapper

So I believe that focus is already being handled correctly by the underlying ariakit implementation.

And for the second issue, you're right as well, the popover is closed when the modal is opened. I'm not entirely sure if we do this on purpose or not but could this be the result of "focus loss". Since the focus is not on the popover anymore, it just closes itself.

Closing the dropownmenu when opening the modal is indeed the cause for focus loss. If we kept the dropdownmenu open, the menu item that was clicked to open the modal would receive focus when the modal gets closed.

In other words, our popovers/dropdowns might not support nested dialogs being focused properly yet.

IMO, the better approach (also UX-wise) is to keep the dropdown menu open under the modal. Doing so should also allow the components to handle focus correctly without extra code:

  • Modal would handle focus restoration when dismissing the modal by focusing the correct dropdown menu item
  • If we want to force the dropdown menu to close, setting its open prop to false should move focus automatically on the dropdownmenu trigger. So we should be already able to cover

When used that way, our components should already handle focus correctly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, the better approach (also UX-wise) is to keep the dropdown menu open under the modal

I agree but my question was: Is that even possible with our current components. I believe most of our "popovers"... close themselves when they lose focus to a child modal/popover but you say otherwise, so that's news for me :)

Copy link
Contributor

@ciampo ciampo Jan 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! The new DropdownMenu menu doesn't use our underlying Modal component, and can be definitely be kept open under a Modal.

I hope that the solution proposed above can be a good starting point for a better UX

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I applied the patch suggested by @ciampo and implemented the remaining todo specified there. Thank you a lot for providing a detailed patch! Things seem to be working well.
The current behavior is:

  • When an action without modal is executed the menu closes and the focus goes to bulk editor button.
  • When an action opens a modal the menu keeps open if the modal is closed the focus goes to the button that triggered the modal, if the action in the modal is executed the menu gets closed and the focus goes back to the bulk edit button.

@youknowriad @ciampo let me know if there is any other update required.

@jameskoster
Copy link
Contributor

I guess for me the answer to this is that I don't see bulk editing as the primary action on the lists, and something you'd rarely don, only for advanced use-cases

I'd agree bulk actions are not always primary, but I don't know that they're 'only advanced'. There are some fairly common flows where bulk actions are situationally primary, e.g. moderating comments, deleting inactive plugins, updating tags or categories. I'd still like to explore fine tuning the visual prominence before introducing a dedicated mode, there are many things to try there.

@jorgefilipecosta jorgefilipecosta force-pushed the add/bulk-actions-to-dataviews branch from d2dfac6 to 3ce5184 Compare January 11, 2024 15:37
@jameskoster
Copy link
Contributor

jameskoster commented Jan 11, 2024

@jorgefilipecosta my style changes from yesterday seem to have vanished 🤔 Is there any way to retrieve them or must I re-do that work?

Edit: Never mind, I re-did it :d

@jorgefilipecosta
Copy link
Member Author

@jorgefilipecosta my style changes from yesterday seem to have vanished 🤔 Is there any way to retrieve them or must I re-do that work?

Edit: Never mind, I re-did it :d

I'm sorry I'm not sure what happened probably some rebase issue 😞 thank you for re-adding the commit 🙇

@jorgefilipecosta
Copy link
Member Author

All the blockers have been addressed thank you all for the feedback, reviews, commits, and suggestions. I will merge this PR so we can continue with follow-ups and related work and avoid other big rebases. However, any feedback is still welcome and will be applied as a follow-up.

@jorgefilipecosta jorgefilipecosta merged commit f154dc7 into trunk Jan 11, 2024
58 checks passed
@jorgefilipecosta jorgefilipecosta deleted the add/bulk-actions-to-dataviews branch January 11, 2024 17:31
@github-actions github-actions bot added this to the Gutenberg 17.6 milestone Jan 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] DataViews Work surrounding upgrading and evolving views in the site editor and beyond [Type] Experimental Experimental feature or API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants