Share dialog: invite access selector shows while invites are off #1053

Closed
opened 2026-10-04 11:01:28 +00:00 by kayg · 9 comments
Owner

Found in the #1034 review (dialog-people-*.png, final branch 9016bfae6): the invite-link access selector ("Share ▾") and its helper text show while the "Invite people without an account" toggle is off. Show the selector only when the toggle is on, or disable it with the reason. Small; fix in the merge round or nearby.

Found in the #1034 review (dialog-people-*.png, final branch 9016bfae6): the invite-link access selector ("Share ▾") and its helper text show while the "Invite people without an account" toggle is off. Show the selector only when the toggle is on, or disable it with the reason. Small; fix in the merge round or nearby.
Author
Owner

Starting #1053 on branch job/invtoggle-1053, based at 9016bfae6631d5dc9f382c2c2ac0910bb8a9589e (job/share-1034). The worktree is clean. I’m tracing the existing Share dialog and shared motion tokens before changing the conditional invite-link access controls.

Starting #1053 on branch `job/invtoggle-1053`, based at `9016bfae6631d5dc9f382c2c2ac0910bb8a9589e` (`job/share-1034`). The worktree is clean. I’m tracing the existing Share dialog and shared motion tokens before changing the conditional invite-link access controls.
Author
Owner

Confirmed the reported state in InviteLinkSection.svelte: the pre-creation Invite access select rendered under !active.length, while the help text rendered whenever instance invite policy was enabled. The switch uses active.length as its checked state, so both appeared while it was off. The fix removes that off-state selector, keeps access changes on active invite rows, and only renders the linked helper text while an invite is active. The controls enter with the shared reduced-motion-aware fade. The e2e now checks absence/presence, keyboard order and both visual states.

Confirmed the reported state in `InviteLinkSection.svelte`: the pre-creation `Invite access` select rendered under `!active.length`, while the help text rendered whenever instance invite policy was enabled. The switch uses `active.length` as its checked state, so both appeared while it was off. The fix removes that off-state selector, keeps access changes on active invite rows, and only renders the linked helper text while an invite is active. The controls enter with the shared reduced-motion-aware fade. The e2e now checks absence/presence, keyboard order and both visual states.
Author
Owner

The real-server keyboard check found one adjacent focus defect: when the Share toggle creates an invite and auto-copies its URL, the legacy clipboard fallback selects a temporary textarea and leaves focus on BODY. The first Tab then goes to the page skip link instead of the new invite controls. I’m fixing the shared clipboard fallback to restore its invoking control, and adding coverage in the existing clipboard/component tests. This is a small shared-helper fix needed to keep the requested keyboard order usable.

The real-server keyboard check found one adjacent focus defect: when the Share toggle creates an invite and auto-copies its URL, the legacy clipboard fallback selects a temporary textarea and leaves focus on BODY. The first Tab then goes to the page skip link instead of the new invite controls. I’m fixing the shared clipboard fallback to restore its invoking control, and adding coverage in the existing clipboard/component tests. This is a small shared-helper fix needed to keep the requested keyboard order usable.
Author
Owner

The e2e run also exercised the full-link state: at 5/5, the existing active filter makes the Invite people switch unchecked, so the selector and helper are now absent there too. I moved the existing UI access-change/Undo scenario to the first joined person, while the switch is on, and added an explicit full-link off-state assertion. The existing access-change behavior remains covered without weakening its test.

The e2e run also exercised the full-link state: at 5/5, the existing `active` filter makes the Invite people switch unchecked, so the selector and helper are now absent there too. I moved the existing UI access-change/Undo scenario to the first joined person, while the switch is on, and added an explicit full-link off-state assertion. The existing access-change behavior remains covered without weakening its test.
Author
Owner

#1053 complete

Branch: job/invtoggle-1053
Head SHA: c54f598dbe4783d5b1363ebd1e273cae261734b5
READY FOR MERGE: no — the screenshot set is captured locally but not attached to this issue. The installed scripts/fj exposes text comments only, with no attachment command.

