Fix Electron update: Squirrel feed URL, version display, error details

- Fix: Squirrel.Windows feed URL /updates → /downloads (Squirrel appends /RELEASES)
- Show Desktop App + Server version in update modal
- Display actual error message in failed state
- Dynamic Electron version via app.getVersion() instead of hardcoded
- Sync electron/package.json version with VERSION file (1.5.8)
- Add "Später" button on update-ready, timeout error message
- Style: version info, error detail box, secondary button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Daniel 2026-03-07 19:23:30 +01:00
parent 56ac2d0079
commit 9fd0992fc4
5 changed files with 66 additions and 10 deletions

View file

@ -28,6 +28,7 @@ export default function App() {
const [connected, setConnected] = useState(false);
const [plugins, setPlugins] = useState<PluginInfo[]>([]);
const [updateState, setUpdateState] = useState<'idle' | 'checking' | 'downloading' | 'ready' | 'uptodate' | 'error'>('idle');
const [updateError, setUpdateError] = useState<string>('');
const [activeTab, setActiveTabRaw] = useState<string>(() => localStorage.getItem('hub_activeTab') ?? '');
const setActiveTab = (tab: string) => {
@ -118,15 +119,22 @@ export default function App() {
}
});
api.onUpdateNotAvailable?.(() => setUpdateState('uptodate'));
api.onUpdateError?.(() => setUpdateState('error'));
api.onUpdateError?.((msg: string) => {
setUpdateError(msg || 'Unbekannter Fehler');
setUpdateState('error');
});
}, []);
const electronVersion = (window as any).electronAPI?.version ?? null;
const handleCheckForUpdates = () => {
setUpdateState('checking');
setUpdateError('');
(window as any).electronAPI?.checkForUpdates?.();
// Timeout: falls Electron nicht antwortet, nach 15s zurücksetzen
setTimeout(() => {
setUpdateState(prev => prev === 'checking' ? 'error' : prev);
setUpdateError(prev => prev || 'Zeitüberschreitung — Server nicht erreichbar.');
}, 15000);
};
@ -199,6 +207,10 @@ export default function App() {
<>
<div className="hub-update-icon">{'\u{1F50D}'}</div>
<h2>Suche nach Updates...</h2>
<div className="hub-update-versions">
{electronVersion && <span>Desktop App: v{electronVersion}</span>}
<span>Server: v{version}</span>
</div>
<div className="hub-update-progress">
<div className="hub-update-progress-bar" />
</div>
@ -210,8 +222,10 @@ export default function App() {
{updateState === 'downloading' && (
<>
<div className="hub-update-icon">{'\u2B07\uFE0F'}</div>
<h2>Update verfügbar</h2>
<p>Update wird heruntergeladen...</p>
<h2>Update wird heruntergeladen...</h2>
<div className="hub-update-versions">
{electronVersion && <span>Aktuell: v{electronVersion}</span>}
</div>
<div className="hub-update-progress">
<div className="hub-update-progress-bar" />
</div>
@ -223,7 +237,10 @@ export default function App() {
<h2>Update bereit!</h2>
<p>Die App wird neu gestartet, um das Update zu installieren.</p>
<button className="hub-update-btn" onClick={() => (window as any).electronAPI?.installUpdate()}>
OK
Jetzt installieren
</button>
<button className="hub-update-btn hub-update-btn-secondary" onClick={() => setUpdateState('idle')}>
Später
</button>
</>
)}
@ -231,7 +248,11 @@ export default function App() {
<>
<div className="hub-update-icon">{'\u2705'}</div>
<h2>Alles aktuell!</h2>
<p>Du verwendest bereits die neueste Version (v{version}).</p>
<div className="hub-update-versions">
{electronVersion && <span>Desktop App: v{electronVersion}</span>}
<span>Server: v{version}</span>
</div>
<p>Du verwendest bereits die neueste Version.</p>
<button className="hub-update-btn" onClick={() => setUpdateState('idle')}>
OK
</button>
@ -241,7 +262,11 @@ export default function App() {
<>
<div className="hub-update-icon">{'\u274C'}</div>
<h2>Update fehlgeschlagen</h2>
<p>Das Update konnte nicht heruntergeladen werden.</p>
<div className="hub-update-versions">
{electronVersion && <span>Desktop App: v{electronVersion}</span>}
<span>Server: v{version}</span>
</div>
{updateError && <p className="hub-update-error-detail">{updateError}</p>}
<button className="hub-update-btn" onClick={() => setUpdateState('idle')}>
Schließen
</button>

View file

@ -313,6 +313,28 @@ html, body {
.hub-update-btn:hover {
opacity: 0.85;
}
.hub-update-btn-secondary {
background: var(--bg-tertiary);
color: var(--text-secondary);
margin-top: 4px;
}
.hub-update-versions {
display: flex;
flex-direction: column;
gap: 2px;
margin: 8px 0;
font-size: 12px;
color: var(--text-muted);
}
.hub-update-error-detail {
font-size: 11px;
color: #ef4444;
background: rgba(239, 68, 68, 0.1);
border-radius: var(--radius);
padding: 6px 10px;
word-break: break-word;
max-width: 300px;
}
/* ── Main Content Area ── */
.hub-content {