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)