Built

  • The invite access selector and helper text are absent while the Invite people switch is off. Active invite links show access controls with the shared reduced-motion-aware fade.
  • The invite toggle keeps keyboard focus through automatic link copying. The new controls follow it in Tab and screen-reader order, and the access selector describes its helper text.
  • The e2e covers the off, active, and full-link states, then verifies the existing access-change and Undo flow while the switch is on.

Files

  • apps/web/src/lib/files/InviteLinkSection.svelte
  • apps/web/src/lib/files/InviteLinkSection.svelte.test.ts
  • apps/web/e2e/invite-1035.mjs
  • packages/ui/src/clipboard.ts

Commits: 312571be2, 62f04d525, c54f598db.

UX gaps closed

  • Off-state invite controls no longer enter keyboard or screen-reader order.
  • The selector is labelled and describes the helper text.
  • Space activation retains focus while the link is created and copied; Tab reaches the invite URL, Copy invite link, then access selector.
  • Screenshots cover macOS-emulated Chromium at 390, 820 and 1440 px in light and dark, for off, active and full states.

UX gaps left

  • Screenshots are in artifacts/invite-1035/ and are not committed. Attach them for visual review.

Decisions

  • The toggle still creates and copies the first Invite link in one action, per DESIGN §54. Its initial access follows the Share dialog's existing access selection; the owner can change access on the active link.
  • Full, expired and revoked links have no active invite state, so their access selector and helper are hidden with the unchecked switch.

Gates

bun run check:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/invtoggle-1053/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

bunx vitest run src/lib/files/InviteLinkSection.svelte.test.ts src/lib/clipboard.test.ts --maxWorkers=2:

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/invtoggle-1053/apps/web

 Test Files  2 passed (2)
      Tests  4 passed (4)
   Start at  18:26:15
   Duration  27.98s (transform 85%, environment 6%, import 6%, tests 1%, setup 1%)

  Transform  |component| transforming modules took 22.13s · 80% of tracked time, re-done on every run
             persist transforms across runs with fsModuleCache: true
             learn more at https://vitest.dev/guide/improving-performance#caching-between-reruns

CALTERNAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" TMPDIR="$PWD/../../target/tmp" bun e2e/invite-1035.mjs --notes:

invite-1035: 5 Guests granted one item; sixth refused; revocation preserves grants; policy hides invite tick; Chromium + WebKit evidence captured

Cleanup: cargo clean removed 7,238 files (4.6 GiB); apps/web/build and apps/web/.svelte-kit were deleted. The worktree is clean.

#1053 complete Branch: `job/invtoggle-1053` Head SHA: `c54f598dbe4783d5b1363ebd1e273cae261734b5` READY FOR MERGE: no — the screenshot set is captured locally but not attached to this issue. The installed `scripts/fj` exposes text comments only, with no attachment command. ## Built - The invite access selector and helper text are absent while the Invite people switch is off. Active invite links show access controls with the shared reduced-motion-aware fade. - The invite toggle keeps keyboard focus through automatic link copying. The new controls follow it in Tab and screen-reader order, and the access selector describes its helper text. - The e2e covers the off, active, and full-link states, then verifies the existing access-change and Undo flow while the switch is on. ## Files - `apps/web/src/lib/files/InviteLinkSection.svelte` - `apps/web/src/lib/files/InviteLinkSection.svelte.test.ts` - `apps/web/e2e/invite-1035.mjs` - `packages/ui/src/clipboard.ts` Commits: `312571be2`, `62f04d525`, `c54f598db`. ## UX gaps closed - Off-state invite controls no longer enter keyboard or screen-reader order. - The selector is labelled and describes the helper text. - Space activation retains focus while the link is created and copied; Tab reaches the invite URL, Copy invite link, then access selector. - Screenshots cover macOS-emulated Chromium at 390, 820 and 1440 px in light and dark, for off, active and full states. ## UX gaps left - Screenshots are in `artifacts/invite-1035/` and are not committed. Attach them for visual review. ## Decisions - The toggle still creates and copies the first Invite link in one action, per DESIGN §54. Its initial access follows the Share dialog's existing access selection; the owner can change access on the active link. - Full, expired and revoked links have no active invite state, so their access selector and helper are hidden with the unchecked switch. ## Gates `bun run check`: ```text $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/invtoggle-1053/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` `bunx vitest run src/lib/files/InviteLinkSection.svelte.test.ts src/lib/clipboard.test.ts --maxWorkers=2`: ```text RUN v5.0.1 /home/kayg/Developer/calternal-wt/invtoggle-1053/apps/web Test Files 2 passed (2) Tests 4 passed (4) Start at 18:26:15 Duration 27.98s (transform 85%, environment 6%, import 6%, tests 1%, setup 1%) Transform |component| transforming modules took 22.13s · 80% of tracked time, re-done on every run persist transforms across runs with fsModuleCache: true learn more at https://vitest.dev/guide/improving-performance#caching-between-reruns ``` `CALTERNAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" TMPDIR="$PWD/../../target/tmp" bun e2e/invite-1035.mjs --notes`: ```text invite-1035: 5 Guests granted one item; sixth refused; revocation preserves grants; policy hides invite tick; Chromium + WebKit evidence captured ``` Cleanup: `cargo clean` removed 7,238 files (4.6 GiB); `apps/web/build` and `apps/web/.svelte-kit` were deleted. The worktree is clean.
Author
Owner

