The assignee menu holds still: the chips under it wait until it shuts #227

Merged
Grandiras merged 1 commit from assignee-menu-holds-still into main 2026-09-23 11:38:26 +00:00
Owner

Follow-up to #225. The assignee menu moved around while you ticked people on and off. It hangs off the foot of the assignee panel, and the panel is as tall as its row of chips. So a person added from the menu wrapped the row, grew the panel and pushed the menu down under the pointer, and removing one pulled it back up.

The chip row now holds still while the menu is open. It's frozen at who was on the card when the menu opened (_heldChips). The menu's ticks show who is on in the meantime, and the chips catch up when the menu closes. This is the same way GitHub's assignee dropdown behaves. Only the drawing waits: every toggle still reaches the dialog as it happens, so closing the menu any way at all (Escape, a click elsewhere) loses nothing.

Also: if a member loses edit rights while the menu is open, the menu now closes. Previously it could stay open offering everybody to someone who may now only add themselves.

Tests: permissions.spec.js now checks that the menu's offset from its panel doesn't change while people are toggled, and that the new chip appears only once the menu closes. It measures the offset rather than the screen position, which the menu's entrance and the smooth scroll would disturb. The spec fails on the #225 picker and passes here. permissions and mobile specs: 9 passed. dotnet test: 560 passed.

The docs (ui.md and boards-and-permissions.md) are updated. No changelog change, since this refines the unreleased picker entry.

🤖 Generated with Claude Code

Follow-up to #225. The assignee menu moved around while you ticked people on and off. It hangs off the foot of the assignee panel, and the panel is as tall as its row of chips. So a person added from the menu wrapped the row, grew the panel and pushed the menu down under the pointer, and removing one pulled it back up. **The chip row now holds still while the menu is open.** It's frozen at who was on the card when the menu opened (`_heldChips`). The menu's ticks show who is on in the meantime, and the chips catch up when the menu closes. This is the same way GitHub's assignee dropdown behaves. Only the drawing waits: every toggle still reaches the dialog as it happens, so closing the menu any way at all (Escape, a click elsewhere) loses nothing. Also: if a member loses edit rights while the menu is open, the menu now closes. Previously it could stay open offering everybody to someone who may now only add themselves. **Tests:** `permissions.spec.js` now checks that the menu's offset from its panel doesn't change while people are toggled, and that the new chip appears only once the menu closes. It measures the offset rather than the screen position, which the menu's entrance and the smooth scroll would disturb. The spec fails on the #225 picker and passes here. `permissions` and `mobile` specs: 9 passed. `dotnet test`: 560 passed. The docs (`ui.md` and `boards-and-permissions.md`) are updated. No changelog change, since this refines the unreleased picker entry. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The assignee menu holds still: the chips under it wait until it shuts
All checks were successful
CI / build (pull_request) Successful in 38s
6f6cc43f14
The menu hangs off the foot of the assignee panel, and the panel is as tall
as its row of chips — so a person added from the menu wrapped the row, grew
the panel and moved the menu under the pointer pressing in it, and taking
one off moved it back. The chips are now held at who was on the card when
the menu opened; the menu's ticks say who is on meanwhile, and the chips
catch up when it shuts. Every toggle still reaches the dialog as it happens.

A role taken away while the menu is open shuts it, rather than leaving a
menu that offers everybody to somebody who may only pick themselves.

permissions.spec.js pins that the menu's offset from its panel does not
change across toggles and that the chip appears only once it shuts; it
fails on the live-updating picker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator

🤖 Reviewing this PR — the review will link the full session transcript.

🤖 Reviewing this PR — the review will link the full session transcript. <!-- opencode-run:review -->
Grandiras force-pushed assignee-menu-holds-still from 6f6cc43f14
All checks were successful
CI / build (pull_request) Successful in 38s
to c8efc0f230
All checks were successful
CI / build (pull_request) Successful in 42s
2026-09-23 11:30:00 +00:00
Compare
opencode-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

The hold is implemented cleanly and the test measures the right thing.

  • _heldChips freezes only the drawing: OnCard reads the snapshot while the menu is open and the live set otherwise, and every close path (CloseAsync, the new demotion branch in OnParametersSet) clears it on the same render, so the chips catch up exactly once. Every toggle still mutates the live SelectedMemberDids and reaches the dialog, so closing the menu any way loses nothing, as the PR claims.
  • The demotion path (a role taken away while the menu is open) both shuts the menu and clears the hold, and the @if (_open && OnlyDid is null) gate makes the menu unreachable in the mode where it should never exist.
  • The test's el.offsetTop probe is correct for what it wants to detect: the menu is absolutely positioned at calc(100% - 0.5rem) inside the position: relative panel, so offsetTop grows with the panel when a chip wraps the row (the #225 bug), while the entrance translateY animation and the smooth scroll in js/assignee-menu.js change only screen position, not offsetTop. The assertion ordering — chip count 0 before reading the offset, chip count 1 only after Escape — is right.

