Add default renderers for group actions.

Review Request #14700 — Created Nov. 18, 2025 and submitted

Information

Review Board
release-7.1.x

Reviewers

Attachment points and groups both support specifying default renderers
for any actions nested within. This applied to both standard actions and
group actions, which would do the wrong thing for group actions, and
necessitated that group actions always specify their own renderers.

These can now specify the default renderer for any group actions. With
this, an attachment point for a menubar could specify that all group
actions are rendered as menus, and groups in sidebars are rendered as
subsections, as a couple of examples.

As an internal optimization, actions now have an is_action_group
boolean property, which differentiates between an action and an action
group. This avoids the more costly isinstance checks that'd otherwise
need to be done multiple times per action render.

I also noted cases where fallback renderers weren't being used, and
where an detailed menu item action failed to render correctly with an
action lacking an icon. These have been fixed.

Unit tests pass.

Tested that existing actions work as expected.

Tested along with the upcoming addition of sidebar renderers.

Summary ID
Add default renderers for group actions.
Attachment points and groups both support specifying default renderers for any actions nested within. This applied to both standard actions and group actions, which would do the wrong thing for group actions, and necessitated that group actions always specify their own renderers. These can now specify the default renderer for any group actions. With this, an attachment point for a menubar could specify that all group actions are rendered as menus, and groups in sidebars are rendered as subsections, as a couple of examples. Group renderers can assign a special value of "self" for subgroup renderers, which ensures the same group renderer is used for its children. Group renderers are also now responsible for rendering their children, moving much of the logic from `{% child_actions_html %}` into a new `BaseActionGroupRenderer.render_children()` method. As an internal optimization, actions now have an `_is_action_group` boolean property, which differentiates between an action and an action group. This avoids the more costly `isinstance` checks that'd otherwise need to be done multiple times per action render. I also noted cases where fallback renderers weren't being used, and where an detailed menu item action failed to render correctly with an action lacking an icon. These have been fixed.
6c921413768587ed07e84713f9c062a466fa70d6
Description From Last Updated

Just noticed that this class docstring is missing "Version Added"

daviddavid

Given that this is not public API, should we call it _is_action_group?

daviddavid

Can we add the "Instance variables" comment in here?

daviddavid

'reviewboard.actions.renderers.ActionSubgroupRendererType' imported but unused Column: 5 Error code: F401

reviewbotreviewbot

line too long (89 > 79 characters) Column: 80 Error code: E501

reviewbotreviewbot

line too long (95 > 79 characters) Column: 80 Error code: E501

reviewbotreviewbot

continuation line under-indented for visual indent Column: 39 Error code: E128

reviewbotreviewbot

'logging' imported but unused Column: 1 Error code: F401

reviewbotreviewbot

Can we add a comment here explaining this case, something like "This attachment point does not allow for child actions."

maubinmaubin

This is missing its docstring.

maubinmaubin

Seems like these should probably both be logger.error. I don't think we need the traceback in the second case.

daviddavid
david
  1. 
      
  2. reviewboard/actions/base.py (Diff revision 1)
     
     
    Show all issues

    Just noticed that this class docstring is missing "Version Added"

  3. reviewboard/actions/base.py (Diff revision 1)
     
     
     
     
     
     
     
     
     
     
     
    Show all issues

    Given that this is not public API, should we call it _is_action_group?

  4. reviewboard/actions/renderers.py (Diff revision 1)
     
     
    Show all issues

    Can we add the "Instance variables" comment in here?

    1. These are all class variables. I'll type them as such. Initially I had intended to let these be set as instance variables, but I've changed that design.

  5. 
      
chipx86
Review request changed
Change Summary:
  • Added BaseActionGroupRenderer.render_children() to handle children rendering, recursively. This addresses issues with renderer selection from the previous code, and can recurse.
  • Added support for 'self' as a value for subgroup renderers, so a group can easily recurse. The template tag is now a thin wrapper around this.
  • Renamed is_action_group to _is_action_group.
  • default_item_renderer_cls and default_subgroup_renderer_cls are now ClassVars.
  • Added a missing Version Added.
Commits:
Summary ID
Add default renderers for group actions.
Attachment points and groups both support specifying default renderers for any actions nested within. This applied to both standard actions and group actions, which would do the wrong thing for group actions, and necessitated that group actions always specify their own renderers. These can now specify the default renderer for any group actions. With this, an attachment point for a menubar could specify that all group actions are rendered as menus, and groups in sidebars are rendered as subsections, as a couple of examples. As an internal optimization, actions now have an `is_action_group` boolean property, which differentiates between an action and an action group. This avoids the more costly `isinstance` checks that'd otherwise need to be done multiple times per action render. I also noted cases where fallback renderers weren't being used, and where an detailed menu item action failed to render correctly with an action lacking an icon. These have been fixed.
7a279edeaf0730e8c028399fa73ffe61c3f927d3
Add default renderers for group actions.
Attachment points and groups both support specifying default renderers for any actions nested within. This applied to both standard actions and group actions, which would do the wrong thing for group actions, and necessitated that group actions always specify their own renderers. These can now specify the default renderer for any group actions. With this, an attachment point for a menubar could specify that all group actions are rendered as menus, and groups in sidebars are rendered as subsections, as a couple of examples. Group renderers can assign a special value of "self" for subgroup renderers, which ensures the same group renderer is used for its children. Group renderers are also now responsible for rendering their children, moving much of the logic from `{% child_actions_html %}` into a new `BaseActionGroupRenderer.render_children()` method. As an internal optimization, actions now have an `_is_action_group` boolean property, which differentiates between an action and an action group. This avoids the more costly `isinstance` checks that'd otherwise need to be done multiple times per action render. I also noted cases where fallback renderers weren't being used, and where an detailed menu item action failed to render correctly with an action lacking an icon. These have been fixed.
24cb0636eac8536774cd08e3ec2378e49e02a9b4

Checks run (1 failed, 1 succeeded)

flake8 failed.
JSHint passed.

flake8

chipx86
david
  1. 
      
  2. reviewboard/actions/renderers.py (Diff revision 3)
     
     
     
     
     
     
     
     
     
     
     
     
     
    Show all issues

    Seems like these should probably both be logger.error. I don't think we need the traceback in the second case.

    1. Not sure what happened there.

  3. 
      
maubin
  1. 
      
  2. reviewboard/actions/base.py (Diff revision 3)
     
     
     
     
    Show all issues

    Can we add a comment here explaining this case, something like "This attachment point does not allow for child actions."

  3. reviewboard/actions/renderers.py (Diff revision 3)
     
     
    Show all issues

    This is missing its docstring.

  4. 
      
chipx86
maubin
  1. Ship It!
  2. 
      
chipx86
Review request changed
Status:
Completed
Change Summary:
Pushed to release-7.1.x (1f1f6e8)