Skip to content

feat(reborn): replace tool permission selects with custom menu - #5769

Merged
think-in-universe merged 11 commits into
mainfrom
feat-custom-tools-select
Jul 8, 2026
Merged

think-in-universe merged 11 commits into
mainfrom
feat-custom-tools-select

Conversation

@italic-jinxin

@italic-jinxin italic-jinxin commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds a reusable WebUI v2 SelectMenu component with keyboard navigation, outside-click dismissal, selected-state styling, and accessible listbox semantics.
  • Replaces the Reborn Tools permission native browser selects with the custom menu while preserving existing permission state behavior.
  • Updates Tools Tab unit coverage and legacy tool-permissions E2E selectors/flow to exercise the custom menu instead of native select behavior.
image

Linked Issue

Closes #5770

Validation

  • node --test crates/ironclaw_webui_v2/static/js/design-system/select-menu.test.mjs crates/ironclaw_webui_v2/static/js/pages/settings/components/tools-tab.test.mjs
  • npm run build from crates/ironclaw_webui_v2/frontend
  • git diff --check
  • tests/e2e/.venv/bin/python -m py_compile tests/e2e/helpers.py tests/e2e/scenarios/test_reborn_webui_v2_legacy_tool_permissions.py
  • tests/e2e/.venv/bin/pytest --collect-only -q tests/e2e/scenarios/test_reborn_webui_v2_legacy_tool_permissions.py::test_reborn_legacy_tool_permission_menu_persists_after_reload

Security Impact

No. This only changes Reborn WebUI v2 presentation and client-side interaction for tool permission controls.

Database Impact

No schema or migration changes.

Blast Radius

Limited to the Reborn WebUI v2 Tools settings permission control, the shared static design-system select component, and related unit/E2E coverage.

Rollback Plan

Revert this PR to restore the previous native browser select controls for tool permissions.

@italic-jinxin italic-jinxin added size: XL 500+ changed lines risk: low Changes to docs, tests, or low-risk modules contributor: core 20+ merged PRs labels Jul 7, 2026
@ironloopai

ironloopai Bot commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

🔎 IronLoop Review Status

Head: 7bab4ce5c7215ff48bbb91bf8538bfb1e447c30a
Result: No reviewer jobs are scheduled yet.
Next: Run @ironloopai review to start reviewers.
Updated: 2026-07-08T16:00:29.218Z

Current reviewers:

Reviewer State Verdict Findings Last update
none Queued N/A No reviewer jobs scheduled yet. N/A
Reviewer summaries
Reviewer Detail
none No reviewer jobs scheduled yet.
Recent activity
Time Reviewer State Detail
N/A N/A Waiting No progress events recorded yet.
Available commands
  • @ironloopai help
  • @ironloopai agents
  • @ironloopai review
  • @ironloopai review --agent <agent-id-or-alias>
  • @ironloopai status
Run metadata

Admission: webhook accepted the request and IronLoop persisted review state before this projection.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 32269b81-fe99-4a49-851d-b8c93448c536

📥 Commits

Reviewing files that changed from the base of the PR and between 3470815 and 7bab4ce.

📒 Files selected for processing (2)
  • crates/ironclaw_webui_v2/frontend/src/design-system/select-menu.test.ts
  • crates/ironclaw_webui_v2/frontend/src/design-system/select-menu.tsx
💤 Files with no reviewable changes (2)
  • crates/ironclaw_webui_v2/frontend/src/design-system/select-menu.tsx
  • crates/ironclaw_webui_v2/frontend/src/design-system/select-menu.test.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added a new custom dropdown control for selecting options, with keyboard support, disabled-state handling, and clearer selected-option display.
    • Improved the Settings → Tools permission UI to use the new selection experience and keep the chosen setting after refresh.
  • Bug Fixes
    • Fixed permission changes so failed saves correctly revert the displayed value and show an error message.
    • Improved locked-tool handling so unavailable permissions are no longer shown as selectable controls.

Walkthrough

Adds a new SelectMenu React component with custom listbox behavior, ARIA wiring, keyboard/mouse interaction, and outside-click closing, plus a Vitest suite covering it. Updates E2E helpers and legacy tool-permission scenarios to interact via the menu instead of a native <select>.

Changes

SelectMenu rollout

