@@ -332,6 +332,157 @@ contents on each row. If you prefer to display all the actions *inline*
332332 }
333333 }
334334
335+ Grouping Actions
336+ ----------------
337+
338+ In addition to individual actions, you can group multiple related actions into
339+ a single button. This is useful when you have many actions and want to organize
340+ them better or save space in the interface. Use the ``ActionGroup `` class
341+ to create these grouped actions::
342+
343+ use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
344+ use EasyCorp\Bundle\EasyAdminBundle\Config\ActionGroup;
345+ use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
346+ use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
347+
348+ public function configureActions(Actions $actions): Actions
349+ {
350+ $publishActions = ActionGroup::new('publish', 'Publish')
351+ ->addAction(Action::new('publishNow', 'Publish Now')->linkToCrudAction('...'))
352+ ->addAction(Action::new('schedule', 'Schedule...')->linkToCrudAction('...'))
353+ ->addAction(Action::new('publishDraft', 'Save as Draft')->linkToCrudAction('...'));
354+
355+ return $actions
356+ // ...
357+ ->add(Crud::PAGE_EDIT, $publishActions)
358+ ;
359+ }
360+
361+ This is how the action group looks in practice:
362+
363+ .. image :: images/easyadmin-action-group.gif
364+ :alt: An action group that includes three different actions into a single button
365+
366+ Similar to standalone actions, on the index page there are two types of action
367+ groups: those associated with each entity and those associated with the entire page::
368+
369+ public function configureActions(Actions $actions): Actions
370+ {
371+ $createActions = ActionGroup::new('create')
372+ ->createAsGlobalActionGroup()
373+ ->addAction(Action::new('new', 'Create Post')->linkToCrudAction('...'))
374+ ->addAction(Action::new('draft', 'Draft Post')->linkToCrudAction('...'))
375+ ->addAction(Action::new('template', 'Create from Template')->linkToCrudAction('...'));
376+
377+ $sendActions = ActionGroup::new('send', 'Send ...')
378+ ->addAction(Action::new('sendEmail', 'Send by Email')->linkToCrudAction('...'))
379+ ->addAction(Action::new('sendSlack', 'Send to Slack')->linkToCrudAction('...'))
380+ ->addAction(Action::new('sendTelegram', 'Send via Telegram')->linkToCrudAction('...'));
381+
382+ return $actions
383+ // ...
384+ ->add(Crud::PAGE_INDEX, $createActions)
385+ ->add(Crud::PAGE_INDEX, $sendActions)
386+ ;
387+ }
388+
389+ The ``createAsGlobalActionGroup() `` method creates an action group associated
390+ with the entire page rather than any specific entity. It appears like the image
391+ shown above for action groups.
392+
393+ When not using the ``createAsGlobalActionGroup() `` method on the index page, the
394+ action group is displayed as a nested dropdown on each entity row (see the image
395+ in the next section below).
396+
397+ Split Button Dropdowns
398+ ~~~~~~~~~~~~~~~~~~~~~~
399+
400+ If one of the grouped actions is more common than the others, you can render the
401+ group as a "split button". This displays the **main action ** as a clickable button,
402+ with the other actions available in the dropdown::
403+
404+ $publishActions = ActionGroup::new('publish', 'Publish')
405+ ->addMainAction(Action::new('publishNow', 'Publish Now')->linkToCrudAction('...'))
406+ ->addAction(Action::new('schedule', 'Schedule...')->linkToCrudAction('...'))
407+ ->addAction(Action::new('publishDraft', 'Save as Draft')->linkToCrudAction('...'));
408+
409+ Now, the action group will look as follows:
410+
411+ .. image :: images/easyadmin-action-group-split-button.gif
412+ :alt: An action group that defines a main action and a list of secondary actions
413+
414+ On the index page, if the action group is associated with each entity, it's
415+ displayed as a dropdown. In the following image, the first action group is a
416+ simple dropdown because it doesn't define a main action. The second action
417+ group is a split dropdown, where the main action is a clickable element and the
418+ remaining actions appear when hovering over the submenu marker:
419+
420+ .. image :: images/easyadmin-action-group-entity-dropdown.gif
421+ :alt: An action group inside an entity dropdown. The second group defines a main action.
422+
423+ Headers and Dividers
424+ ~~~~~~~~~~~~~~~~~~~~
425+
426+ For better organization, especially with many actions in a dropdown, you can add
427+ headers and dividers to create logical groups::
428+
429+ $actionsGroup = ActionGroup::new('actions', 'Actions', 'fa fa-cog')
430+ ->addHeader('Quick Actions')
431+ ->addAction(Action::new('approve', 'Approve')->linkToCrudAction('approve'))
432+ ->addAction(Action::new('reject', 'Reject')->linkToCrudAction('reject'))
433+ ->addDivider()
434+ ->addHeader('Advanced')
435+ ->addAction(Action::new('archive', 'Archive')->linkToCrudAction('archive'))
436+ ->addAction(Action::new('delete', 'Delete')->linkToCrudAction('delete')
437+ ->addCssClass('text-danger'));
438+
439+ Headers help users understand the purpose of each group, while dividers provide
440+ visual separation between different sections.
441+
442+ Conditional Dropdown Display
443+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
444+
445+ Like regular actions, dropdowns can be displayed conditionally based on the
446+ entity state or user permissions::
447+
448+ $moderationGroup = ActionGroup::new('moderation', 'Moderation')
449+ // the callable receives the current entity instance or null (in the index page)
450+ ->displayIf(static function ($entity) {
451+ return null !== $entity && 'pending' === $entity->getStatus();
452+ })
453+ ->addAction(Action::new('approve', 'Approve')->linkToCrudAction('approve'))
454+ ->addAction(Action::new('reject', 'Reject')->linkToCrudAction('reject'));
455+
456+ The dropdown will only appear when the condition is met. Individual actions
457+ within the dropdown can also have their own display conditions.
458+
459+ Customizing Dropdown Appearance
460+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
461+
462+ Dropdowns support the same customization options as regular actions for styling
463+ and HTML attributes::
464+
465+ $customGroup = ActionGroup::new('custom', 'Options')
466+ // use only an icon, no label
467+ ->setLabel(false)
468+ ->setIcon('fa fa-ellipsis-v')
469+
470+ // create different variants of action groups
471+ ->asPrimaryActionGroup()
472+ ->asDefaultActionGroup()
473+ ->asSuccessActionGroup()
474+ ->asWarningActionGroup()
475+ ->asDangerActionGroup()
476+
477+ // add custom CSS classes
478+ ->addCssClass('my-custom-dropdown')
479+
480+ // add HTML attributes
481+ ->setHtmlAttributes(['data-foo' => 'bar']);
482+
483+ You can also customize individual actions within the dropdown using the standard
484+ action configuration methods.
485+
335486.. _actions-custom :
336487
337488Adding Custom Actions
@@ -414,6 +565,14 @@ that will represent the action::
414565 // useful when customizing a built-in action, which already has CSS classes)
415566 ->addCssClass('some-custom-css-class text-danger')
416567
568+ This is how the different button style variants look in light and dark mode:
569+
570+ .. image :: images/easyadmin-buttons-light-mode.gif
571+ :alt: EasyAdmin button variants in light mode
572+
573+ .. image :: images/easyadmin-buttons-dark-mode.gif
574+ :alt: EasyAdmin button variants in dark mode
575+
417576.. note ::
418577
419578 When using ``setCssClass() `` or ``addCssClass() `` methods, the action loses
0 commit comments