• 
      

    Give action templates more control over presentation and attributes.

    Review Request #14701 — Created Nov. 19, 2025 and submitted

    Information

    Review Board
    release-7.1.x

    Reviewers

    Action templates all inherit from action_base.html, which has two
    modes:

    1. Presenting top-level actions, which have a rb-c-actions__action
      container with an ID, visibility attributes, and more.

    2. Presenting inner actions, which don't have a container but do manage
      an ID and visibility attributes.

    There was no control over that container element in templates, and the
    attribute and visibility management was a bit all over the place. Any
    child of a group was invisible by default, which is really only
    appropriate for the default style of non-Ink menu item.

    The old template made it a real challenge to create maintainable
    actions, and was impacting the new sidebar action support, so it's been
    reworked.

    The new template defines all the following blocks for various bits of
    control:

    • action_is_visible: Controls visibility of the action. Can contain
      true or any other value for false. Defaults to the action's
      visible state.

    • action_has_container: Controls the presence of a default container
      element. Defaults to true if it's a top-level action.

    • action_container_tag: The HTML tag for the container element.
      Defaults to li.

    • action_container_css_class: Any additional CSS classes for the
      container element.

    • action_attrs: DOM attributes suitable for the inner element.
      Defaults to including an ID and visibility attributes if
      action_has_container=False.

    • action_container_attrs: DOM attributes suitable for the container
      element. Defaults to including an ID and visibility attributes if
      action_has_container=True.

    • action_container_role: The role for the container element. Defaults
      to presentation.

    • action_container_start: The start tag for the container element.

    • action_container_end: The end tag for the container element.

    • action_content: The content of the action.

    There are some structural changes that are important for consistency
    with flexible rendering:

    1. Action IDs are now always set for the inner element, and not the
      container element. This provides consistency. Before, it was
      dependent on where the action was rendered.

    2. Because of that, actions should now be wrapped in one element,
      regardless of a container, so it may have an ID associated. The menu
      action, for instance, now has an inner wrapper element for the ID
      with a label.

    3. Visibility is still on the container action for top-level actions,
      and the inner element for inner actions. The JavaScript still manages
      this properly. Actions are no longer hidden by default if they're
      inside another group.

    4. The visibility changes uncovered a bug in menu items where, due
      to being directly parented to the rb-c-actions__action container
      element of the parent menu, they fetched the wrong visibility
      element. Since they're not intended to be shown (menus get rebuilt
      with their information), we now wrap them in a hidden div so they
      never display.

    The menu template is adapted to support the new functionality and to
    cover the use cases we were special-casing everywhere. The custom
    Archive and Account menus have been moved over to use the improved
    template. This all needed to be done in the same change due to the
    impact on these templates.

    This change requires the new changes up for review in Djblets 5.3 for
    {% definevar as_type= %}.

    Tested the appearance and interactivity of all actions, with close
    attention paid to the various menu actions.

    Tested new in-progress action renderers for sidebars.

    Unit tests pass.

    Summary ID
    Give action templates more control over presentation and attributes.
    Action templates all inherit from `action_base.html`, which has two modes: 1. Presenting top-level actions, which have a `rb-c-actions__action` container with an ID, visibility attributes, and more. 2. Presenting inner actions, which don't have a container but do manage an ID and visibility attributes. There was no control over that container element in templates, and the attribute and visibility management was a bit all over the place. Any child of a group was invisible by default, which is really only appropriate for the default style of non-Ink menu item. The old template made it a real challenge to create maintainable actions, and was impacting the new sidebar action support, so it's been reworked. The new template defines all the following blocks for various bits of control: * `action_is_visible`: Controls visibility of the action. Can contain `true` or any other value for `false`. Defaults to the action's `visible` state. * `action_has_container`: Controls the presence of a default container element. Defaults to `true` if it's a top-level action. * `action_container_tag`: The HTML tag for the container element. Defaults to `li`. * `action_container_css_class`: Any additional CSS classes for the container element. * `action_attrs`: DOM attributes suitable for the inner element. Defaults to including an ID and visibility attributes if `action_has_container=False`. * `action_container_attrs`: DOM attributes suitable for the container element. Defaults to including an ID and visibility attributes if `action_has_container=True`. * `action_container_role`: The role for the container element. Defaults to `presentation`. * `action_container_start`: The start tag for the container element. * `action_container_end`: The end tag for the container element. * `action_content`: The content of the action. There are some structural changes that are important for consistency with flexible rendering: 1. Action IDs are now always set for the inner element, and not the container element. This provides consistency. Before, it was dependent on where the action was rendered. 2. Because of that, actions should now be wrapped in one element, regardless of a container, so it may have an ID associated. The menu action, for instance, now has an inner wrapper element for the ID with a label. 3. Visibility is still on the container action for top-level actions, and the inner element for inner actions. The JavaScript still manages this properly. Actions are no longer hidden by default if they're inside another group. 4. The visibility changes uncovered a bug in menu items where, due to being directly parented to the `rb-c-actions__action` container element of the parent menu, they fetched the wrong visibility element. Since they're not intended to be shown (menus get rebuilt with their information), we now wrap them in a hidden div so they never display. The menu template is adapted to support the new functionality and to cover the use cases we were special-casing everywhere. The custom Archive and Account menus have been moved over to use the improved template. This all needed to be done in the same change due to the impact on these templates. This change requires the new changes up for review in Djblets 5.3 for `{% definevar as_type= %}`.
    e4d4c92ede1689dc100bc9c305400d1d83f73bfd
    Description From Last Updated

    In your description, the explanation for action_container_role says "Defaults" at the end with no finish.

    david david

    In your description, "There are some couple structural changes..."

    david david

    In your description, item 4: "... uncovered a bug in menu items where. Due to being..."

    david david

    It might be nice to have a big comment at the top of this that lists out the blocks that …

    david david

    Browsers ignore role="presentation" on focusable elements like <a> tags.

    david david

    Can we use a CSS rule for div[hidden] to do this, instead of needing the inline style attribute? This probably …

    david david

    Nit but we could just make a variable for placement.parent_id is not None and then give has_parent the value and …

    maubin maubin
    david
    1. 
        
    2. Show all issues

      In your description, the explanation for action_container_role says "Defaults" at the end with no finish.

    3. Show all issues

      In your description, "There are some couple structural changes..."

    4. Show all issues

      In your description, item 4: "... uncovered a bug in menu items where. Due to being..."

    5. Show all issues

      It might be nice to have a big comment at the top of this that lists out the blocks that can be defined in templates that extend this (basically what you have in your commit message).

    6. Show all issues

      Browsers ignore role="presentation" on focusable elements like <a> tags.

      1. We had this before, and I think it's correct. This gets consumed by an Ink Menu wrapper, which sets up a parent element that manages its own events. This particular element just ends up wrapping a label (visible in the accessibility tree) and icon (presentation only). The parent menu has the events and state from Ink, indicating it can be opened and clicked, and that it controls menu contents. So this element is indeed presentation-only.

    7. Show all issues

      Can we use a CSS rule for div[hidden] to do this, instead of needing the inline style attribute?

      This probably also needs aria-hidden="true"

      1. aria-hidden="true" is implied by hidden and by display: none, according to MDN.

        I want to play with the hidden/display: none later. Originally, back when I was modifying this for Quick Access, I tried moving entirely to hidden, but something kept it visible at some point, or something. Been one of these rabbit holes to dig back into, but not now. This change is invasive enough as it is.

    8. 
        
    chipx86
    chipx86
    david
    1. Ship It!
    2. 
        
    maubin
    1. 
        
    2. reviewboard/actions/renderers.py (Diff revision 3)
       
       
       
      Show all issues

      Nit but we could just make a variable for placement.parent_id is not None and then give has_parent the value and is_toplevel the opposite of the value.

      I wonder if we should even have two separate context variables for this, if they're always just going to be the opposite of eachother? With the rewrites we don't seem to use has_parent anywhere anymore.

      1. Good points. has_parent is probably what we'd ideally have (we'd need to retain for backwards-compatibility -- we actually have a legacy action hook that has legacy rendering that uses this currently), but is_toplevel lets us cheaply do a True/False in a particular template variable. Django doesn't have a {{...|not}} which is a bit annoying. It's cheap enough to keep both, cheaper than going another route to inverse in the templates.

      2. Sounds good, let's keep both.

    3. 
        
    chipx86
    Review request changed
    Status:
    Completed
    Change Summary:
    Pushed to release-7.1.x (0551145)