refactor(ui): strip non-functional Settings stubs, wire real data#97
Merged
Conversation
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.
9 tasks
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
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
onchange, no real data source, hardcoded marketing copy). Net diff is-708 / +355insettings.rs— most of the change is deletion.IdentityBackupflow already inapp/login.rs, the realfreenet_aft_interface::Tierenum, andwindow.location.host.What got stripped (was rendering, did nothing)
Tier).What got wired
freenet-identity-{alias}.jsonvia the sameIdentityBackup::from_identity+trigger_browser_downloadpath that powers the login screen, then stampslast_backup_at(Unix millis) on the identity's settings bucket. The amber "not backed up" banner reads from the same field.ImportBackupmodal signal — no duplicate parser.role="listbox") of every identity on the device. Click switchesUser.set_logged_id+InboxView.set_active_id.freenet_aft_interface::Tiervalues with rate strings derived from the tier name (1 / minute,1 / day,1 / year). Replaced the redundant required-tier select.address_book::all_contacts()with live search filter (alias / fingerprint / description). Remove button is real. Import / Share reuse the topbar modals.window.location.hostso 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_tierchanged from"Mid1"(never existed inTier) 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,SharePendingData→pub(crate).Test plan
cargo test -p mail-local-state --lib— 18 passed (1 newidentity_settings_missing_last_backup_defaults_none, 1 updated round-trip).cargo test --workspace— all green.cargo build -p freenet-email-ui(defaultuse-node).cargo build -p freenet-email-ui --features example-data,no-sync --no-default-features.cargo make build-mail-local-state-delegate— new code hash5Yru13ZTp29f4wNXjPfH2Y1gxzduk1YrAwSTCCLxmWRz.cargo make clippy,cargo fmt --all -- --check.dev-example: gear → Account → "Back up now" downloads JSON, banner disappears, Last backup shows timestamp.dev-example: caret → switcher popover lists both example identities, click switches active id, alias + fingerprint pill update, mailbox refreshes.dev-example: ScrContacts after import: search box filters, Remove deletes from address book.