Skip to content

feat: add add-solver permission selector and payload support#58

Merged
arkanoider merged 3 commits into
mainfrom
feat/admin-add-solver-permissions-ui
Apr 29, 2026
Merged

feat: add add-solver permission selector and payload support#58
arkanoider merged 3 commits into
mainfrom
feat/admin-add-solver-permissions-ui

Conversation

@arkanoider

@arkanoider arkanoider commented Apr 29, 2026

Copy link
Copy Markdown
Collaborator

Improve the admin add-solver flow by introducing a read/read-write permission selector in the popup and carrying that choice through confirmation and submission. Format admin-add-solver payloads according to protocol expectations, preserve state on cancel paths, and refresh help text and tests for the new behavior.

Summary by CodeRabbit

  • New Features

    • Added permission selection (Read or Read-Write) when adding dispute solvers
    • Confirmation now shows the chosen permission label
  • Improvements

    • Redesigned Add Solver popup into a dedicated permission-aware UI with in-popup help
    • Left/Right keys toggle permission during setup; cancelling preserves the selected permission

Improve the admin add-solver flow by introducing a read/read-write permission selector in the popup and carrying that choice through confirmation and submission. Format admin-add-solver payloads according to protocol expectations, preserve state on cancel paths, and refresh help text and tests for the new behavior.

Made-with: Cursor
@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@arkanoider has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 41 minutes and 10 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c9c93b6a-abd0-46a5-bd02-7df44bbb7fd6

📥 Commits

Reviewing files that changed from the base of the PR and between f6cba5b and cafe34e.

📒 Files selected for processing (2)
  • src/ui/draw.rs
  • src/ui/key_handler/admin_handlers.rs

Walkthrough

A solver permission selector is introduced to the admin "Add Solver" UI flow. A new SolverPermission enum (Read/ReadWrite) is created, encapsulated in AddSolverState alongside key input. The UI renders a dedicated permission selector popup, Left/Right keys toggle permissions, and the backend generates payloads with conditional :read suffix based on the selected permission. shared is exported from the crate root.

Changes

Cohort / File(s) Summary
State Model & Type System
src/shared/permissions.rs, src/ui/admin_state.rs, src/ui/mod.rs, src/ui/state.rs
Add SolverPermission enum with toggle() and as_label(); introduce AddSolverState { key_input, permission }; update AdminMode and public re-exports to include AddSolverState and SolverPermission.
UI Rendering
src/ui/draw.rs, src/ui/help_popup.rs
Replace generic add-solver popup with render_add_solver_popup showing pubkey + permission selector and update help text to instruct permission selection.
Key Handling & Input Flow
src/ui/key_handler/...
src/ui/key_handler/admin_handlers.rs, .../confirmation.rs, .../enter_handlers.rs, .../esc_handlers.rs, .../mod.rs, .../navigation.rs
Thread permission through admin key-handler flow: AddSolver now contains AddSolverState; Confirm uses struct-style variant with permission; Left/Right toggle permission in AddSolver; character input goes to nested key_input. execute_add_solver_action signature updated to accept permission.
Business Logic & Payload Generation
src/util/order_utils/execute_admin_add_solver.rs
execute_admin_add_solver gains a permission parameter and builds payload via build_solver_payload_text, appending :read for Read and leaving pubkey unchanged for ReadWrite; added unit tests for both cases.
Paste Handling & Exports
src/main.rs, src/lib.rs
Refactor paste handling in apply_pasted_text_to_active_input into explicit branches per admin mode; export pub mod shared; from crate root.

Sequence Diagram

sequenceDiagram
    participant User
    participant KeyHandler as Key Handler
    participant AdminState as Admin State
    participant Draw as UI Renderer
    participant Backend as Backend Executor

    User->>KeyHandler: Enter Add Solver mode
    KeyHandler->>AdminState: Create AddSolverState(key_input, permission=ReadWrite)
    AdminState-->>Draw: Render permission selector popup
    Draw-->>User: Display pubkey & Read/Read-Write options

    loop user edits / navigates
        User->>KeyHandler: Type chars / Press Left/Right
        alt char input
            KeyHandler->>AdminState: Append chars to key_input
        else left/right
            KeyHandler->>AdminState: Toggle permission (Read ⇄ ReadWrite)
        end
        AdminState-->>Draw: Re-render popup
    end

    User->>KeyHandler: Confirm (Enter)
    KeyHandler->>AdminState: Transition to ConfirmAddSolver{solver_pubkey, permission}
    Draw-->>User: Show confirmation with permission label

    User->>KeyHandler: Confirm yes
    KeyHandler->>Backend: Call execute_admin_add_solver(solver_pubkey, permission)
    Backend->>Backend: Build payload (append :read if permission == Read)
    Backend-->>User: Send payload to Mostro instance
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • Catrya
  • grunch
  • mostronatorcoder

