diff --git a/changelog.md b/changelog.md index c7996d5..6784c3e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,14 @@ # Changelog +## 2025-12-04 - 7.1.0 - feat(swdash) +Add live speedtest progress UI to service worker dashboard + +- Introduce reactive speedtest state (phase, progress, elapsed) in sw-dash-overview component +- Start a progress interval to animate overall test progress and estimate phases (latency, download, upload) +- Dispatch 'speedtest-complete' event and show a brief complete state before resetting UI +- Add helper methods for phase labels and elapsed time formatting +- Add CSS for progress bar, shimmer animation and phase pulse to sw-dash-styles + ## 2025-12-04 - 7.0.0 - BREAKING CHANGE(serviceworker) Move serviceworker speedtest to time-based chunked transfers and update dashboard/server contract diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index f6f64b4..b19eaa3 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@api.global/typedserver', - version: '7.0.0', + version: '7.1.0', description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.' } diff --git a/ts_swdash/sw-dash-overview.ts b/ts_swdash/sw-dash-overview.ts index 3409d92..67c27f4 100644 --- a/ts_swdash/sw-dash-overview.ts +++ b/ts_swdash/sw-dash-overview.ts @@ -70,15 +70,46 @@ export class SwDashOverview extends LitElement { @property({ type: Object }) accessor metrics: IMetricsData | null = null; @state() accessor speedtestRunning = false; + @state() accessor speedtestPhase: 'idle' | 'latency' | 'download' | 'upload' | 'complete' = 'idle'; + @state() accessor speedtestProgress = 0; + @state() accessor speedtestElapsed = 0; + + // Speedtest timing constants (must match service worker) + private static readonly TEST_DURATION_MS = 5000; // 5 seconds per test + private progressInterval: number | null = null; private async runSpeedtest(): Promise { if (this.speedtestRunning) return; this.speedtestRunning = true; + this.speedtestPhase = 'latency'; + this.speedtestProgress = 0; + this.speedtestElapsed = 0; + + // Start progress animation (total ~10.5s: latency ~0.5s + 5s download + 5s upload) + const totalEstimatedMs = 10500; + const startTime = Date.now(); + + this.progressInterval = window.setInterval(() => { + this.speedtestElapsed = Date.now() - startTime; + this.speedtestProgress = Math.min(100, (this.speedtestElapsed / totalEstimatedMs) * 100); + + // Estimate phase based on elapsed time + if (this.speedtestElapsed < 500) { + this.speedtestPhase = 'latency'; + } else if (this.speedtestElapsed < 5500) { + this.speedtestPhase = 'download'; + } else { + this.speedtestPhase = 'upload'; + } + }, 100); try { const response = await fetch('/sw-dash/speedtest'); const result = await response.json(); + this.speedtestPhase = 'complete'; + this.speedtestProgress = 100; + // Dispatch event to parent to update metrics this.dispatchEvent(new CustomEvent('speedtest-complete', { detail: result, @@ -87,11 +118,36 @@ export class SwDashOverview extends LitElement { })); } catch (err) { console.error('Speedtest failed:', err); + this.speedtestPhase = 'idle'; } finally { - this.speedtestRunning = false; + if (this.progressInterval) { + window.clearInterval(this.progressInterval); + this.progressInterval = null; + } + // Keep showing complete state briefly, then reset + setTimeout(() => { + this.speedtestRunning = false; + this.speedtestPhase = 'idle'; + this.speedtestProgress = 0; + }, 1500); } } + private getPhaseLabel(): string { + switch (this.speedtestPhase) { + case 'latency': return 'Testing latency...'; + case 'download': return 'Download test...'; + case 'upload': return 'Upload test...'; + case 'complete': return 'Complete!'; + default: return ''; + } + } + + private formatElapsed(): string { + const seconds = Math.floor(this.speedtestElapsed / 1000); + return `${seconds}s`; + } + public render(): TemplateResult { if (!this.metrics) { return html`
Loading metrics...
`; @@ -166,11 +222,23 @@ export class SwDashOverview extends LitElement { ${m.speedtest.isOnline ? 'Online' : 'Offline'} -
Download:${m.speedtest.lastDownloadSpeedMbps.toFixed(2)} Mbps
-
-
Upload:${m.speedtest.lastUploadSpeedMbps.toFixed(2)} Mbps
-
-
Latency:${m.speedtest.lastLatencyMs.toFixed(0)} ms
+ ${this.speedtestRunning ? html` +
+
+ ${this.getPhaseLabel()} + ${this.formatElapsed()} +
+
+
+
+
+ ` : html` +
Download:${m.speedtest.lastDownloadSpeedMbps.toFixed(2)} Mbps
+
+
Upload:${m.speedtest.lastUploadSpeedMbps.toFixed(2)} Mbps
+
+
Latency:${m.speedtest.lastLatencyMs.toFixed(0)} ms
+ `}