• 
      

    Modernize the UI and improve state for the API Tokens view.

    Review Request #15345 — Created Sept. 25, 2026 and updated

    Information

    Review Board
    release-9.x

    Reviewers

    The policy selection button is now using a standard Ink MenuButton,
    instead of the flat list of radio buttons with an embedded link. This is
    basically the same structure except that the "Custom" radio
    button/editor link has been replaced with a standard "Custom policy..."
    menu item at the bottom. Instead of a radio selection there, the menu
    button label will just indicate that Custom is chosen.

    The button is sized to provide enough room for the longest policy name
    in the menu. This prevents the button from resizing when changing
    policies.

    During save, the menu button will now be set to a busy state. The
    existing spinner is still shown, which kind of lasts a bit longer than
    the busy state and provides the same feedback all edits provide.

    The previous custom policy is remembered during the page's session. This
    allows the user to go from Custom to (say) Read-Only and then back
    without losing the Custom policy, which was an issue before.

    Some of the layout has been fixed to be less squashed together and to
    fix wrapping issues on mobile.

    Tested switching policies on several tokens.

    Tested going between new custom policies and built-in policies and
    back, verifying the custom policies weren't lost.

    Summary ID
    Modernize the UI and improve state for the API Tokens view.
    The policy selection button is now using a standard Ink MenuButton, instead of the flat list of radio buttons with an embedded link. This is basically the same structure except that the "Custom" radio button/editor link has been replaced with a standard "Custom policy..." menu item at the bottom. Instead of a radio selection there, the menu button label will just indicate that Custom is chosen. The button is sized to provide enough room for the longest policy name in the menu. This prevents the button from resizing when changing policies. During save, the menu button will now be set to a busy state. The existing spinner is still shown, which kind of lasts a bit longer than the busy state and provides the same feedback all edits provide. The previous custom policy is remembered during the page's session. This allows the user to go from Custom to (say) Read-Only and then back without losing the Custom policy, which was an issue before. Some of the layout has been fixed to be less squashed together and to fix wrapping issues on mobile.
    1332f9d292d6fdbfd4dde096e8a2a65975b79a96

    Description From Last Updated

    We should have tests for the new model state logic (setPolicyType(), saveCustomPolicy(), the #lastCustomPolicy round-trip, and rollback in savePolicy() should …

    david david

    policyType is only set to "custom" in initialize() and saveCustomPolicy(), both of which set this.#lastCustomPolicy. So this block seems redundant.

    david david

    Before, the policy editor would load this.model.get('policy'), so a token set to read-only would open the editor starting with a …

    david david

    typo: will shown -> will show

    david david

    This is only including the built-in labels, and not "Custom". While "Custom" in English is shorter than the built-in names, …

    david david

    typo: max width -> min width

    david david

    In ink, the busy state doesn't stop the menu from opening. We should probably set disabled alongside busy.

    david david
    Checks run (2 succeeded)
    flake8 passed.
    JSHint passed.
    david
    1. 
        
    2. Show all issues

      We should have tests for the new model state logic (setPolicyType(), saveCustomPolicy(), the #lastCustomPolicy round-trip, and rollback in savePolicy() should all be pretty easy to check)

    3. reviewboard/static/rb/js/accountPrefsPage/views/apiTokensView.ts (Diff revision 1)
       
       
       
       
       
       
       
       
      Show all issues

      policyType is only set to "custom" in initialize() and saveCustomPolicy(), both of which set this.#lastCustomPolicy. So this block seems redundant.

    4. Show all issues

      Before, the policy editor would load this.model.get('policy'), so a token set to read-only would open the editor starting with a read-only policy. Now it opens defaultPolicies.custom unless there was an earlier custom policy. Perhaps intentional, but if not, we should fall back to this.get('policy') before the default.

    5. Show all issues

      typo: will shown -> will show

    6. Show all issues

      This is only including the built-in labels, and not "Custom". While "Custom" in English is shorter than the built-in names, it won't necessarily be if we translate it.

      Can we initialize this to this.model.collection.policiesMap[POLICY_CUSTOM].name.length?

    7. Show all issues

      typo: max width -> min width

    8. Show all issues

      In ink, the busy state doesn't stop the menu from opening. We should probably set disabled alongside busy.

    9.