Poem

🐰 I hopped to the popup, permission in paw,
Read or read-write, choose what you saw,
Left and right flick, the label replied,
Pubkey and permission now walk side by side,
A tiny rabbit cheers as the admin flow glides.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a permission selector and payload support to the admin add-solver feature.
Docstring Coverage ✅ Passed Docstring coverage is 95.65% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/admin-add-solver-permissions-ui

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
Review rate limit: 0/1 reviews remaining, refill in 41 minutes and 10 seconds.

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

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (4)
src/ui/key_handler/enter_handlers.rs (1)

1077-1080: Consider defaulting solver permission to Read for safer UX.

Line 1079 currently defaults to ReadWrite; starting at Read would better follow least-privilege and reduce accidental over-granting.

Proposed tweak
-                    permission: crate::ui::SolverPermission::ReadWrite,
+                    permission: crate::ui::SolverPermission::Read,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/key_handler/enter_handlers.rs` around lines 1077 - 1080, The code
currently sets the new AddSolver state with permission
SolverPermission::ReadWrite; change this default to the least-privilege option
by replacing SolverPermission::ReadWrite with SolverPermission::Read when
constructing UiMode::AdminMode(AdminMode::AddSolver(crate::ui::AddSolverState {
key_input: key_state, permission: ... })); ensure you only change the permission
enum value in the AddSolverState construction (leave UiMode::AdminMode,
AdminMode::AddSolver, and key_input as-is).
src/ui/help_popup.rs (1)

241-241: Include the selection keybinding in this help text.

Line 241 explains what to choose, but adding Left/Right would also explain how to choose it in-popup.

Suggested wording
-            "Enter solver npub and choose read or read-write permission before confirming.",
+            "Enter solver npub, use Left/Right to choose read or read-write, then confirm.",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/help_popup.rs` at line 241, Update the help text string in
src/ui/help_popup.rs (the line containing "Enter solver npub and choose read or
read-write permission before confirming.") to include the selection keybinding,
e.g., append "Use Left/Right to switch" or similar so users know how to toggle
the read vs read-write option; modify the exact literal in the help popup
rendering code where this message is defined to include "Left/Right" (or
"Left/Right arrow keys") next to the instruction.
src/util/order_utils/execute_admin_add_solver.rs (2)

102-114: Add a hex-input regression test for payload generation.

Current tests validate npub cases only. Add one case with a 64-char hex key to verify normalization + :read suffix behavior, since that path is part of this new payload logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/util/order_utils/execute_admin_add_solver.rs` around lines 102 - 114, Add
a new test that covers the hex-key normalization path: call
build_solver_payload_text with a 64-character hex key string and
SolverPermission::Read and assert the returned payload equals "{hex}:read"
(i.e., the hex key plus ":read"); also add a complementary test that calls
build_solver_payload_text with the same hex key and SolverPermission::ReadWrite
and assert the payload equals the hex key unchanged. Place these tests alongside
the existing add_solver_payload_* tests that use npub so the hex-input
regression for build_solver_payload_text is exercised.

8-8: Consider decoupling order_utils from crate::ui types.

src/util/order_utils/execute_admin_add_solver.rs importing crate::ui::SolverPermission couples utility/protocol code to UI state. Prefer moving this enum to a shared/domain module consumed by both layers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/util/order_utils/execute_admin_add_solver.rs` at line 8, The file
execute_admin_add_solver.rs currently imports SolverPermission from crate::ui
which couples utility code to the UI; move the SolverPermission enum into a
shared/domain module (e.g., crate::domain::permissions or crate::shared::types)
and update execute_admin_add_solver.rs to import the enum from that new module
instead of crate::ui; update any other files that reference
crate::ui::SolverPermission to use the new path and run tests/compile to ensure
no remaining crate::ui references remain (look for the symbol SolverPermission
and the execute_admin_add_solver.rs import line).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/ui/help_popup.rs`:
- Line 241: Update the help text string in src/ui/help_popup.rs (the line
containing "Enter solver npub and choose read or read-write permission before
confirming.") to include the selection keybinding, e.g., append "Use Left/Right
to switch" or similar so users know how to toggle the read vs read-write option;
modify the exact literal in the help popup rendering code where this message is
defined to include "Left/Right" (or "Left/Right arrow keys") next to the
instruction.

In `@src/ui/key_handler/enter_handlers.rs`:
- Around line 1077-1080: The code currently sets the new AddSolver state with
permission SolverPermission::ReadWrite; change this default to the
least-privilege option by replacing SolverPermission::ReadWrite with
SolverPermission::Read when constructing
UiMode::AdminMode(AdminMode::AddSolver(crate::ui::AddSolverState { key_input:
key_state, permission: ... })); ensure you only change the permission enum value
in the AddSolverState construction (leave UiMode::AdminMode,
AdminMode::AddSolver, and key_input as-is).

In `@src/util/order_utils/execute_admin_add_solver.rs`:
- Around line 102-114: Add a new test that covers the hex-key normalization
path: call build_solver_payload_text with a 64-character hex key string and
SolverPermission::Read and assert the returned payload equals "{hex}:read"
(i.e., the hex key plus ":read"); also add a complementary test that calls
build_solver_payload_text with the same hex key and SolverPermission::ReadWrite
and assert the payload equals the hex key unchanged. Place these tests alongside
the existing add_solver_payload_* tests that use npub so the hex-input
regression for build_solver_payload_text is exercised.
- Line 8: The file execute_admin_add_solver.rs currently imports
SolverPermission from crate::ui which couples utility code to the UI; move the
SolverPermission enum into a shared/domain module (e.g.,
crate::domain::permissions or crate::shared::types) and update
execute_admin_add_solver.rs to import the enum from that new module instead of
crate::ui; update any other files that reference crate::ui::SolverPermission to
use the new path and run tests/compile to ensure no remaining crate::ui
references remain (look for the symbol SolverPermission and the
execute_admin_add_solver.rs import line).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9d77aff7-ed9a-4f99-b58f-b114af42fb23

📥 Commits

Reviewing files that changed from the base of the PR and between 77246d0 and f166cee.

📒 Files selected for processing (13)
  • src/main.rs
  • src/ui/admin_state.rs
  • src/ui/draw.rs
  • src/ui/help_popup.rs
  • src/ui/key_handler/admin_handlers.rs
  • src/ui/key_handler/confirmation.rs
  • src/ui/key_handler/enter_handlers.rs
  • src/ui/key_handler/esc_handlers.rs
  • src/ui/key_handler/mod.rs
  • src/ui/key_handler/navigation.rs
  • src/ui/mod.rs
  • src/ui/state.rs
  • src/util/order_utils/execute_admin_add_solver.rs

@mostronatorcoder mostronatorcoder 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.

I reviewed the latest diff carefully and I do not see a blocker here.

What I checked:

  • the new add-solver UI state machine, including permission selection, confirmation, and cancel paths
  • keyboard handling so Left/Right toggles permission in the input popup and still behaves correctly in the confirmation popup
  • payload formatting for AdminAddSolver, especially the :read suffix for read-only solvers and the default payload for read-write solvers
  • state preservation when backing out of confirmation
  • help text and popup guidance

The implementation looks coherent to me:

  • Read maps to <npub>:read
  • ReadWrite keeps the existing payload shape
  • the selected permission survives Enter, Esc, and NO/cancel paths instead of silently resetting
  • the paste path in main.rs was updated correctly for the richer AddSolverState

Checks are green too, so this looks good from my side. Nice improvement to the admin solver flow.

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (3)
src/ui/key_handler/admin_handlers.rs (1)

92-110: Optional: remove extra solver_pubkey clone before spawn.

You can move solver_pubkey into the async block directly and borrow it there, avoiding the intermediate clone.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/key_handler/admin_handlers.rs` around lines 92 - 110, There’s an
unnecessary clone of solver_pubkey (solver_pubkey_clone) before spawning the
task; instead move/own solver_pubkey into the async block and use it there to
avoid the extra clone. Replace usage of solver_pubkey_clone with solver_pubkey
inside the tokio::spawn closure and ensure execute_admin_add_solver is called
with a reference or moved value consistent with its signature; remove the
solver_pubkey_clone binding and adjust the surrounding code that prepares
parameters (client_clone, result_tx, mostro_info) so they are moved/borrowed
into the spawned task similarly.
src/main.rs (1)

103-123: Optional: extract shared paste-append helper for admin key inputs.

Line 105-123 repeats the same sanitize/append/just_pasted pattern for two admin input states; pulling this into a small helper would reduce drift risk on future input updates.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main.rs` around lines 103 - 123, Extract the repeated paste-and-append
logic into a small helper function (e.g., sanitize_and_append_paste) and replace
the duplicated blocks in the UiMode::AdminMode(AdminMode::AddSolver(ref mut
add_solver_state)) and UiMode::AdminMode(AdminMode::SetupAdminKey(ref mut
key_state)) arms to call it; the helper should take the pasted_text and a
mutable reference to the input buffer and just_pasted flag (or the state
struct), perform the chars().filter(|c| !c.is_control() || *c ==
'\t').collect(), append the result to the target key_input (for AddSolver use
add_solver_state.key_input.key_input.push_str, for SetupAdminKey use
key_state.key_input.push_str), and set just_pasted = true so both
add_solver_state and key_state reuse the same logic.
src/ui/draw.rs (1)

460-464: Optional render-path optimization: avoid cloning solver input each draw.

You can render with &str/Cow<'_, str> instead of allocating a new String every frame on Line 463.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/draw.rs` around lines 460 - 464, The current code always allocates a
new String for input_display by cloning add_solver_state.key_input.key_input;
instead use a borrowed &str or Cow<'_, str> to avoid per-frame allocation:
change input_display's type to &str or Cow<'_, str> and return either a borrowed
literal ("npub... / hex...") or a borrowed slice of
add_solver_state.key_input.key_input (e.g.,
&add_solver_state.key_input.key_input) instead of calling .clone(), referencing
the symbol add_solver_state.key_input.key_input and the binding input_display to
locate where to update.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main.rs`:
- Around line 103-123: Extract the repeated paste-and-append logic into a small
helper function (e.g., sanitize_and_append_paste) and replace the duplicated
blocks in the UiMode::AdminMode(AdminMode::AddSolver(ref mut add_solver_state))
and UiMode::AdminMode(AdminMode::SetupAdminKey(ref mut key_state)) arms to call
it; the helper should take the pasted_text and a mutable reference to the input
buffer and just_pasted flag (or the state struct), perform the
chars().filter(|c| !c.is_control() || *c == '\t').collect(), append the result
to the target key_input (for AddSolver use
add_solver_state.key_input.key_input.push_str, for SetupAdminKey use
key_state.key_input.push_str), and set just_pasted = true so both
add_solver_state and key_state reuse the same logic.

In `@src/ui/draw.rs`:
- Around line 460-464: The current code always allocates a new String for
input_display by cloning add_solver_state.key_input.key_input; instead use a
borrowed &str or Cow<'_, str> to avoid per-frame allocation: change
input_display's type to &str or Cow<'_, str> and return either a borrowed
literal ("npub... / hex...") or a borrowed slice of
add_solver_state.key_input.key_input (e.g.,
&add_solver_state.key_input.key_input) instead of calling .clone(), referencing
the symbol add_solver_state.key_input.key_input and the binding input_display to
locate where to update.

In `@src/ui/key_handler/admin_handlers.rs`:
- Around line 92-110: There’s an unnecessary clone of solver_pubkey
(solver_pubkey_clone) before spawning the task; instead move/own solver_pubkey
into the async block and use it there to avoid the extra clone. Replace usage of
solver_pubkey_clone with solver_pubkey inside the tokio::spawn closure and
ensure execute_admin_add_solver is called with a reference or moved value
consistent with its signature; remove the solver_pubkey_clone binding and adjust
the surrounding code that prepares parameters (client_clone, result_tx,
mostro_info) so they are moved/borrowed into the spawned task similarly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1050bd0a-21de-4981-8f0a-6525cd59d945

📥 Commits

Reviewing files that changed from the base of the PR and between f166cee and f6cba5b.

📒 Files selected for processing (12)
  • src/lib.rs
  • src/main.rs
  • src/shared/mod.rs
  • src/shared/permissions.rs
  • src/ui/admin_state.rs
  • src/ui/draw.rs
  • src/ui/help_popup.rs
  • src/ui/key_handler/admin_handlers.rs
  • src/ui/key_handler/enter_handlers.rs
  • src/ui/mod.rs
  • src/ui/state.rs
  • src/util/order_utils/execute_admin_add_solver.rs
✅ Files skipped from review due to trivial changes (4)
  • src/shared/mod.rs
  • src/lib.rs
  • src/ui/state.rs
  • src/ui/help_popup.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/ui/mod.rs
  • src/ui/key_handler/enter_handlers.rs
  • src/util/order_utils/execute_admin_add_solver.rs

@mostronatorcoder mostronatorcoder 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.

Re-reviewed the follow-up commits after my earlier approval.

I only checked the new changes since f166ceed, and they look fine to me:

  • SolverPermission was moved into a shared module, which is a reasonable cleanup and does not change the behavior
  • the add-solver call path still passes the selected permission through correctly
  • the small draw/help updates are harmless and consistent with the UI flow
  • checks are green on the latest head commit

I do not see a new blocker in the follow-up commits, so my approval still stands.

@arkanoider arkanoider merged commit 6898509 into main Apr 29, 2026
11 checks passed
@arkanoider arkanoider deleted the feat/admin-add-solver-permissions-ui branch April 29, 2026 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant