mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-21 21:31:12 +02:00
feat(x): scrollable release-notes box on the update card, notes on Windows too
The notes pane was a bare max-h clip: nothing signalled that more content sat below the fold, and Squirrel.Windows never supplies release notes at all, so Windows users only ever saw the static fallback line. Squirrel.Mac is no better in the edit-after-publish window — it snapshots the release body at download time, which is how v0.7.7 shipped a card showing two paragraphs of a ten-item release. - Render the notes in a bordered, inset scroll box (max-h + overflow-y) so the frame and scrollbar make the overflow visible on both platforms. - Backfill the notes from the GitHub release body after update-downloaded: gives Windows notes for the first time and replaces macOS's stale snapshot with the current body. On fetch failure the snapshot (or the fallback line) stands. - Strip the release body's leading "What's new" heading, which duplicated the card's own label. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
63a99e5fe4
commit
60165979f0
2 changed files with 42 additions and 4 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { app, autoUpdater, nativeImage, BrowserWindow } from "electron";
|
||||
import { app, autoUpdater, net, nativeImage, BrowserWindow } from "electron";
|
||||
import { capture } from "@x/core/dist/analytics/posthog.js";
|
||||
import type { ipc } from "@x/shared";
|
||||
|
||||
|
|
@ -90,6 +90,12 @@ export function initUpdater(): void {
|
|||
releaseNotes: releaseNotes || undefined,
|
||||
});
|
||||
showReadyBadge();
|
||||
// Squirrel.Windows never carries notes, and Squirrel.Mac's copy is a
|
||||
// snapshot from download time — stale when the release body is edited
|
||||
// after publish (update.electronjs.org caching widens that window).
|
||||
// Refresh from the GitHub API; on failure the snapshot (or the card's
|
||||
// static fallback line) stands.
|
||||
void backfillReleaseNotes(releaseName || undefined);
|
||||
});
|
||||
autoUpdater.on("error", (err) => {
|
||||
setStatus({ state: "error", error: err.message, lastCheckedAt: status.lastCheckedAt });
|
||||
|
|
@ -110,6 +116,30 @@ export function initUpdater(): void {
|
|||
setInterval(checkForUpdates, CHECK_INTERVAL_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the staged update's release notes with the current GitHub release
|
||||
* body. releaseName is "0.7.7" from Squirrel.Windows and "v0.7.7" from
|
||||
* Squirrel.Mac — normalize to the tag form.
|
||||
*/
|
||||
async function backfillReleaseNotes(releaseName: string | undefined): Promise<void> {
|
||||
if (!releaseName) return;
|
||||
try {
|
||||
const tag = `v${releaseName.replace(/^v/, "")}`;
|
||||
const res = await net.fetch(`https://api.github.com/repos/${REPO}/releases/tags/${tag}`, {
|
||||
headers: { Accept: "application/vnd.github+json", "User-Agent": "Rowboat" },
|
||||
});
|
||||
if (!res.ok) return;
|
||||
const { body } = (await res.json()) as { body?: string };
|
||||
const notes = body?.trim();
|
||||
// Re-check the state: the fetch raced user actions (quitAndInstall).
|
||||
if (notes && status.state === "ready" && status.newVersion === releaseName) {
|
||||
setStatus({ ...status, releaseNotes: notes });
|
||||
}
|
||||
} catch {
|
||||
// Offline or rate-limited — the Squirrel snapshot / fallback line stands.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manual "Check for updates". Only meaningful when idle or errored;
|
||||
* checking/downloading are already in flight and ready is already staged.
|
||||
|
|
|
|||
|
|
@ -55,6 +55,11 @@ export function UpdateCard() {
|
|||
if (!visible || status?.state !== "ready") return null
|
||||
|
||||
const releaseUrl = version ? `${RELEASES_URL}/tag/v${version}` : `${RELEASES_URL}/latest`
|
||||
// Release bodies usually open with their own "What's new" heading, which
|
||||
// would duplicate the card's label above the box — drop it.
|
||||
const releaseNotes = status.releaseNotes
|
||||
?.replace(/^\s*#{1,6}[ \t]*what[’']?s new[ \t]*\r?\n+/i, "")
|
||||
.trim()
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -81,10 +86,13 @@ export function UpdateCard() {
|
|||
</p>
|
||||
<div className="mt-3">
|
||||
<h5 className="text-xs font-semibold">What's new</h5>
|
||||
{status.releaseNotes ? (
|
||||
<div className="mt-1.5 max-h-56 overflow-y-auto">
|
||||
{releaseNotes ? (
|
||||
// A bordered, fixed-height scroll box (not a bare max-h clip): the
|
||||
// frame and inset scrollbar signal there is more content below the
|
||||
// fold on every platform.
|
||||
<div className="mt-1.5 max-h-56 overflow-y-auto overscroll-contain rounded-md border border-border/60 bg-muted/30 p-2.5">
|
||||
<Streamdown className="prose prose-sm dark:prose-invert max-w-none text-xs [&>*:first-child]:mt-0 [&>*:last-child]:mb-0">
|
||||
{status.releaseNotes}
|
||||
{releaseNotes}
|
||||
</Streamdown>
|
||||
</div>
|
||||
) : (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue