codeburn/app/renderer/components/UpdateBanner.tsx
Resham Joshi ae1d1c026b
app: Download button direct-downloads the update asset (#777)
The update Download button opened the GitHub release page; it now
downloads the right artifact for the running platform directly: arm64
or x64 dmg on macOS (preload newly exposes process.arch), the Setup exe
on Windows. Linux keeps the release page since it ships three formats
and the user picks. Unknown platforms and preloads without arch fall
back to the page. URL mapping is unit-tested per platform.

Co-authored-by: reviewer <review@local>
2026-07-20 10:02:43 -07:00

40 lines
1.5 KiB
TypeScript

import { useState } from 'react'
import { updateDownloadUrl, useUpdateStatus } from '../hooks/useUpdateStatus'
import { codeburn } from '../lib/ipc'
const DISMISS_KEY = 'codeburn.updateDismissed'
function readDismissed(): string | null {
try { return globalThis.localStorage?.getItem(DISMISS_KEY) ?? null } catch { return null }
}
/**
* Subtle, dismissible "update available" nudge, in the budget-banner visual
* language. Dismiss persists per release tag (codeburn.updateDismissed), so the
* same version never nags twice but the next release shows fresh. Download opens
* the release page via the https-only openExternal bridge. Never auto-installs.
*/
export function UpdateBanner() {
const status = useUpdateStatus()
const [dismissedTag, setDismissedTag] = useState<string | null>(readDismissed)
if (!status || !status.updateAvailable || !status.tag) return null
if (dismissedTag === status.tag) return null
const tag = status.tag
const dismiss = () => {
try { globalThis.localStorage?.setItem(DISMISS_KEY, tag) } catch { /* storage can be unavailable */ }
setDismissedTag(tag)
}
return (
<div role="status" className="update-banner">
<span>
Update available: CodeBurn {status.latestVersion} ·{' '}
<button type="button" className="set-text-button" onClick={() => { void codeburn.openExternal(updateDownloadUrl(tag)) }}>Download</button>
</span>
<button type="button" className="set-text-button" onClick={dismiss}>Dismiss</button>
</div>
)
}