Two minor notes, neither blocking: in the OnParametersSet demotion path focus is not handed anywhere (unlike CloseAsync's _addButton.FocusAsync(), and the old button isn't rendered in that mode anyway), so a keyboard user's focus drops to the body when the menu vanishes under them; and theoretically a parent swapping SelectedMemberDids for a fresh instance while the menu is open would leave ticks reading the new set while the chips read the snapshot — but every route to that also flips CanEdit, which the new gate now handles.



⏱ 8m 28s · 0 steps · $0.0000 · tokens: 0 in / 0 out (+0 cache-read) · Go: 5h 14% · wk 80% · mo 72%

✅ **Verdict: approve** — no blocking issues found. The hold is implemented cleanly and the test measures the right thing. - `_heldChips` freezes only the drawing: `OnCard` reads the snapshot while the menu is open and the live set otherwise, and every close path (`CloseAsync`, the new demotion branch in `OnParametersSet`) clears it on the same render, so the chips catch up exactly once. Every toggle still mutates the live `SelectedMemberDids` and reaches the dialog, so closing the menu any way loses nothing, as the PR claims. - The demotion path (a role taken away while the menu is open) both shuts the menu and clears the hold, and the `@if (_open && OnlyDid is null)` gate makes the menu unreachable in the mode where it should never exist. - The test's `el.offsetTop` probe is correct for what it wants to detect: the menu is absolutely positioned at `calc(100% - 0.5rem)` inside the `position: relative` panel, so `offsetTop` grows with the panel when a chip wraps the row (the #225 bug), while the entrance `translateY` animation and the smooth scroll in `js/assignee-menu.js` change only screen position, not `offsetTop`. The assertion ordering — chip count 0 before reading the offset, chip count 1 only after Escape — is right. Two minor notes, neither blocking: in the `OnParametersSet` demotion path focus is not handed anywhere (unlike `CloseAsync`'s `_addButton.FocusAsync()`, and the old button isn't rendered in that mode anyway), so a keyboard user's focus drops to the body when the menu vanishes under them; and theoretically a parent swapping `SelectedMemberDids` for a fresh instance while the menu is open would leave ticks reading the new set while the chips read the snapshot — but every route to that also flips `CanEdit`, which the new gate now handles. --- --- ⏱ 8m 28s · 0 steps · $0.0000 · tokens: 0 in / 0 out (+0 cache-read) · Go: 5h 14% · wk 80% · mo 72% <!-- opencode-reviewed-head:6f6cc43f14ba5c80cfda693fa43161946b7ade39 --> <!-- opencode-verdict:approve -->
Collaborator

🤖 Reviewing this PR — the review will link the full session transcript.

🤖 Reviewing this PR — the review will link the full session transcript. <!-- opencode-run:review -->
Grandiras deleted branch assignee-menu-holds-still 2026-09-23 11:38:27 +00:00
opencode-reviewer left a comment

💬 Verdict: comment — the reviewer did not submit a structured review; the raw output follows.

(empty)



⏱ 0m 28s · 0 steps · $0.0000 · tokens: 0 in / 0 out (+0 cache-read) · Go: 5h 14% · wk 80% · mo 72%

💬 **Verdict: comment** — the reviewer did not submit a structured review; the raw output follows. (empty) --- --- ⏱ 0m 28s · 0 steps · $0.0000 · tokens: 0 in / 0 out (+0 cache-read) · Go: 5h 14% · wk 80% · mo 72%
Collaborator

🔧 Let opencode-bot fix this — tick the box and opencode-bot picks up the review above, on this PR branch. Nothing runs until you do.

  • @opencode-bot Address the findings of the latest review on this pull request.
🔧 **Let opencode-bot fix this** — tick the box and opencode-bot picks up the review above, on this PR branch. Nothing runs until you do. - [ ] @opencode-bot Address the findings of the latest review on this pull request. <!-- opencode-fix-button:227 -->
Grandiras referenced this pull request from a commit 2026-09-23 11:47:01 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Grandiras/Ponente!227
No description provided.