Skip to content

fix(webapp): say why the buttons are dead (BEA-190) - #200

Open
ssowonny wants to merge 1 commit into
mainfrom
bea-190-ph-scan-bug-a-read-only-member-is-never-told-they-are-read
Open

fix(webapp): say why the buttons are dead (BEA-190)#200
ssowonny wants to merge 1 commit into
mainfrom
bea-190-ph-scan-bug-a-read-only-member-is-never-told-they-are-read

Conversation

@ssowonny

@ssowonny ssowonny commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

TL;DR

  • A read-only member got the same "install the CLI and start syncing" prompt everyone gets, and found out the hub refuses pushes only after installing, running bdrive init and editing a file.
  • On Settings the Save button and the whole Danger zone just vanished. Absence reads as a broken page; now they're there, disabled, next to a sentence saying why.
  • The report missed a third case: a plain write member got no signal at all — no chip (it's gated on < write), no buttons (gated on < admin). Fixed by keying the copy off mayEdit, not off perm.
  • Known gap: the sibling report (a read-only member sees the Public links table and its copy control) is not here — separate issue, and BEA-130 deliberately lets readers copy a link they can already see.
  • Frontend only. No server-side permission change; the hub already enforced all of this.

The hole

Three levels, two thresholds, one page. Nobody in the middle column was told anything.

read write (not admin) admin
Settings — "Read-only" chip yes (11px, --text-faint) no — gated on < write no
Settings — Save / Danger zone absent absent live
Settings — a reason, before none none n/a
Settings — a reason, now "You have read access to this project. Changes you make locally stay on your device." "Only a project admin can rename or delete this project." none
Installation page, before full writer CTA full writer CTA full writer CTA
Installation page, now + read-only note unchanged unchanged

That middle column is why the new copy is derived from mayEdit rather than from perm. Deriving it from perm would have shipped the exact bug again for write members.

Installation page

ConnectGuide already receives the whole Project and never consulted perm. It does now, and a perm < write account gets a gd-note above the paste prompt — before anything is copied.

The copy deliberately does not say "don't install". A read-only member genuinely can sync down (GET /store/list, GET /store/object are PermRead) and cannot push (POST /store/sign, PUT /store/object are PermWrite), so pull-only is a supported use of this page. What they're told is both halves: you'll receive the team's changes, your own edits stay on this device.

The project.perm !== undefined guard matters — Project.perm is optional in the TS type even though the hub always populates it, and atLeast(undefined, "write") is false. Without the guard a payload missing perm would warn every user, which is worse than warning none.

before after
install before install after

Settings

Save and the Danger zone are rendered unconditionally with disabled={!mayEdit}, and each gated card states the reason once. The three General fields were already disabled; only the two controls that vanished changed.

The .ps-chip stays — it's a fine at-a-glance badge, it just can't be the only signal. It shipped in 69e7231 (2026-07-27), well before the scan, so the "neither page contains the words read only" half of the report was wrong as filed; what was right is that it's 11px --text-faint and two reviewers missed it.

read-only member — before, the page rendered normally with its buttons quietly missing:

before after
settings reader before settings reader after

write member — the case the report didn't see. Before: no chip, no buttons, no explanation anywhere on the page.

before after
settings member before settings member after

What I'm accepting

Showing a disabled Danger zone to every project member is more chrome for more people. That's the trade the issue's acceptance criteria asked for ("no control silently absent"), and the stated fallback was one explicit statement covering both removed controls instead. I picked disabled-with-reason and applied it to both cards rather than mixing. If that reads as clutter, the swap is one {mayEdit && …} away — say so and I'll flip both.

What was run

  • go test ./... — pass.
  • go vet ./... — clean.
  • npm run build in internal/webapp/frontend, internal/webapp/static committed; ./check-dist.sh clean.
  • npm run e2e — 207 passed, 1 skipped, 0 failed.
  • Five new e2e cases (READER / MEMBER / ADMIN across both pages), plus two existing ones updated: they asserted the danger zone and Save were absent, which is the behavior this PR deliberately changes.
  • Screenshots above are the real UI at 1280 wide against the seeded e2e hub. Disabled controls verified at computed opacity: 0.5, pointer-events: none.

Two components, one stylesheet rule, one bundle rebuild. No new component, seam or data flow, so architecture/webapp-frontend.md is unchanged and there's no "Architecture changes" section.

Closes BEA-190.

Build session

cd $(git worktree list | grep bea-190-ph-scan-bug-a-read-only-member-is-never-told-they-are-read | awk '{print $1}') && claude --resume 6e7cbe22-c67e-413f-99c2-55037cd89c25

(this machine only)

The hub knew an account was restricted, changed its UI to match, and never
said so. A read-only member got the identical "install the CLI and start
syncing" prompt a writer gets, and found out the hub refuses pushes only
after installing, running `bdrive init` and editing a file. On Settings the
Save button and the whole Danger zone simply vanished — absence reads as a
broken page, not as policy.

- Installation page: a `perm < write` account gets a note above the paste
  prompt saying it will receive the team's changes and that its own edits
  stay local. Not "don't install": pull-only sync is supported and the
  page is legitimately useful to them.
- Settings: one sentence per gated card, derived from `mayEdit` rather
  than from `perm`. That covers the case the report missed — a plain
  write member is short of *admin*, saw no Read-only chip (it is gated on
  `< write`) and no buttons either, so they got no explanation at all.
- Save and Danger zone are rendered disabled instead of removed. The
  server still enforces both; this is only what the page says about it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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