fix(#588): the row menu offers only what the grant allows #593

Merged
Cordy merged 1 commit from fix-588 into main 2026-09-18 01:43:40 +00:00
Owner

Two gates, kept distinct because they answer different questions, both computed by a new pure block (pure:menu-gates) and applied where openRowMenu assembles the menu:

  • share — false for anything under /shared. Re-sharing and re-addressing (Share, Copy link, Send to peer, Create space from selection) are refused at any role — only the owner decides who else gets it (#571, structural in #575's resolveOwned). The UI now stops offering what the server refuses.
  • mutate — false when the listing carries readOnly (#64's flag): Can-view grant recipients and read-only space members, one mechanism. Gates Move, Rename, Delete, Lock acquisition. As a side effect this also closes the pre-existing gap where a read-only space member was offered Delete — same flag, same fix.

Copy to… stays at every role: it reads the source and writes to the caller's own tree, both of which the grant permits. Open, Download, favourites, Details, and unlock-own-lock are untouched.

The toolbar half was already gated — it just didn't look it. applyReadOnly (#64) has disabled Upload/New on read-only listings all along, but the upload control is a label wrapping the file input, and nothing styled the disabled state (the #552 lesson again). applyReadOnly now toggles a .rodis class on the visible control; one CSS rule.

Plumbing: the listing's readOnly flag is captured into curReadOnly beside the existing applyReadOnly call, so the row menu and the toolbar consult the same server-derived fact. Delegation is derived from the item's /shared/ prefix — that prefix is the delegation marker by construction of the overlay.

New: web/test/row-menu.test.js — one pure truth-table for menuGates, then the glue: lifts openRowMenu (with menuBtn and MI) and builds the menu against a fake DOM in four scenarios — delegated read, delegated write, owned, read-only space — asserting exactly which labels appear. Red witnessed: all five failed pre-fix (delegated read offered mSharemDelete); the workflow aborts if the test passes before the splice. Green: all five, the full web suite, and the #389 extract gate.

Docs ship with the behaviour: sharing.md gains the "What a recipient is offered" paragraph #591 deliberately held back, so the handbook never described a state that didn't exist.

Two gates, kept distinct because they answer different questions, both computed by a new pure block (`pure:menu-gates`) and applied where `openRowMenu` assembles the menu: - **`share`** — false for anything under `/shared`. Re-sharing and re-addressing (`Share`, `Copy link`, `Send to peer`, `Create space from selection`) are refused at *any* role — only the owner decides who else gets it (#571, structural in #575's `resolveOwned`). The UI now stops offering what the server refuses. - **`mutate`** — false when the listing carries `readOnly` (#64's flag): Can-view grant recipients *and* read-only space members, one mechanism. Gates `Move`, `Rename`, `Delete`, `Lock` acquisition. As a side effect this also closes the pre-existing gap where a read-only space member was offered Delete — same flag, same fix. `Copy to…` stays at every role: it reads the source and writes to the caller's own tree, both of which the grant permits. `Open`, `Download`, favourites, `Details`, and unlock-own-lock are untouched. **The toolbar half was already gated — it just didn't look it.** `applyReadOnly` (#64) has disabled Upload/New on read-only listings all along, but the upload control is a `label` wrapping the file input, and nothing styled the disabled state (the #552 lesson again). `applyReadOnly` now toggles a `.rodis` class on the visible control; one CSS rule. **Plumbing:** the listing's `readOnly` flag is captured into `curReadOnly` beside the existing `applyReadOnly` call, so the row menu and the toolbar consult the same server-derived fact. Delegation is derived from the item's `/shared/` prefix — that prefix *is* the delegation marker by construction of the overlay. **New: `web/test/row-menu.test.js`** — one pure truth-table for `menuGates`, then the glue: lifts `openRowMenu` (with `menuBtn` and `MI`) and builds the menu against a fake DOM in four scenarios — delegated read, delegated write, owned, read-only space — asserting exactly which labels appear. Red witnessed: all five failed pre-fix (delegated read offered `mShare`…`mDelete`); the workflow aborts if the test passes before the splice. Green: all five, the full web suite, and the #389 extract gate. **Docs ship with the behaviour:** `sharing.md` gains the "What a recipient is offered" paragraph #591 deliberately held back, so the handbook never described a state that didn't exist.
fix(#588): the row menu offers only what the grant allows
All checks were successful
ci / test-and-build (pull_request) Successful in 1m2s
218e5a63d6
Cordy merged commit 7eca50e08a into main 2026-09-18 01:43:40 +00:00
Cordy deleted branch fix-588 2026-09-18 01:43:42 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
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: Cordy/Cairn#593
No description provided.