Layer / File(s) Summary
SelectMenu component
crates/ironclaw_webui_v2/frontend/src/design-system/select-menu.tsx
New SelectMenu component with shared outside-click closing, keyboard navigation (Arrow/Home/End/Enter/Space/Escape/Tab), active/selected index derivation, safe root prop passthrough, and ARIA-wired trigger/listbox rendering with tone dots and check icon.
SelectMenu tests
crates/ironclaw_webui_v2/frontend/src/design-system/select-menu.test.ts
New Vitest suite using a mocked React VM harness covering closed render, selection via click/keyboard, reordering, Escape handling, focus restoration, shared document listener behavior, prop filtering, and disabled states.
E2E selector and scenario updates
tests/e2e/helpers.py, tests/e2e/reborn_coverage_tests.txt, tests/e2e/scenarios/test_reborn_webui_v2_legacy_tool_permissions.py
Adds settings_tool_permission selector, registers the renamed reload-persistence test in the coverage gate, and rewrites tool-permission E2E interactions/assertions to use the menu trigger instead of a <select>.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SettingsUI
  participant SelectMenuTrigger
  participant SelectMenuListbox
  participant PermissionAPI

  User->>SettingsUI: open Tools settings
  SettingsUI->>SelectMenuTrigger: render current permission label
  User->>SelectMenuTrigger: click / ArrowDown
  SelectMenuTrigger->>SelectMenuListbox: open listbox, set aria-expanded
  User->>SelectMenuListbox: select option (click/Enter)
  SelectMenuListbox->>SettingsUI: onChange(newPermission)
  SettingsUI->>PermissionAPI: save permission
  alt save succeeds
    PermissionAPI-->>SettingsUI: success
    SettingsUI->>SelectMenuTrigger: update label
  else save fails
    PermissionAPI-->>SettingsUI: error "Permission denied"
    SettingsUI->>SelectMenuTrigger: revert label, show alert
  end
Loading

Possibly related PRs

  • nearai/ironclaw#5375: Original addition of the legacy tool-permissions scenario/module and adjacent settings/tools UI coverage now updated for the menu/listbox UI.
  • nearai/ironclaw#5699: Introduced the "Save failed: Permission denied" alert behavior that this PR's updated E2E assertions verify against the new menu control.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title uses Conventional Commits and accurately summarizes the custom menu swap for Reborn tool permissions.
Description check ✅ Passed The description covers summary, linked issue, validation, security, database impact, blast radius, and rollback.
Linked Issues check ✅ Passed The changes replace native selects with a reusable dropdown and preserve keyboard, listbox, and persisted permission behavior.
Out of Scope Changes check ✅ Passed The diff stays within the new SelectMenu, Reborn permission wiring, and matching tests, with no unrelated scope added.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot removed the size: XL 500+ changed lines label Jul 7, 2026
@italic-jinxin

Copy link
Copy Markdown
Contributor Author

@claude review

@github-actions github-actions Bot added the size: L 200-499 changed lines label Jul 7, 2026
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5769 July 7, 2026 13:38 Destroyed
gemini-code-assist[bot]

This comment was marked as resolved.

@ironloopai ironloopai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ IronLoop Review: reviewer

Verdict: ✅ Approved
Findings: 0 blocking / 0 notes
Next: No reviewer action needed.
Head: c7fb8dad751a9f8456cb2f56d7ab8b3bc481068d

Run details

Status: Current
Needs human: no
Needs validation: no

**Inline candidates:** 0

Summary

No blocking correctness, security, or coverage issues found in the reviewed PR. The new select-menu behavior is covered by focused JS tests and the updated Reborn E2E manifest includes the persisted permission-menu scenario.

Findings

None.

Developer follow-up

After fixing this feedback:

  1. Push the fix to this PR branch.
  2. Re-run this reviewer with @ironloopai review --agent reviewer if you only changed this reviewer's findings.
  3. Re-run all reviewers with @ironloopai review when the fix may affect multiple areas.
  4. Use @ironloopai status to check queued/running/completed/stale/stalled state while reviewers run.

@claude

This comment was marked as resolved.

@italic-jinxin
italic-jinxin marked this pull request as ready for review July 7, 2026 13:43
@github-actions

github-actions Bot commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

Coverage ratchet

Ratchet mode: ENFORCING

RATCHET PASS: global
  observed: 85.16% (282153 / 331314 lines)
  floor:    85.3% (tolerance 0.5pp -> effective floor 84.8%)
  denominator: 331314 lines now vs 320188 at floor capture (+11126 lines, +3.47%) — not a material change

⚠️ 3 Reborn crate(s) have 0 int-tier coverage (target: 0) — ironclaw_prompt_envelope, ironclaw_scripts, ironclaw_skill_learning

Reborn integration-tier coverage

