From a299eaf925856349e7fe31ee77aa0577dbe0f26f Mon Sep 17 00:00:00 2001 From: ARIA Date: Mon, 6 Jul 2026 20:45:50 +0200 Subject: [PATCH] Always render VM list; surface SPICE connect target for diagnosis - Auto-connect (single-VM shortcut and autostart match) now renders the VM list first instead of skipping straight to the connect attempt. With cluster dedup collapsing 3 duplicate entries down to 1, the VM vanished from the screen entirely whenever the connection failed. - proxmox:connect now returns the resolved host:port it handed to remote-viewer, shown in the success notice, so connection failures (e.g. Proxmox handing out a cluster-internal node address the client cannot route to) can be diagnosed without racing delete-this-file. --- package.json | 2 +- src/main.js | 11 ++++++++--- src/renderer/vms.js | 19 +++++++++++-------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index f575895..f062d05 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "proxmox-spice-client", - "version": "1.0.5", + "version": "1.0.6", "description": "VDI SPICE Client f\u00fcr Proxmox", "main": "src/main.js", "scripts": { diff --git a/src/main.js b/src/main.js index c4168e5..d282e05 100644 --- a/src/main.js +++ b/src/main.js @@ -222,9 +222,9 @@ ipcMain.handle('proxmox:connect', async (_e, { host, node, vmid }) => { const entry = clients.find((c) => c.host === host) || clients[0]; if (!entry) throw new Error('Nicht angemeldet.'); const params = await entry.client.getSpiceTicket(node, vmid); - const vvPath = buildVVFile(params, vmid, entry.client); + const { vvPath, target } = buildVVFile(params, vmid, entry.client); launchRemoteViewer(vvPath); - return { success: true }; + return { success: true, target }; } catch (err) { return { success: false, error: err.message }; } @@ -290,7 +290,12 @@ function buildVVFile(params, vmid, client) { const vvPath = path.join(os.tmpdir(), `spice-${vmid}-${Date.now()}.vv`); fs.writeFileSync(vvPath, lines.join('\n') + '\n', { mode: 0o600 }); - return vvPath; + + // Surfaced to the renderer so a failed connection (e.g. Proxmox handing out + // a cluster-internal node address the client can't route to) is diagnosable + // without having to catch the .vv file before remote-viewer deletes it. + const port = params['tls-port'] || params.port || '?'; + return { vvPath, target: `${host}:${port}` }; } // VirtViewer's Windows installer names its folder after the bundled version diff --git a/src/renderer/vms.js b/src/renderer/vms.js index 4b0d2a2..1e37c17 100644 --- a/src/renderer/vms.js +++ b/src/renderer/vms.js @@ -76,6 +76,15 @@ async function loadVMs() { return; } + const autoConnect = await api.settings.getAutoConnect(); + const autoMatch = autoConnect && vms.find( + (vm) => vm.host === autoConnect.host && String(vm.vmid) === String(autoConnect.vmid) + ); + + // Render the list first — even when we're about to auto-connect, Stefan + // needs to see the VM (and reach Settings/retry) if that connection fails. + renderList(vms, autoConnect); + // Auto-connect when there is exactly one SPICE VM if (vms.length === 1) { showNotice(`Nur eine VM verfügbar — verbinde mit „${vms[0].name}" …`); @@ -84,18 +93,11 @@ async function loadVMs() { } // Auto-connect the VM the user marked for autostart (only one at a time) - const autoConnect = await api.settings.getAutoConnect(); - const autoMatch = autoConnect && vms.find( - (vm) => vm.host === autoConnect.host && String(vm.vmid) === String(autoConnect.vmid) - ); - if (autoMatch) { showNotice(`Autostart-VM „${autoMatch.name}" markiert — verbinde …`); await connectVM(autoMatch); return; } - - renderList(vms, autoConnect); } loadVMs(); @@ -187,7 +189,8 @@ async function connectVM(vm) { if (!result.success) { showError(result.error || 'Verbindung fehlgeschlagen.'); } else { - showNotice(`„${vm.name}" — SPICE-Sitzung gestartet.`); + const targetInfo = result.target ? ` (Ziel: ${result.target})` : ''; + showNotice(`„${vm.name}" — SPICE-Sitzung gestartet${targetInfo}.`); } }