App Passwords UI: shared select and date picker, input surface token, one sheet title #377

Closed
opened 2026-09-28 23:04:41 +00:00 by kayg · 7 comments
Owner

UI follow-ups from Claude's review of #328 (App Passwords scopes)

  1. Native controls: "Scope preset" is a native <select> and "Expires" a native datetime-local input. CLAUDE.md: never invent basic UI; use the shared Select/Menu (bits-ui headless, calternal.js styling) and the shared date/time picker used elsewhere (Calendar/composer). If none exists yet for date+time, port it from calternal.js first.
  2. Dark inputs are pure black (#000-looking fields on the glass card). Inputs use the shared input surface token (one step lighter than the card, as in Mail settings).
  3. Phone sheet shows "App Passwords" twice: the sheet header title and a faded copy of the section title under it. Same rule as #369: in a single-section sheet the section header is dropped.
  4. The app-passwords e2e must attach its screenshots to the issue (the job could not: scripts/fj has no attachment command; use the Forgejo API asset upload like other jobs do).

Screenshots at 390/820/1440 light and dark.

## UI follow-ups from Claude's review of #328 (App Passwords scopes) 1. **Native controls:** "Scope preset" is a native `<select>` and "Expires" a native `datetime-local` input. CLAUDE.md: never invent basic UI; use the shared Select/Menu (bits-ui headless, calternal.js styling) and the shared date/time picker used elsewhere (Calendar/composer). If none exists yet for date+time, port it from calternal.js first. 2. **Dark inputs are pure black** (#000-looking fields on the glass card). Inputs use the shared input surface token (one step lighter than the card, as in Mail settings). 3. **Phone sheet shows "App Passwords" twice:** the sheet header title and a faded copy of the section title under it. Same rule as #369: in a single-section sheet the section header is dropped. 4. The app-passwords e2e must attach its screenshots to the issue (the job could not: `scripts/fj` has no attachment command; use the Forgejo API asset upload like other jobs do). Screenshots at 390/820/1440 light and dark.
Author
Owner

Starting #377 on branch job/app-pw-ui, based on dev at 45315bb9e9d8577d843ea24909014baa6a7b954d.

Initial finding: AppPasswordsGroup.svelte uses native <select> controls for every scope field and a native datetime-local expiry input. The reusable app currently has no Select component under packages/ui; I am checking the calternal.js ports and the settings sheet composition before choosing the smallest shared implementation.

Starting #377 on branch `job/app-pw-ui`, based on `dev` at `45315bb9e9d8577d843ea24909014baa6a7b954d`. Initial finding: `AppPasswordsGroup.svelte` uses native `<select>` controls for every scope field and a native `datetime-local` expiry input. The reusable app currently has no `Select` component under `packages/ui`; I am checking the calternal.js ports and the settings sheet composition before choosing the smallest shared implementation.
Author
Owner

Reuse/design finding: packages/ui has no Select component, but its shared Menu supports checked radio items and keyboard navigation. The app also has a FieldPopover already ported from calternal.js composer date/time pickers, with a shared floating surface, but it has no combined mode. I will add a small Select wrapper over Menu, extend FieldPopover to show date and time together, and alias the input surface token to --glass-card-inner-bg. The app-password group heading will stay available for its deep link and accessible name while hidden visually inside the single-section phone sheet; the sheet header already owns the Copy link action.

Reuse/design finding: `packages/ui` has no Select component, but its shared `Menu` supports checked radio items and keyboard navigation. The app also has a `FieldPopover` already ported from calternal.js composer date/time pickers, with a shared floating surface, but it has no combined mode. I will add a small `Select` wrapper over `Menu`, extend `FieldPopover` to show date and time together, and alias the input surface token to `--glass-card-inner-bg`. The app-password group heading will stay available for its deep link and accessible name while hidden visually inside the single-section phone sheet; the sheet header already owns the Copy link action.
Author
Owner

Build setup finding: bun run build stopped before compiling because vite is not installed in this worktree (vite: command not found). I am restoring only the locked workspace dependencies with bun install --frozen-lockfile; no dependency version change is planned.

Build setup finding: `bun run build` stopped before compiling because `vite` is not installed in this worktree (`vite: command not found`). I am restoring only the locked workspace dependencies with `bun install --frozen-lockfile`; no dependency version change is planned.
Author
Owner

Test-first evidence: the real-server production-build E2E reached App Passwords, opened the form, then failed the new assertion because it found one native <select> (1 !== 0). This confirms the reported native scope control is present before the fix. The server binary is now built at the job target path for the green run and screenshots.

Test-first evidence: the real-server production-build E2E reached App Passwords, opened the form, then failed the new assertion because it found one native `<select>` (`1 !== 0`). This confirms the reported native scope control is present before the fix. The server binary is now built at the job target path for the green run and screenshots.
Author
Owner

Second red check: the real-server E2E independently found one input[type=datetime-local] after opening the form (1 !== 0). The shared FieldPopover now has a combined date/time mode. Its unit test passes and verifies that Save returns both local fields together.

Second red check: the real-server E2E independently found one `input[type=datetime-local]` after opening the form (`1 !== 0`). The shared FieldPopover now has a combined date/time mode. Its unit test passes and verifies that Save returns both local fields together.
Author
Owner

Screenshot guard finding: the production E2E captured 1440 light/dark and 820 light, then stopped at 820 dark because the touch context still had html.is-dark === false after media emulation. No 820 dark screenshot was saved. I am changing capture setup to assert and apply the requested appearance state before each image.

Screenshot guard finding: the production E2E captured 1440 light/dark and 820 light, then stopped at 820 dark because the touch context still had `html.is-dark === false` after media emulation. No 820 dark screenshot was saved. I am changing capture setup to assert and apply the requested appearance state before each image.
Author
Owner

Implemented and pushed on job/app-pw-ui.

Head: e06a6b9d929f8d420405f521eae5d78d2d073312

Changes: added a shared menu-backed Select; changed App Passwords scope and access controls to use it; replaced datetime-local with the shared FieldPopover date/time editor; applied the input surface token to settings fields; hid the duplicate section heading in the single-group phone sheet; added real-server E2E assertions and light/dark screenshot capture. Added focused FieldPopover tests. No API behavior changed.

Screenshots from the final production build and E2E run:

Final production E2E output:

app password e2e: calendar profiles, scoped PhotoSync access, and responsive settings passed

Gate results:

  • cargo fmt --check: exit 0, no output.
  • cargo clippy --all-targets -- -D warnings:
Finished `dev` profile [unoptimized + debuginfo] target(s) in 25m 13s
  • bun run check (run before the final shared formatter-helper correction):
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/app-pw-ui/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings
  • Focused post-correction formatter test:
Test Files  1 passed (1)
     Tests  3 passed (3)
  • The one full bun run test run failed before the formatter-helper correction at src/lib/date-formatting.test.ts; the final code now uses the shared UI formatters, and the focused test above passed. The full suite was not rerun.
  • The one cargo test run had these unrelated calternal-cli loopback failures:
test result: FAILED. 12 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in 26.85s
error: test failed, to rerun pass `-p calternal-cli --test output_contract`

Follow-up issue: #389.

  • One adversarial round reported FINDINGS 234; the SLOW findings were treated as load. Non-SLOW items were filed for review in #387. No existing API test expectations were changed.

Decisions where the design docs were silent: the existing shared FieldPopover owns date/time editing and uses native date/time input primitives internally; an empty expiry starts at local time +15 minutes when opened and is saved only by the explicit Save action. The single-group phone sheet keeps its sheet title and hides only the repeated section title.

Implemented and pushed on `job/app-pw-ui`. Head: `e06a6b9d929f8d420405f521eae5d78d2d073312` Changes: added a shared menu-backed Select; changed App Passwords scope and access controls to use it; replaced `datetime-local` with the shared `FieldPopover` date/time editor; applied the input surface token to settings fields; hid the duplicate section heading in the single-group phone sheet; added real-server E2E assertions and light/dark screenshot capture. Added focused `FieldPopover` tests. No API behavior changed. Screenshots from the final production build and E2E run: - 390 light: https://git.kayg.org/attachments/577e44e8-6159-4652-acbe-980e09a115f8 - 390 dark: https://git.kayg.org/attachments/83e8a879-8e85-4e00-a2e5-efcdae8b4680 - 820 light: https://git.kayg.org/attachments/d9014079-9b56-4fcf-96d6-a1b90aae6301 - 820 dark: https://git.kayg.org/attachments/534e77f5-c12f-474c-8457-e85b8a5baf8d - 1440 light: https://git.kayg.org/attachments/d2b0469b-43fc-433d-b707-2d9def3ad7f4 - 1440 dark: https://git.kayg.org/attachments/4aef93ce-cfac-4509-aa08-9da773d48a6c Final production E2E output: ```text app password e2e: calendar profiles, scoped PhotoSync access, and responsive settings passed ``` Gate results: - `cargo fmt --check`: exit 0, no output. - `cargo clippy --all-targets -- -D warnings`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 25m 13s ``` - `bun run check` (run before the final shared formatter-helper correction): ```text Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/app-pw-ui/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` - Focused post-correction formatter test: ```text Test Files 1 passed (1) Tests 3 passed (3) ``` - The one full `bun run test` run failed before the formatter-helper correction at `src/lib/date-formatting.test.ts`; the final code now uses the shared UI formatters, and the focused test above passed. The full suite was not rerun. - The one `cargo test` run had these unrelated `calternal-cli` loopback failures: ```text test result: FAILED. 12 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in 26.85s error: test failed, to rerun pass `-p calternal-cli --test output_contract` ``` Follow-up issue: #389. - One adversarial round reported `FINDINGS 234`; the SLOW findings were treated as load. Non-SLOW items were filed for review in #387. No existing API test expectations were changed. Decisions where the design docs were silent: the existing shared `FieldPopover` owns date/time editing and uses native date/time input primitives internally; an empty expiry starts at local time +15 minutes when opened and is saved only by the explicit Save action. The single-group phone sheet keeps its sheet title and hides only the repeated section title.
kayg closed this issue 2026-09-29 04:09:04 +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#377
No description provided.