Line coverage (Reborn crates): 85.16% — 282153 / 331314 lines

Per-crate breakdown (65 crates, lowest-covered first)
Crate Line % Covered / Total
ironclaw_prompt_envelope 0% 0 / 88
ironclaw_scripts 0% 0 / 347
ironclaw_skill_learning 0% 0 / 61
ironclaw_wasm_sandbox_core 7.37% 7 / 95
ironclaw_runtime_policy 33.2% 80 / 241
ironclaw_event_projections 43.34% 673 / 1553
ironclaw_run_state 52.36% 222 / 424
ironclaw_authorization 53.54% 461 / 861
ironclaw_triggers 59.99% 1736 / 2894
ironclaw_observability 61.54% 16 / 26
ironclaw_webui_v2 63.12% 2543 / 4029
ironclaw_mcp 63.15% 581 / 920
ironclaw_reborn_cli 63.41% 3816 / 6018
ironclaw_reborn_migration 67.01% 1172 / 1749
ironclaw_memory 67.12% 747 / 1113
ironclaw_dispatcher 67.15% 92 / 137
ironclaw_filesystem 67.44% 3815 / 5657
ironclaw_trust 72.88% 661 / 907
ironclaw_capabilities 74.08% 1658 / 2238
ironclaw_wasm_limiter 74.6% 47 / 63
ironclaw_reborn_event_store 74.61% 958 / 1284
ironclaw_extractors 74.72% 538 / 720
ironclaw_first_party_extensions 77.62% 5411 / 6971
ironclaw_llm 77.88% 19480 / 25013
ironclaw_product_context 78.57% 11 / 14
ironclaw_wasm_product_adapters 80.58% 1510 / 1874
ironclaw_process_sandbox 80.65% 671 / 832
ironclaw_reborn_openai_compat 80.95% 956 / 1181
ironclaw_memory_native 81.86% 3226 / 3941
ironclaw_wasm 82.54% 950 / 1151
ironclaw_secrets 82.7% 2791 / 3375
ironclaw_events 83.47% 1762 / 2111
ironclaw_processes 84.06% 965 / 1148
ironclaw_turns 84.24% 13099 / 15549
ironclaw_host_api 85.17% 2549 / 2993
ironclaw_product_workflow 85.74% 10624 / 12391
ironclaw_projects 85.92% 659 / 767
ironclaw_network 86.12% 670 / 778
ironclaw_threads 86.45% 4021 / 4651
ironclaw_common 86.59% 1472 / 1700
ironclaw_slack_v2_adapter 86.79% 1806 / 2081
ironclaw_auth 86.96% 2995 / 3444
ironclaw_reborn_config 86.98% 1730 / 1989
ironclaw_reborn_identity 87.03% 557 / 640
ironclaw_product_adapters 87.29% 3207 / 3674
ironclaw_skills 87.35% 4336 / 4964
ironclaw_hooks 87.84% 9916 / 11289
ironclaw_product_adapter_registry 87.96% 526 / 598
ironclaw_reborn_traces 88.23% 11707 / 13268
ironclaw_extensions 88.26% 2631 / 2981
ironclaw_reborn_composition 88.77% 69708 / 78529
ironclaw_host_runtime 88.95% 17523 / 19700
ironclaw_reborn 89.14% 15703 / 17616
ironclaw_conversations 90% 2924 / 3249
ironclaw_approvals 90.51% 1507 / 1665
ironclaw_event_streams 91.48% 1009 / 1103
ironclaw_loop_support 92.46% 14723 / 15924
ironclaw_resources 93.05% 4607 / 4951
ironclaw_attachments 93.06% 630 / 677
ironclaw_reborn_webui_ingress 93.19% 2217 / 2379
ironclaw_telegram_v2_adapter 94.01% 2447 / 2603
ironclaw_agent_loop 94.58% 8776 / 9279
ironclaw_safety 94.8% 3668 / 3869
ironclaw_first_party_extension_ports 95% 3094 / 3257
ironclaw_outbound 95.59% 3556 / 3720

This table itself is informational and never gates the PR on its own — not the percentage, not the per-crate holes, not the 0-coverage callout. A separate coverage ratchet (dry-run until enforce=true; see tests/integration/coverage-floor.toml) can fail the build on specific configured floors.

