Extension: show installed/latest version for drift tracking

Popup footer shows its own installed version (from manifest.json, via
chrome.runtime.getManifest()); Terminals page shows the latest bundled
version next to the download link (new GET /api/extension/version, reads
the same manifest.json). Bumped manifest.json to 0.2.0 for the Today's
Arrivals change, and documented in extension-src/README.md that every
future change to this folder must bump the version too — nothing else
keeps it in sync automatically.
This commit is contained in:
jtricerolph 2026-10-09 12:12:32 +00:00
parent ebf9875ca8
commit 790431c446
8 changed files with 49 additions and 5 deletions

View file

@ -58,6 +58,7 @@ export function checkinPdfUrl(id: number): string { return `${BASE}/checkins/${i
// backend/extension-src), zipped fresh on each request rather than served as
// a static file. See project_checkin memory's "Standalone push extension".
export function extensionDownloadUrl(): string { return `${BASE}/extension/download` }
export function fetchExtensionVersion(): Promise<{ version: string }> { return request('/extension/version') }
// Marketing
export function fetchMarketingProviders(): Promise<MarketingProvider[]> { return request('/marketing/providers') }

View file

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'
import { RefreshCw, KeyRound, Ban, Trash2, Copy, Download } from 'lucide-react'
import { fetchTerminals, createTerminal, revokeTerminal, deleteTerminal, extensionDownloadUrl } from '../api'
import { fetchTerminals, createTerminal, revokeTerminal, deleteTerminal, extensionDownloadUrl, fetchExtensionVersion } from '../api'
import type { Terminal } from '../types'
export default function Terminals() {
@ -10,6 +10,7 @@ export default function Terminals() {
const [newName, setNewName] = useState('')
const [creating, setCreating] = useState(false)
const [revealedKey, setRevealedKey] = useState<{ name: string; key: string } | null>(null)
const [extensionVersion, setExtensionVersion] = useState('')
function load() {
setLoading(true)
@ -20,6 +21,7 @@ export default function Terminals() {
}
useEffect(load, [])
useEffect(() => { fetchExtensionVersion().then(v => setExtensionVersion(v.version)).catch(() => {}) }, [])
async function handleCreate(e: React.FormEvent) {
e.preventDefault()
@ -77,9 +79,12 @@ export default function Terminals() {
select the unzipped folder. It'll need a terminal key from below to actually authorize
pushes — create one first if you haven't already.
</p>
<a className="btn" href={extensionDownloadUrl()} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, textDecoration: 'none' }}>
<Download size={16} strokeWidth={1.75} /> Download Extension (.zip)
</a>
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<a className="btn" href={extensionDownloadUrl()} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, textDecoration: 'none' }}>
<Download size={16} strokeWidth={1.75} /> Download Extension (.zip)
</a>
{extensionVersion && <span className="field-hint">Latest version: {extensionVersion}</span>}
</div>
</div>
{error && <div className="error-banner">{error}</div>}