f38052979d35
polish Sync layout and migration notices (v5.2.50)
- time
- 2026-09-12 00:12 UTC · 1 month ago
- machine
- koh2
- agent
- camel-stream/auto
- session
- sync screen polish
- parent
- 8e6d7effbebe
↓ peach-browser-f3805297.tar.gzatlas at this save
files changed4 files
src/popup/views/Settings.tsx+30 −34src/popup/views/contracts.test.tsx+5 −0src/shared/release-notes.test.ts+12 −9src/shared/release-notes.ts+2 −2src/popup/views/Settings.tsx+30 −34
@@ -255,7 +255,7 @@255255 id: "sync",256256 num: "IV · ECHO",257257 title: "Sync",258- lede: isPro() ? "your devices, one vault" : "Pro · encrypted device sync",258+ lede: isPro() ? "End to End Encryption" : "Pro · encrypted device sync",259259 bgVar: "--stack-sync-bg",260260 fgVar: "--stack-sync-fg",261261 icon: "sync",@@ -1738,22 +1738,18 @@17381738 <span class="peach-settings-value" style="color:var(--peach-t2);line-height:1.5;flex:1;min-width:0;overflow-wrap:anywhere">17391739 {syncFlash() ?? lastSyncLine()}17401740 </span>1741- </div>1742- <Show when={pairedDevices().length > 0}>1743- <div class="peach-settings-row peach-settings-row--meta">1744- <span class="peach-settings-value" style="color:var(--peach-t2)">1745- {(syncSummary().entriesSent ?? 0) + (syncSummary().entriesReceived ?? 0) > 01746- ? `${syncSummary().entriesSent ?? 0} sent · ${syncSummary().entriesReceived ?? 0} received`1747- : ""}1748- </span>1741+ {/* The transfer counts already ride in the status line, so this row1742+ was an empty flex sibling in every other case: it read as a dead1743+ gap and held the button away from the status it belongs to. */}1744+ <Show when={pairedDevices().length > 0}>17491745 <button17501746 class="peach-btn peach-btn--subtle peach-btn--sm"17511747 aria-label="Sync this vault now"17521748 disabled={syncStatus() === "syncing"}17531749 onClick={() => void syncNow()}17541750 >{syncStatus() === "syncing" ? "syncing…" : "sync now"}</button>1755- </div>1756- </Show>1751+ </Show>1752+ </div>17571753 17581754 {/* §11: this panel is a migration call to action, not a permanent17591755 label. On the settled new generation there is nothing left to do@@ -1822,29 +1818,6 @@18221818 </Show>18231819 </Show>18241820 1825- <p class="peach-settings-sub-label">ADD A DEVICE</p>1826- <button1827- class="peach-sync-pair-option"1828- onClick={() => props.onOpenSyncPairing?.("code")}1829- >1830- <span class="peach-sync-pair-option-icon" aria-hidden="true">1831- <svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">1832- <rect x="6" y="2.5" width="8" height="15" rx="1.6" />1833- <path d="M9 15 L11 15" />1834- </svg>1835- </span>1836- <span class="peach-sync-pair-option-main">1837- <span class="peach-sync-pair-option-title">Show a code</span>1838- <span class="peach-sync-pair-option-sub">Scan it with Peach on your phone, then confirm one 8-digit code</span>1839- </span>1840- <span class="peach-sync-pair-option-chevron" aria-hidden="true">›</span>1841- </button>1842- <Show when={!isPro()}>1843- <p class="peach-settings-value" style="font-size:11px;line-height:1.5;color:var(--peach-t2);margin:8px 2px 0">1844- At least one device needs Peach Pro — pair with a Pro device and it carries over to here.1845- </p>1846- </Show>1847-18481821 <Show when={pairedDevices().length > 0}>18491822 <p class="peach-settings-sub-label">PAIRED DEVICES</p>18501823 <For each={pairedDevices()}>@@ -1965,6 +1938,29 @@19651938 </div>19661939 )}19671940 </For>1941+ </Show>1942+1943+ <p class="peach-settings-sub-label">ADD A DEVICE</p>1944+ <button1945+ class="peach-sync-pair-option"1946+ onClick={() => props.onOpenSyncPairing?.("code")}1947+ >1948+ <span class="peach-sync-pair-option-icon" aria-hidden="true">1949+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">1950+ <rect x="6" y="2.5" width="8" height="15" rx="1.6" />1951+ <path d="M9 15 L11 15" />1952+ </svg>1953+ </span>1954+ <span class="peach-sync-pair-option-main">1955+ <span class="peach-sync-pair-option-title">Show a code</span>1956+ <span class="peach-sync-pair-option-sub">Scan it with Peach on your phone, then confirm one 8-digit code</span>1957+ </span>1958+ <span class="peach-sync-pair-option-chevron" aria-hidden="true">›</span>1959+ </button>1960+ <Show when={!isPro()}>1961+ <p class="peach-settings-value" style="font-size:11px;line-height:1.5;color:var(--peach-t2);margin:8px 2px 0">1962+ At least one device needs Peach Pro — pair with a Pro device and it carries over to here.1963+ </p>19681964 </Show>19691965 19701966 <buttonsrc/popup/views/contracts.test.tsx+5 −0
@@ -811,6 +811,11 @@811811 const syncNowButton = container.querySelector<HTMLButtonElement>(812812 'button[aria-label="Sync this vault now"]',813813 )!;814+ const syncStatusRow = syncNowButton.closest(".peach-settings-row--meta");815+ const syncCard = syncNowButton.closest('[data-settings-card-id="sync"]');816+ expect(syncStatusRow).not.toBeNull();817+ expect(syncStatusRow?.contains(syncNowButton)).toBe(true);818+ expect(syncCard?.querySelectorAll(".peach-settings-row--meta")).toHaveLength(1);814819 const labels = Array.from(container.querySelectorAll(".peach-settings-sub-label"));815820 const addDeviceLabel = labels.find((label) => label.textContent?.includes("ADD A DEVICE"))!;816821 const pairedDevicesLabel = labels.find((label) => label.textContent?.includes("PAIRED DEVICES"))!;src/shared/release-notes.test.ts+12 −9
@@ -43,27 +43,30 @@4343 expect(PEACH_VERSION.length).toBeGreaterThan(0);4444 });4545 46- it("keeps sync recovery as its own breaking release", () => {47- const syncRecovery = RELEASES.find((release) =>48- release.notes.some((note) => {49- const body = note.body.toLowerCase();50- return body.includes("revoke") && body.includes("pair");51- })52- );46+ it("keeps the major Sync security repair notice explicit", () => {47+ const syncRecovery = RELEASES.find((release) => release.version === "5.2.46");48+ const body = syncRecovery?.notes[0]?.body.toLowerCase() ?? "";5349 expect(syncRecovery?.importance).toBe("breaking");54- expect(syncRecovery?.version).toBe("5.2.17");50+ expect(body).toContain("update peach on every device");51+ expect(body).toContain("open sync settings");52+ expect(body).toContain("master password");53+ expect(body).toContain("reset sync");54+ expect(body).toContain("pair or re-pair every device");55+ expect(body).toContain("revocation");56+ expect(body).toContain("vault and recovery words are unchanged");57+ expect(body).toContain("sorry");5558 5659 const vaultV4 = RELEASES.find((release) => release.version === "5.1.3");5760 expect(vaultV4?.importance).toBe("breaking");5861 expect(vaultV4?.notes.some((note) => note.body.toLowerCase().includes("revoke"))).toBe(false);5962 });60-6163 it("shows the sync recovery releases for upgrades from 5.2.15", () => {6264 expect(importantReleasesSince("5.2.15").map((release) => release.version)).toEqual(["5.2.46", "5.2.17"]);6365 });6466 it("combines every important release newer than the installed version", () => {6567 expect(importantReleasesSince("5.0.0").map((release) => release.version)).toEqual(["5.2.46", "5.2.17", "5.1.3"]);6668 });69+6770 6871 it("hasReleaseNotes returns true when notes exist", () => {6972 expect(hasReleaseNotes()).toBe(true);src/shared/release-notes.ts+2 −2
@@ -41,8 +41,8 @@4141 releasedAt: "2026-09-11",4242 importance: "breaking",4343 notes: [{44- heading: "Sync needs one deliberate repair",45- body: "This security update starts a new Sync generation. Update Peach on every other device, reset Sync here, then pair each device again. Your vault and recovery words are unchanged; old device trust is archived, not silently reused.",44+ heading: "A major Sync security update",45+ body: "We're sorry for the extra step. This major security update makes Sync and device Revocation meaningfully more secure, but it requires a deliberate repair: 1) update Peach on every device; 2) open Sync settings on the device showing the reset notice; 3) enter your master password and complete Reset Sync; 4) pair or re-pair every device individually. Old device trust will not continue automatically. Your vault and recovery words are unchanged.",4646 }],4747 },4848 { version: "5.2.17", releasedAt: "2026-09-07", importance: "breaking", notes: [{ heading: "Sync may need device repair", body: "If sync starts failing after this security update, revoke the affected devices and pair them again. A recent security change may require repairing device trust before sync can resume." }] },