Exemptions (4 entry/entries excluded from the accounting above)
Module / Crate Reason Issue
crate: ironclaw_embeddings v1-only: consumed only by root ironclaw (src/app.rs, src/tools/builtin/memory.rs, src/workspace/mod.rs, src/config/{mod,embeddings}.rs); no crates/* dependents. Covered by "Tests (Legacy)". #5657
crate: ironclaw_gateway v1-only: consumed only by root ironclaw (src/channels/web/platform/static_files.rs, src/channels/web/handlers/frontend.rs); no crates/* dependents. Covered by "Tests (Legacy)". #5657
crate: ironclaw_oauth v1-only: consumed only by root ironclaw (src/auth/oauth.rs); no crates/* dependents. Crate's own doc comment confirms v1-only. Covered by "Tests (Legacy)". #5657
crate: ironclaw_tui v1-only: consumed only by root ironclaw (src/main.rs, src/channels/tui.rs); no crates/* dependents. Crate's own doc comment confirms it bridges INTO v1, not Reborn. Covered by "Tests (Legacy)". #5657

coderabbitai[bot]

This comment was marked as resolved.

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5769 July 7, 2026 13:53 Destroyed
@github-actions github-actions Bot added size: XL 500+ changed lines and removed size: L 200-499 changed lines labels Jul 7, 2026
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5769 July 7, 2026 13:56 Destroyed
@italic-jinxin

Copy link
Copy Markdown
Contributor Author

@claude review

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5769 July 7, 2026 14:00 Destroyed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ironclaw_webui_v2/static/js/design-system/select-menu.js`:
- Around line 167-173: The outside-click path in the select menu still invokes
closeMenu() with the default focus-restoring behavior, so update the
outsideClickEntryRef.current.close callback in select-menu.js to call closeMenu
with restoreFocus disabled. Keep the Escape/keyboard close path unchanged so it
can still restore focus, and make sure the change is applied where the
outside-click handler is wired up.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b6894423-3c15-4037-8ac6-efda6e313dec

📥 Commits

Reviewing files that changed from the base of the PR and between c7fb8da and ef2c9e0.

📒 Files selected for processing (3)
  • crates/ironclaw_webui_v2/static/js/design-system/select-menu.js
  • crates/ironclaw_webui_v2/static/js/design-system/select-menu.test.mjs
  • tests/e2e/scenarios/test_reborn_webui_v2_legacy_tool_permissions.py

Comment thread crates/ironclaw_webui_v2/static/js/design-system/select-menu.js Outdated
@claude

This comment was marked as resolved.

@railway-app

railway-app Bot commented Jul 7, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the ironclaw-pr-5769 environment in ironclaw-ci-preview

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Jul 8, 2026 at 12:15 pm

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5769 July 7, 2026 14:15 Destroyed
@italic-jinxin italic-jinxin self-assigned this Jul 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ironclaw_webui_v2/static/js/design-system/select-menu.js`:
- Around line 198-202: The select menu button props currently always include
aria-owns even when the listbox is closed, leaving an IDREF to an element that
is not rendered. Update the buttonListboxProps logic in the select menu
component so aria-owns is only applied when open, or remove it entirely since
aria-controls already handles the open relationship and the listbox is a
sibling. Keep the open-state and activeOptionId handling in the same
buttonListboxProps object.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4e097971-6872-442a-8b8d-a906b9f8feb7

📥 Commits

Reviewing files that changed from the base of the PR and between 0bb5f40 and dc10bae.

📒 Files selected for processing (2)
  • crates/ironclaw_webui_v2/static/js/design-system/select-menu.js
  • crates/ironclaw_webui_v2/static/js/design-system/select-menu.test.mjs

Comment thread crates/ironclaw_webui_v2/frontend/src/design-system/select-menu.tsx
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5769 July 7, 2026 14:23 Destroyed
@italic-jinxin italic-jinxin added the human-verified Manually tested and verified label Jul 7, 2026
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5769 July 8, 2026 12:05 Destroyed
# Conflicts:
#	crates/ironclaw_webui_v2/frontend/src/pages/settings/components/tools-tab.tsx
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-5769 July 8, 2026 16:00 Destroyed
@github-actions github-actions Bot added size: L 200-499 changed lines and removed size: XL 500+ changed lines labels Jul 8, 2026
@think-in-universe
think-in-universe added this pull request to the merge queue Jul 8, 2026
Merged via the queue into main with commit 52cc484 Jul 8, 2026
61 checks passed
@think-in-universe
think-in-universe deleted the feat-custom-tools-select branch July 8, 2026 16:28

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-5769 — 7bab4ce5 Deployed Jul 8, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs human-verified Manually tested and verified risk: low Changes to docs, tests, or low-risk modules size: L 200-499 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve Reborn tool permission selects with a custom dropdown

2 participants