Correction to the final report: the visual evidence is now attached to #1053, so the earlier READY FOR MERGE: no is superseded. mono is light mode and noir is dark mode. Each link opens the macOS-emulated Chromium screenshot for that state and width.

State Light Dark
Invite off 390 · 820 · 1440 390 · 820 · 1440
Invite active 390 · 820 · 1440 390 · 820 · 1440
Invite full (5/5) 390 · 820 · 1440 390 · 820 · 1440

READY FOR MERGE: yes.

Correction to the final report: the visual evidence is now attached to #1053, so the earlier `READY FOR MERGE: no` is superseded. `mono` is light mode and `noir` is dark mode. Each link opens the macOS-emulated Chromium screenshot for that state and width. | State | Light | Dark | | --- | --- | --- | | Invite off | [390](https://git.kayg.org/attachments/129dfeb9-72ab-48f5-9fd4-9fa96e998c4b) · [820](https://git.kayg.org/attachments/b5c046eb-2857-49a7-9eeb-133440068597) · [1440](https://git.kayg.org/attachments/ee947145-eff5-406b-a63f-a98f8f662c86) | [390](https://git.kayg.org/attachments/45817077-12b4-4d41-9847-77b231629606) · [820](https://git.kayg.org/attachments/5384aaa2-13ba-4c31-ac3b-b66a1dacf546) · [1440](https://git.kayg.org/attachments/02781ac5-4b3a-42aa-a1cc-b38859c0196f) | | Invite active | [390](https://git.kayg.org/attachments/1e7d7cb2-f4e2-4ebc-8388-8005e038f0e8) · [820](https://git.kayg.org/attachments/1bd367ae-6448-4c35-a7f9-700673ff8241) · [1440](https://git.kayg.org/attachments/a9904661-4c7b-4da7-a1a5-9b64fd9c302d) | [390](https://git.kayg.org/attachments/81ba611a-cf81-497d-939b-0fa689e0c531) · [820](https://git.kayg.org/attachments/b1cf566d-d02b-4dfc-b9d5-daa27915a063) · [1440](https://git.kayg.org/attachments/f3f000bd-8d96-4a17-946e-b070c016e174) | | Invite full (5/5) | [390](https://git.kayg.org/attachments/0fc711e8-a46c-4531-a25d-f48148751c4b) · [820](https://git.kayg.org/attachments/f6c57df5-0cef-42f5-8b2f-273322014cf2) · [1440](https://git.kayg.org/attachments/fc6d658c-f824-457f-8639-45717c39e02e) | [390](https://git.kayg.org/attachments/4bb7541b-d1ae-4bf4-8076-f44b9d9a9ae3) · [820](https://git.kayg.org/attachments/f7dfec47-c9e2-4645-a73a-e22ea149095e) · [1440](https://git.kayg.org/attachments/55d98827-7f4e-4608-a493-e672cc50ed92) | READY FOR MERGE: yes.
Author
Owner

Merged in 3e2eb7bcd. InviteLinkSection.svelte.test.ts passes (1 test), covering Space activation, the enabled access control, a 44 px shared toggle target, and retained focus. Invite end-to-end and visual evidence remain in the merge-round run.

Merged in `3e2eb7bcd`. `InviteLinkSection.svelte.test.ts` passes (1 test), covering Space activation, the enabled access control, a 44 px shared toggle target, and retained focus. Invite end-to-end and visual evidence remain in the merge-round run.
Author
Owner

Merge-round 8 completed at 2b6c77c14be78e7d1e1030e23b14c63a6772fca7; #1053 is integrated with the app-update, PDF, NFC/NFD search and Notes idle changes. READY FOR STAGING: yes.

Invite access behavior and invite-1035 --notes passed:

COMPLETED #1035 scenarios and Chromium + WebKit screenshot capture
invite-1035: 5 Guests granted one item; sixth refused; revocation preserves grants; policy hides invite tick; Chromium + WebKit evidence captured

The Share dialog invite section has evidence for 390/820/1440 px in light and dark, empty/created/policy states, Chromium and WebKit. Total invite captures: 78 PNGs under artifacts/invite-1035/ (ignored, not committed). API classification also passed: 392 operations, 1101 tools, 47 admin operations reviewed.

Merge-round web gates: svelte-check found 0 errors and 4 warnings in 3 files; Test Files 224 passed (224), Tests 1517 passed (1517); editor Test Files 21 passed (21), Tests 433 passed (433). Rust fmt, clippy and per-crate tests passed for all affected crates.

UX gaps closed: the grant toggle refuses a sixth Guest, preserves grants on revocation, and hides the invite tick when policy disallows it. The primary action, refusal and revocation were exercised in e2e. Screenshots were not uploaded because scripts/fj issue has no attachment command.

Merge-round 8 completed at `2b6c77c14be78e7d1e1030e23b14c63a6772fca7`; #1053 is integrated with the app-update, PDF, NFC/NFD search and Notes idle changes. READY FOR STAGING: yes. Invite access behavior and `invite-1035 --notes` passed: ``` COMPLETED #1035 scenarios and Chromium + WebKit screenshot capture invite-1035: 5 Guests granted one item; sixth refused; revocation preserves grants; policy hides invite tick; Chromium + WebKit evidence captured ``` The Share dialog invite section has evidence for 390/820/1440 px in light and dark, empty/created/policy states, Chromium and WebKit. Total invite captures: 78 PNGs under `artifacts/invite-1035/` (ignored, not committed). API classification also passed: 392 operations, 1101 tools, 47 admin operations reviewed. Merge-round web gates: `svelte-check found 0 errors and 4 warnings in 3 files`; `Test Files 224 passed (224)`, `Tests 1517 passed (1517)`; editor `Test Files 21 passed (21)`, `Tests 433 passed (433)`. Rust fmt, clippy and per-crate tests passed for all affected crates. UX gaps closed: the grant toggle refuses a sixth Guest, preserves grants on revocation, and hides the invite tick when policy disallows it. The primary action, refusal and revocation were exercised in e2e. Screenshots were not uploaded because `scripts/fj issue` has no attachment command.
Author
Owner

Deployed to production 2026-10-05 03:12 CEST in round 8 (2b6c77c14). Staging healthy first; production healthy in 33 s; /api/v1/version reports the build ID; change events 0/30 s.

Deployed to production 2026-10-05 03:12 CEST in round 8 (2b6c77c14). Staging healthy first; production healthy in 33 s; `/api/v1/version` reports the build ID; change events 0/30 s.
kayg closed this issue 2026-10-05 01:13:51 +00:00
Sign in to join this conversation.
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
kayg/calternal#1053
No description provided.