diff --git a/.agents/skills/flotilla-state/SKILL.md b/.agents/skills/flotilla-state/SKILL.md index 846ebef0..72c94387 100644 --- a/.agents/skills/flotilla-state/SKILL.md +++ b/.agents/skills/flotilla-state/SKILL.md @@ -245,7 +245,7 @@ A derivation that every row subscribes to, or that joins large sets, is built by | repository, tracker, relays, relay stats, handles, zappers, plaintext, wraps | IndexedDB | yes | deleted | | settings (`SettingsValues`) | an encrypted app-data event, cached in IndexedDB | yes | local copy deleted | | `session`, `wallet` | `ss` | no | cleared | -| `theme`, `flTheme`, `checked`, `shouldUnwrap`, `device`, `notificationSettings`, push state | `kv` | no | cleared | +| `theme`, `flTheme`, `checked`, `shouldUnwrap`, `device`, `notificationSettings`, push state, `needsKeyBackup` | `kv` | no | cleared | | drafts, dictations | a module `Map`, lost on reload | no | page reloads | ### IndexedDB (`src/app/storage.ts`, `src/lib/indexeddb.ts`) @@ -284,8 +284,8 @@ anything in them outlives a login and is cleared only by logout. Secrets go in ` default first, and the stored value arrives later (`.ready`). `theme` and `flTheme` (`theme.ts`), `checked` (`notifications.ts`) and `shouldUnwrap` (`sync.ts`) use it. - `sync({key, store, storage})` binds a store that already exists. The root layout awaits it - for `device`, `wallet`, `notificationSettings` and `pushState` before first render, so boot - code sees the restored values. It also binds `shouldUnwrap`, which `synced` already persists. + for `device`, `wallet`, `notificationSettings`, `pushState` and `needsKeyBackup` before first + render, so boot code sees the restored values. It also binds `shouldUnwrap`, which `synced` already persists. Raw `localStorage` holds only `theme`, `fl-theme` and `font-size`. The root layout mirrors them there to apply them synchronously before `kv` loads, which avoids a flash of the wrong theme. diff --git a/src/app/components/HealthCheckItem.svelte b/src/app/components/HealthCheckItem.svelte index 9d8d879d..352f34fb 100644 --- a/src/app/components/HealthCheckItem.svelte +++ b/src/app/components/HealthCheckItem.svelte @@ -2,27 +2,22 @@ import Stars from "@assets/icons/stars.svg?dataurl" import Icon from "@lib/components/Icon.svelte" import Button from "@lib/components/Button.svelte" - import type {HealthCheck} from "@app/healthChecks" - import {healthChecks, reviewPlans} from "@app/healthChecks" type Props = { - healthCheck: HealthCheck + title: string + description: string + onfix: () => void } - const {healthCheck}: Props = $props() - - const start = () => reviewPlans([$healthChecks.plan(healthCheck)]) + const {title, description, onfix}: Props = $props() -
+
- {healthCheck.title} -

{healthCheck.description}

+ {title} +

{description}

- diff --git a/src/app/components/HealthCheckReview.svelte b/src/app/components/HealthCheckReview.svelte index dd254060..89dac60c 100644 --- a/src/app/components/HealthCheckReview.svelte +++ b/src/app/components/HealthCheckReview.svelte @@ -1,6 +1,8 @@ @@ -53,7 +59,7 @@ Review changes Nothing changes until you confirm. - {#each publishing as plan (plan.summary)} + {#each plans as plan (plan.summary)}

{plan.summary}

{#each plan.changes as change (change.label)} diff --git a/src/app/components/HomeHealthChecks.svelte b/src/app/components/HomeHealthChecks.svelte index d2e24744..b01584b2 100644 --- a/src/app/components/HomeHealthChecks.svelte +++ b/src/app/components/HomeHealthChecks.svelte @@ -7,20 +7,51 @@ import Button from "@lib/components/Button.svelte" import HomeSection from "@app/components/HomeSection.svelte" import HealthCheckItem from "@app/components/HealthCheckItem.svelte" - import {healthChecks, reviewPlans} from "@app/healthChecks" + import HealthCheckReview from "@app/components/HealthCheckReview.svelte" + import KeyDownload from "@app/components/KeyDownload.svelte" + import type {HealthCheck} from "@app/healthChecks" + import {healthChecks, needsKeyBackup} from "@app/healthChecks" + import {session} from "@app/core" + import {pushModal} from "@app/modal" const pending = $healthChecks.pending.$ - const reviewAll = () => reviewPlans($pending.map(check => $healthChecks.plan(check))) + const count = $derived($pending.length + ($needsKeyBackup ? 1 : 0)) + + const finishKeyBackup = () => { + needsKeyBackup.set(false) + history.back() + } + + const backUpKey = () => + pushModal(KeyDownload, { + secret: ($session!.data as {secret: string}).secret, + next: finishKeyBackup, + submitText: "Done", + }) + + const review = (checks: HealthCheck[], next?: () => void) => { + const plans = checks + .map(check => $healthChecks.plan(check)) + .filter(plan => plan.changes.length > 0) + + if (plans.length > 0) { + pushModal(HealthCheckReview, {plans, next}) + } else { + next?.() + } + } + + const reviewAll = () => review($pending, $needsKeyBackup ? backUpKey : undefined) {#snippet action()} - {#if $pending.length > 0} - {$pending.length} open + {#if count > 0} + {count} open {/if} {/snippet} - {#if $pending.length === 0} + {#if count === 0}

Your connection to the network looks healthy. @@ -28,9 +59,18 @@ {:else}

{#each $pending as healthCheck (healthCheck.id)} - + review([healthCheck])} /> {/each} - {#if $pending.length > 1} + {#if $needsKeyBackup} + + {/if} + {#if count > 1}