• 
      
    Fish Trophy

    chipx86 got a fish trophy!

    Fish Trophy

    Move action activation and state management into the action models.

    Review Request #14641 — Created Oct. 18, 2025 and submitted

    Information

    Review Board
    release-7.1.x

    Reviewers

    Actions didn't have a standard way to perform an activation of the
    action. The menu item action views had an activate() method tied to a
    click handler, and subclasses implemented that, but this wasn't a
    capability of ActionView. Quick Access actions happened to get the
    same activation support by inheriting the same view for menu items, even
    though buttons were used for display (creating a potential future
    issue by themselves).

    As part of the work to centralize actions, Action now has an
    activate() method, which performs the operation backed by the action.
    Although these are models, this method is allowed to contain or call
    UI/view code.

    ActionView has been updated to have an official activate() method
    for compatibility, which defaults to calling model.activate().
    Subclasses can always override this to put in logic between the parent
    class's call and the model's activation logic.

    ActionView has also been updated to rely more on Action for
    visibility management (newly added for Quick Access actions in 7.1),
    so all views for an action will behave the same way.

    The existing action views have largely been replaced with models, which
    in upcoming changes will be better utilized for both standard and Quick
    Access actions. The old views have been removed, and probably aren't
    worth retaining for any kind of API compatibility.

    Unit tests pass.

    Tested every single action, making sure states were updated,
    visibility was reflected, and actions were activated correctly.

    Summary ID
    Move action activation and state management into the action models.
    Actions didn't have a standard way to perform an activation of the action. The menu item action views had an `activate()` method tied to a click handler, and subclasses implemented that, but this wasn't a capability of `ActionView`. Quick Access actions happened to get the same activation support by inheriting the same view for menu items, even though buttons were used for display (creating a potential future issue by themselves). As part of the work to centralize actions, `Action` now has an `activate()` method, which performs the operation backed by the action. Although these are models, this method is allowed to contain or call UI/view code. `ActionView` has been updated to have an official `activate()` method for compatibility, which defaults to calling `model.activate()`. Subclasses can always override this to put in logic between the parent class's call and the model's activation logic. `ActionView` has also been updated to rely more on `Action` for visibility management (newly added for Quick Access actions in 7.1), so all views for an action will behave the same way. The existing action views have largely been replaced with models, which in upcoming changes will be better utilized for both standard and Quick Access actions. The old views have been removed, and probably aren't worth retaining for any kind of API compatibility.
    1d6249e553fb942258a13d696db502316d9bb172
    Description From Last Updated

    This is missing a docstring, and maybe its better to have the assert be something like "<classname> must implement getLabelForVisibility".

    maubinmaubin

    This can be removed.

    maubinmaubin

    This can be removed.

    maubinmaubin

    Seems like leftover debug code.

    maubinmaubin

    Shouldn't we be triggering closeError on the reviewRequestEditor instance instead of on the action? I know in the previous code …

    maubinmaubin

    Do we want to explicitly list out the things exported here, in case we add additional things (i.e. attrs interfaces) …

    daviddavid

    Can you add a file-level comment at the top?

    daviddavid

    Given that this should never be called, can we make the method abstract?

    daviddavid

    Typo here: getLabels -> getLabel

    daviddavid

    This should be when there is an existing pending review.

    daviddavid

    Copy/pasto: Action view -> Action

    daviddavid

    Should be UpdateDiffActionView

    daviddavid

    So I think the old implementation might have been wrong to start with, but nothing is listening to "closeError" on …

    daviddavid

    Same here.

    daviddavid

    We also don't have any error handling here in case the promise fails. We probably should show whatever error and …

    daviddavid

    Some of our activate() methods are async, and some are not. I feel like we should standardize on all being …

    daviddavid

    Since some model implementations are async, I feel like we should make this async as well and do await this.model.activate()

    daviddavid

    Do we want a Version Changed here about this now being exported, and perhaps a note about how this is …

    daviddavid

    Let's make this async and do await this.#pendingReview.save().

    daviddavid
    chipx86
    maubin
    1. 
        
    2. Show all issues

      This is missing a docstring, and maybe its better to have the assert be something like "<classname> must implement getLabelForVisibility".

    3. Show all issues

      This can be removed.

    4. Show all issues

      This can be removed.

    5. Show all issues

      Seems like leftover debug code.

    6. Show all issues

      Shouldn't we be triggering closeError on the reviewRequestEditor instance instead of on the action? I know in the previous code we were triggering this event on the action model, but I don't see how this gets bubbled up to ReviewRequestEditor which is the thing that actually listens to closeError events.

      1. That is a very good point. Let me address that in its own change, since that's going to take some testing. I don't want to bury that in here.

      2. Sounds good.

    7. 
        
    chipx86
    maubin
    1. 
        
    2. 
        
    david
    1. 
        
    2. Show all issues

      Do we want to explicitly list out the things exported here, in case we add additional things (i.e. attrs interfaces) to this file later?

      1. My two cents is that we should be avoiding consumers (extensions, etc.) having to know our file structure. We namespace our objects well, and I think anything worth exporting should be made available via the base packages. That's a large conversation though.

    3. Show all issues

      Can you add a file-level comment at the top?

    4. Show all issues

      Given that this should never be called, can we make the method abstract?

    5. Show all issues

      Typo here: getLabels -> getLabel

    6. Show all issues

      This should be when there is an existing pending review.

    7. Show all issues

      Copy/pasto: Action view -> Action

    8. Show all issues

      Should be UpdateDiffActionView

    9. Show all issues

      So I think the old implementation might have been wrong to start with, but nothing is listening to "closeError" on this. I think we want to be doing reviewRequesEditor.trigger('closeError', err.message) here?

      Or perhaps we want to think about more generic error handling across the board for actions?

      1. This is all being redone in a separate change that makes all this much, much nicer. Michelle pointed out the same problem.

    10. Show all issues

      Same here.

    11. Show all issues

      We also don't have any error handling here in case the promise fails. We probably should show whatever error and set the button to non-busy.

      1. A fix for this is included in the separate change.

    12. 
        
    chipx86
    david
    1. 
        
    2. Show all issues

      Some of our activate() methods are async, and some are not. I feel like we should standardize on all being async, starting with the base class definition here.

      1. I'm on board with this. Let me do it as a separate change, given how much code churn exists in follow-up changes at this point.

    3. Show all issues

      Since some model implementations are async, I feel like we should make this async as well and do await this.model.activate()

    4. reviewboard/static/rb/js/common/models/userSessionModel.ts (Diff revision 4)
       
       
       
       
       
       
       
       
       
      Show all issues

      Do we want a Version Changed here about this now being exported, and perhaps a note about how this is exported from this file but does not get exported all the way to the global namespace?

    5. reviewboard/static/rb/js/reviews/models/reviewRequestActionModels.ts (Diff revision 4)
       
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      Let's make this async and do await this.#pendingReview.save().

    6. 
        
    chipx86
    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 (9fa122d)