• 
      

    Add new dedicated classes for handling action rendering.

    Review Request #14659 — Created Oct. 29, 2025 and submitted

    Information

    Review Board
    release-7.1.x

    Reviewers

    When actions were first built, we had a one-to-one mapping of action
    class to UI representation. This changed with the introduction of the
    Quick Access actions, which required duplicating and specializing
    actions.

    We only had basic forms of menu and menu item actions at that time, but
    as we adopt actions for more parts of the UI (including page navigation
    soon) that can show up in multiple places, we've needed a more flexible
    approach.

    Now, actions provide the metadata and, client-side, activation logic
    (implemented in a former change), and rendering is handled by a separate
    set of renderer classes. These are responsible for taking a registered
    action and turning it into a UI representation server-side. These may be
    buttons, menus, menu items, sidebar items, or something specialized for
    any part of the UI.

    Renderers don't need to be registered anywhere. They can be created and
    then set as either the default for an action, or passed explicitly
    during action rendering, which will yield new HTML/JavaScript for that
    action's view.

    Compatibility with existing action-driven rendering is still provided,
    but deprecated and will be removed in Review Board 9. As of this change,
    such actions are still using the legacy behavior, in part to aid in
    testing this compatibility. These will be updated in another change.

    This is a precursor to change that will provide defaults for different
    areas on a page, which will make it even easier to reuse actions across
    a page.

    Unit tests passed.

    Tested all actions used in the UI, making sure they rendered and
    activated correctly.

    Summary ID
    Add new dedicated classes for handling action rendering.
    When actions were first built, we had a one-to-one mapping of action class to UI representation. This changed with the introduction of the Quick Access actions, which required duplicating and specializing actions. We only had basic forms of menu and menu item actions at that time, but as we adopt actions for more parts of the UI (including page navigation soon) that can show up in multiple places, we've needed a more flexible approach. Now, actions provide the metadata and, client-side, activation logic (implemented in a former change), and rendering is handled by a separate set of renderer classes. These are responsible for taking a registered action and turning it into a UI representation server-side. These may be buttons, menus, menu items, sidebar items, or something specialized for any part of the UI. Renderers don't need to be registered anywhere. They can be created and then set as either the default for an action, or passed explicitly during action rendering, which will yield new HTML/JavaScript for that action's view. Compatibility with existing action-driven rendering is still provided, but deprecated and will be removed in Review Board 9. As of this change, such actions are still using the legacy behavior, in part to aid in testing this compatibility. These will be updated in another change. This is a precursor to change that will provide defaults for different areas on a page, which will make it even easier to reuse actions across a page.
    e48a6ac154ef9ea95b016d774eb921d8b0f87df0

    Description From Last Updated

    Typo: renderes

    maubinmaubin

    Typo: renderes -> renderers

    daviddavid

    I wrote a similar message using the class name recently, but I used self.__class__.__name__. Is one better than the other?

    maubinmaubin

    Just to be a little more defensive, can we do if not issubclass(renderer_cls, BaseActionRenderer)?

    daviddavid

    Same here.

    daviddavid

    Can you add a raises section in the docstring for this.

    maubinmaubin

    Can we alphabetize these.

    maubinmaubin

    Should we annotate these as ClassVar[]?

    daviddavid

    Shouldn't this be :py:meth instead of :js:meth?

    maubinmaubin

    We shouldn't need to repeat the typing on this.

    daviddavid

    We shouldn't need to repeat the typing on this.

    daviddavid

    TypeError is probably more appropriate. This is a developer-facing error that doesn't need localization.

    daviddavid

    'django.utils.translation.gettext as _' imported but unused Column: 1 Error code: F401

    reviewbotreviewbot
    chipx86
    chipx86
    maubin
    1. Looks solid!

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

      Typo: renderes

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

      I wrote a similar message using the class name recently, but I used self.__class__.__name__. Is one better than the other?

      1. In this particular case, no. It used to matter more in Python 2. That said, type() is probably usually the more correct answer (but in practice either is generally fine).

        type() reaches into the Python type system rather than doing an attribute lookup. You can actually override __class__, since it goes through the standard attribute lookup path. But even if you do, type() will give the right answer. For example:

        >>> class A:
        ...   __class__ = 'Foo'
        ...
        >>> a = A()
        >>> a.__class__
        'Foo'
        >>> type(a)
        <class '__main__.A'>
        
    4. reviewboard/actions/base.py (Diff revision 3)
       
       
      Show all issues

      Can you add a raises section in the docstring for this.

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

      Can we alphabetize these.

      1. Don't worry about this for now. This whole class is going away. This change here is just temporary.

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

      Shouldn't this be :py:meth instead of :js:meth?

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

      Typo: renderes -> renderers

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

      Just to be a little more defensive, can we do if not issubclass(renderer_cls, BaseActionRenderer)?

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

      Same here.

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

      Should we annotate these as ClassVar[]?

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

      We shouldn't need to repeat the typing on this.

      1. We do. If we don't, subclasses are restricted to MenuItemActionRenderer or a subclass of it. I hit this with the Quick Access implementation initially (we had to redefine the types) and hit this again with this change.

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

      We shouldn't need to repeat the typing on this.

    8. Show all issues

      TypeError is probably more appropriate.

      This is a developer-facing error that doesn't need localization.

    9. 
        
    chipx86
    Review request changed
    Change Summary:
    • Fixed some doc issues.
    • Introduced a new MissingActionRendererError class and made use of it.
    • Made class attributes ClassVars.
    • Added issubclass checks to ensure a proper renderer is set.
    Commits:
    Summary ID
    Add new dedicated classes for handling action rendering.
    When actions were first built, we had a one-to-one mapping of action class to UI representation. This changed with the introduction of the Quick Access actions, which required duplicating and specializing actions. We only had basic forms of menu and menu item actions at that time, but as we adopt actions for more parts of the UI (including page navigation soon) that can show up in multiple places, we've needed a more flexible approach. Now, actions provide the metadata and, client-side, activation logic (implemented in a former change), and rendering is handled by a separate set of renderer classes. These are responsible for taking a registered action and turning it into a UI representation server-side. These may be buttons, menus, menu items, sidebar items, or something specialized for any part of the UI. Renderers don't need to be registered anywhere. They can be created and then set as either the default for an action, or passed explicitly during action rendering, which will yield new HTML/JavaScript for that action's view. Compatibility with existing action-driven rendering is still provided, but deprecated and will be removed in Review Board 9. As of this change, such actions are still using the legacy behavior, in part to aid in testing this compatibility. These will be updated in another change. This is a precursor to change that will provide defaults for different areas on a page, which will make it even easier to reuse actions across a page.
    be7b9ebac56f069961667eaa280152339068b25a
    Add new dedicated classes for handling action rendering.
    When actions were first built, we had a one-to-one mapping of action class to UI representation. This changed with the introduction of the Quick Access actions, which required duplicating and specializing actions. We only had basic forms of menu and menu item actions at that time, but as we adopt actions for more parts of the UI (including page navigation soon) that can show up in multiple places, we've needed a more flexible approach. Now, actions provide the metadata and, client-side, activation logic (implemented in a former change), and rendering is handled by a separate set of renderer classes. These are responsible for taking a registered action and turning it into a UI representation server-side. These may be buttons, menus, menu items, sidebar items, or something specialized for any part of the UI. Renderers don't need to be registered anywhere. They can be created and then set as either the default for an action, or passed explicitly during action rendering, which will yield new HTML/JavaScript for that action's view. Compatibility with existing action-driven rendering is still provided, but deprecated and will be removed in Review Board 9. As of this change, such actions are still using the legacy behavior, in part to aid in testing this compatibility. These will be updated in another change. This is a precursor to change that will provide defaults for different areas on a page, which will make it even easier to reuse actions across a page.
    5782c87f553f6664f3e7597cb008dae1e3b2d916

    Checks run (1 failed, 1 succeeded)

    flake8 failed.
    JSHint passed.

    flake8

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