Skip to content

refactor(ui): strip non-functional Settings stubs, wire real data#97

Merged
iduartgomez merged 1 commit into
mainfrom
ui-settings-strip-stubs
May 3, 2026
Merged

refactor(ui): strip non-functional Settings stubs, wire real data#97
iduartgomez merged 1 commit into
mainfrom
ui-settings-strip-stubs

Conversation

@iduartgomez
Copy link
Copy Markdown
Contributor

Summary

  • Remove every Settings control that was rendering but not actually doing anything (no onchange, no real data source, hardcoded marketing copy). Net diff is -708 / +355 in settings.rs — most of the change is deletion.
  • Wire the screens that remain to real sources: address book, current identity list, the IdentityBackup flow already in app/login.rs, the real freenet_aft_interface::Tier enum, and window.location.host.
  • Implement the identity switcher popover, backup, restore, and backup-status banner flows the user explicitly asked for.

What got stripped (was rendering, did nothing)

Screen Removed
ScrAft Quota meter, 7-day sparkline, "Notify at" / "Edit thresholds" row, marketing tier copy, the invented 4-tier picker (Min1/Min2/Mid1/Mid2 — none in Tier).
ScrAccount "Show full key", "Copy", "Show QR", "Rotate" buttons; key-card footer; Danger Zone card.
ScrPrivacy "Auto-accept new keys" select; "Identity delegate refresh" card.
ScrInbox Auto-archive / Sent retention / Quarantine retention / Save drafts every / Default reply selects (all no-op).
ScrAppearance "UI font size" select.
ScrAdvanced 8-line fake diagnostics terminal; hardcoded "14.2 MB / 80 MB" storage row; Reconnect / Clear cache / Copy report buttons; Factory Reset Danger Zone.
ScrContacts 5-row hardcoded contact list; "All trust levels" filter; "Trust on first message" / "Format for share-my-card" defaults.

What got wired

  • Backup: "Back up now" → downloads freenet-identity-{alias}.json via the same IdentityBackup::from_identity + trigger_browser_download path that powers the login screen, then stamps last_backup_at (Unix millis) on the identity's settings bucket. The amber "not backed up" banner reads from the same field.
  • Restore: "Restore…" closes Settings and flips the existing ImportBackup modal signal — no duplicate parser.
  • Identity switcher: the caret pill in the Settings sidebar is now a real popover (role="listbox") of every identity on the device. Click switches User.set_logged_id + InboxView.set_active_id.
  • AFT tier grid: enumerated from the 15 real freenet_aft_interface::Tier values with rate strings derived from the tier name (1 / minute, 1 / day, 1 / year). Replaced the redundant required-tier select.
  • Contacts: address_book::all_contacts() with live search filter (alias / fingerprint / description). Remove button is real. Import / Share reuse the topbar modals.
  • Advanced: "Page origin" row shows window.location.host so the user sees what the UI is actually connected to. Custom-relay URL input only renders when the toggle is on.

Backward-compat data change

  • IdentityAftPrefs::default().required_tier changed from "Mid1" (never existed in Tier) to "Day1" (real, sane inbox floor).
  • IdentitySettings.last_backup_at: Option<i64> added — #[serde(default)], no breaking change. 1 new round-trip + 1 missing-field test.

Visibility opens

  • User.set_logged_id, InboxView.set_active_id, IdentityBackup, trigger_browser_download, ImportBackup, ShareContact, ImportContact, SharePending, SharePendingDatapub(crate).

Test plan

  • cargo test -p mail-local-state --lib — 18 passed (1 new identity_settings_missing_last_backup_defaults_none, 1 updated round-trip).
  • cargo test --workspace — all green.
  • cargo build -p freenet-email-ui (default use-node).
  • cargo build -p freenet-email-ui --features example-data,no-sync --no-default-features.
  • cargo make build-mail-local-state-delegate — new code hash 5Yru13ZTp29f4wNXjPfH2Y1gxzduk1YrAwSTCCLxmWRz.
  • cargo make clippy, cargo fmt --all -- --check.
  • Manual dev-example: gear → Account → "Back up now" downloads JSON, banner disappears, Last backup shows timestamp.
  • Manual dev-example: caret → switcher popover lists both example identities, click switches active id, alias + fingerprint pill update, mailbox refreshes.
  • Manual dev-example: ScrContacts after import: search box filters, Remove deletes from address book.

Removes UI controls that don't map to anything persisted or otherwise
functional — they were carried over from the design handoff but were
never going to do anything until separate features land. Wires the
remaining real data sources (address book, identity switcher, backup
flow, AFT tier enum, current WS host) directly into the screens.

Stripped (no-op controls / hardcoded display data):
  - ScrAft: today's quota meter, 7-day sparkline, "Notify at" / "Edit
    thresholds" row, the marketing tier copy ("Mid1 = Heavy use…").
  - ScrAft: invented 4-tier picker (Min1/Min2/Mid1/Mid2 — none of
    those exist in `freenet_aft_interface::Tier`).
  - ScrAccount: "Show full key", "Copy", "Show QR", "Rotate" buttons
    on the key cards; "Last verified" / "rotates never" footer; the
    Danger Zone card (delete identity needs a confirm modal).
  - ScrPrivacy: "Auto-accept new keys" select; "Identity delegate
    refresh" card.
  - ScrInbox: "Auto-archive after", "Sent retention", "Auto-delete
    from Quarantine after", "Save drafts every", "Default reply
    behavior" — all selects with no onchange.
  - ScrAppearance: "UI font size" select.
  - ScrAdvanced: 8-line fake diagnostics terminal, hardcoded
    "14.2 MB / 80 MB" storage row, "Reconnect" / "Clear cache" /
    "Copy report" buttons, "Factory reset" Danger Zone.
  - ScrContacts: 5-row hardcoded contact list, "All trust levels"
    filter (no logic), "Trust on first message" / "Format for
    share-my-card" defaults.

Wired (real data plumbed in):
  - ScrAccount backup flow: "Back up now" produces a downloadable
    `freenet-identity-{alias}.json` via the same code path that
    powers the login-screen export, then stamps `last_backup_at` on
    the per-identity Settings bucket so the amber banner stops
    showing. "Last backup" row renders the timestamp.
  - ScrAccount restore: "Restore…" closes Settings and opens the
    existing `ImportBackup` modal — no second copy of the parser.
  - ScrAft tier grid: enumerated from the real
    `freenet_aft_interface::Tier` set (Min1 / Min5 / Min10 / Min30 /
    Hour1 / Hour3 / Hour6 / Hour12 / Day1 / Day7 / Day15 / Day30 /
    Day90 / Day180 / Day365), each row showing the rate string
    derived from the tier name. The earlier "Required tier" select
    is gone — the grid is the single source.
  - `IdentityAftPrefs::default().required_tier` updated from `"Mid1"`
    (which never existed) to `"Day1"` (real, sane inbox floor).
  - `IdentitySettings.last_backup_at: Option<i64>` added (additive,
    `#[serde(default)]`); 1 new round-trip + 1 missing-field test.
  - ScrContacts: list comes from `address_book::all_contacts()`,
    filtered live by the search input against alias / fingerprint /
    description. Remove buttons call `address_book::remove_contact`.
    Import / Share buttons reuse the existing topbar modal flow
    (closes Settings, flips `ImportContact` / `ShareContact` +
    `SharePending` signals).
  - ScrAdvanced: "Page origin" row reads `window.location.host` so
    you see what the UI is actually talking to. Custom-relay URL
    input only renders when the toggle is on.
  - SettingsShell: identity pill (caret) is now an actual switcher
    popover — opens a listbox of every identity on the device,
    click switches the active id (writes both `User.set_logged_id`
    and `InboxView.set_active_id`).

API: `User.set_logged_id`, `InboxView.set_active_id`,
`IdentityBackup`, `trigger_browser_download`, `ImportBackup`,
`ShareContact`, `ImportContact`, `SharePending`,
`SharePendingData` are now `pub(crate)` so the settings module can
reach them. No new dependencies.
@iduartgomez iduartgomez merged commit 51c6e82 into main May 3, 2026
4 checks passed
iduartgomez added a commit that referenced this pull request May 3, 2026
Removes UI controls that don't map to anything persisted or otherwise
functional — they were carried over from the design handoff but were
never going to do anything until separate features land. Wires the
remaining real data sources (address book, identity switcher, backup
flow, AFT tier enum, current WS host) directly into the screens.

Stripped (no-op controls / hardcoded display data):
  - ScrAft: today's quota meter, 7-day sparkline, "Notify at" / "Edit
    thresholds" row, the marketing tier copy ("Mid1 = Heavy use…").
  - ScrAft: invented 4-tier picker (Min1/Min2/Mid1/Mid2 — none of
    those exist in `freenet_aft_interface::Tier`).
  - ScrAccount: "Show full key", "Copy", "Show QR", "Rotate" buttons
    on the key cards; "Last verified" / "rotates never" footer; the
    Danger Zone card (delete identity needs a confirm modal).
  - ScrPrivacy: "Auto-accept new keys" select; "Identity delegate
    refresh" card.
  - ScrInbox: "Auto-archive after", "Sent retention", "Auto-delete
    from Quarantine after", "Save drafts every", "Default reply
    behavior" — all selects with no onchange.
  - ScrAppearance: "UI font size" select.
  - ScrAdvanced: 8-line fake diagnostics terminal, hardcoded
    "14.2 MB / 80 MB" storage row, "Reconnect" / "Clear cache" /
    "Copy report" buttons, "Factory reset" Danger Zone.
  - ScrContacts: 5-row hardcoded contact list, "All trust levels"
    filter (no logic), "Trust on first message" / "Format for
    share-my-card" defaults.

Wired (real data plumbed in):
  - ScrAccount backup flow: "Back up now" produces a downloadable
    `freenet-identity-{alias}.json` via the same code path that
    powers the login-screen export, then stamps `last_backup_at` on
    the per-identity Settings bucket so the amber banner stops
    showing. "Last backup" row renders the timestamp.
  - ScrAccount restore: "Restore…" closes Settings and opens the
    existing `ImportBackup` modal — no second copy of the parser.
  - ScrAft tier grid: enumerated from the real
    `freenet_aft_interface::Tier` set (Min1 / Min5 / Min10 / Min30 /
    Hour1 / Hour3 / Hour6 / Hour12 / Day1 / Day7 / Day15 / Day30 /
    Day90 / Day180 / Day365), each row showing the rate string
    derived from the tier name. The earlier "Required tier" select
    is gone — the grid is the single source.
  - `IdentityAftPrefs::default().required_tier` updated from `"Mid1"`
    (which never existed) to `"Day1"` (real, sane inbox floor).
  - `IdentitySettings.last_backup_at: Option<i64>` added (additive,
    `#[serde(default)]`); 1 new round-trip + 1 missing-field test.
  - ScrContacts: list comes from `address_book::all_contacts()`,
    filtered live by the search input against alias / fingerprint /
    description. Remove buttons call `address_book::remove_contact`.
    Import / Share buttons reuse the existing topbar modal flow
    (closes Settings, flips `ImportContact` / `ShareContact` +
    `SharePending` signals).
  - ScrAdvanced: "Page origin" row reads `window.location.host` so
    you see what the UI is actually talking to. Custom-relay URL
    input only renders when the toggle is on.
  - SettingsShell: identity pill (caret) is now an actual switcher
    popover — opens a listbox of every identity on the device,
    click switches the active id (writes both `User.set_logged_id`
    and `InboxView.set_active_id`).

API: `User.set_logged_id`, `InboxView.set_active_id`,
`IdentityBackup`, `trigger_browser_download`, `ImportBackup`,
`ShareContact`, `ImportContact`, `SharePending`,
`SharePendingData` are now `pub(crate)` so the settings module can
reach them. No new dependencies.
@iduartgomez iduartgomez deleted the ui-settings-strip-stubs branch May 23, 2026 07:34
iduartgomez added a commit that referenced this pull request May 23, 2026
…t verify-on-send off (#262)

Three related fixes to the Import/Share contact modals reachable from
Settings → Contacts (the .fm-app scope):

1. Form fields rendered unstyled in the inbox view. The modal markup
   uses .field/.input/.textarea/.verify-words*/.token-block/.verify-check*
   classes that only existed under login.css @scope (.fm-pre). The
   Settings → Contacts render site lives under @scope (.fm-app), where
   only .veil/.modal-* were mirrored, so labels rendered inline-left of
   inputs and the textarea overlapped its label. Mirror the missing
   rules into settings.css's .fm-app block.

2. Opening Import/Share called close_settings() first (from #97, before
   the modal CSS worked in .fm-app), dropping the background to the
   inbox. Remove that so the modal overlays the Contacts panel instead.

3. "Require known key to send" (verify_on_send) now defaults off — it
   was blocking sends to any not-yet-verified contact out of the box.

Comments in the live-node / repro Playwright specs and the QA inventory
updated to reflect the new default (tests still tick verify explicitly,
so behavior is unchanged).
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