3 Commits
Author SHA1 Message Date
aria.hacker 7fbac7c18a Add per-VM autostart checkbox (single-select, persisted)
Only one VM can be marked for autostart at a time — checking a new
one unchecks the previous. Matched by host+vmid since the same vmid
can exist on multiple standalone Proxmox hosts in a cluster setup.
2026-07-06 13:43:38 +02:00
aria.hacker 5c4e3781fd Bump version to 1.0.3 2026-07-06 12:19:52 +02:00
aria.hacker f4828f73b9 Fix broken VirtViewer download links (virt-manager.org dead, use gitlab.com release) 2026-07-06 11:01:30 +02:00
6 changed files with 79 additions and 11 deletions
+3 -3
View File
@@ -18,7 +18,7 @@ Jetzt automatisch herunterladen und installieren (ca. 30 MB)?" \
DetailPrint "Lade VirtViewer herunter..."
nsExec::ExecToLog 'powershell.exe -NonInteractive -Command \
"Invoke-WebRequest \
-Uri \"https://virt-manager.org/download/virt-viewer-x64.msi\" \
-Uri \"https://gitlab.com/virt-viewer/virt-viewer/-/releases/v11.0/downloads/virt-viewer-x64-11.0-1.0.msi\" \
-OutFile \"$TEMP\virt-viewer-setup.msi\" \
-UseBasicParsing"'
Pop $0
@@ -26,7 +26,7 @@ Jetzt automatisch herunterladen und installieren (ca. 30 MB)?" \
MessageBox MB_OK|MB_ICONEXCLAMATION \
"Download fehlgeschlagen (Fehlercode: $0).$\n$\n\
Bitte VirtViewer nach der Installation manuell installieren:$\n\
https://virt-manager.org/download/"
https://gitlab.com/virt-viewer/virt-viewer/-/releases/v11.0"
Goto vv_skip
${EndIf}
@@ -40,7 +40,7 @@ https://virt-manager.org/download/"
MessageBox MB_OK|MB_ICONEXCLAMATION \
"VirtViewer-Installation schlug fehl (Code: $0).$\n$\n\
Bitte nach Abschluss manuell installieren:$\n\
https://virt-manager.org/download/"
https://gitlab.com/virt-viewer/virt-viewer/-/releases/v11.0"
${EndIf}
Goto vv_skip
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "proxmox-spice-client",
"version": "1.0.2",
"version": "1.0.4",
"description": "VDI SPICE Client f\u00fcr Proxmox",
"main": "src/main.js",
"scripts": {
+10 -1
View File
@@ -229,6 +229,15 @@ ipcMain.handle('settings:browseViewerPath', async () => {
return chosen;
});
// Only one VM can be marked for autostart at a time — identified by
// host+vmid since the same vmid can exist on several hosts.
ipcMain.handle('settings:getAutoConnect', () => store.get('autoConnect', null));
ipcMain.handle('settings:setAutoConnect', (_e, target) => {
if (target) store.set('autoConnect', target);
else store.delete('autoConnect');
});
// ---------- SPICE helpers ----------
function buildVVFile(params, vmid, client) {
@@ -303,7 +312,7 @@ function launchRemoteViewer(vvPath) {
if (i >= candidates.length) {
const hint =
process.platform === 'win32'
? 'Windows: https://virt-manager.org/download/\n\n' +
? 'Windows: https://gitlab.com/virt-viewer/virt-viewer/-/releases/v11.0\n\n' +
'Falls VirtViewer an einem nicht-standardmäßigen Ort installiert ist, ' +
'trage den Pfad unter „Einstellungen → Viewer-Pfad" ein.'
: 'Linux: sudo apt install virt-viewer';
+2
View File
@@ -17,5 +17,7 @@ contextBridge.exposeInMainWorld('api', {
getViewerPath: () => ipcRenderer.invoke('settings:getViewerPath'),
browseViewerPath: () => ipcRenderer.invoke('settings:browseViewerPath'),
clearViewerPath: () => ipcRenderer.invoke('settings:clearViewerPath'),
getAutoConnect: () => ipcRenderer.invoke('settings:getAutoConnect'),
setAutoConnect: (target) => ipcRenderer.invoke('settings:setAutoConnect', target),
},
});
+14
View File
@@ -250,6 +250,20 @@ body.vms-page {
.vm-info { flex: 1; min-width: 0; }
.vm-autostart {
display: flex;
align-items: center;
gap: 0.35rem;
font-size: 0.75rem;
color: var(--muted);
cursor: pointer;
white-space: nowrap;
flex-shrink: 0;
user-select: none;
}
.vm-autostart input { cursor: pointer; }
.vm-name {
font-size: 0.97rem;
font-weight: 600;
+49 -6
View File
@@ -83,20 +83,37 @@ async function loadVMs() {
return;
}
renderList(vms);
// 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();
// ── Render ────────────────────────────────────────────────
function renderList(vms) {
function renderList(vms, autoConnect) {
// Only show the host when there's more than one — single-host setups don't need the noise.
const multiHost = new Set(vms.map((vm) => vm.host)).size > 1;
listEl.innerHTML = vms
.map(
(vm) => `
.map((vm) => {
const isAutostart = !!(
autoConnect &&
autoConnect.host === vm.host &&
String(autoConnect.vmid) === String(vm.vmid)
);
return `
<div class="vm-card" data-vmid="${vm.vmid}">
<div class="vm-info">
<div class="vm-name">${esc(vm.name)}</div>
@@ -105,6 +122,17 @@ function renderList(vms) {
Läuft &nbsp;·&nbsp; ${multiHost ? `Host: ${esc(vm.host)} &nbsp;·&nbsp; ` : ''}Node: ${esc(vm.node)} &nbsp;·&nbsp; ID: ${vm.vmid}
</div>
</div>
<label class="vm-autostart" title="Beim Start automatisch mit dieser VM verbinden">
<input
type="checkbox"
class="autostart-checkbox"
data-vmid="${vm.vmid}"
data-host="${esc(vm.host)}"
data-name="${esc(vm.name)}"
${isAutostart ? 'checked' : ''}
>
Autostart
</label>
<button
class="btn-connect"
data-vmid="${vm.vmid}"
@@ -113,8 +141,8 @@ function renderList(vms) {
data-name="${esc(vm.name)}"
>Verbinden</button>
</div>
`
)
`;
})
.join('');
listEl.querySelectorAll('.btn-connect').forEach((btn) => {
@@ -128,6 +156,21 @@ function renderList(vms) {
);
});
listEl.querySelectorAll('.autostart-checkbox').forEach((cb) => {
cb.addEventListener('change', async () => {
if (cb.checked) {
// Only one VM can be the autostart VM — uncheck any other.
listEl.querySelectorAll('.autostart-checkbox').forEach((other) => {
if (other !== cb) other.checked = false;
});
await api.settings.setAutoConnect({ host: cb.dataset.host, vmid: cb.dataset.vmid });
showNotice(`${cb.dataset.name}" wird beim nächsten Start automatisch verbunden.`);
} else {
await api.settings.setAutoConnect(null);
}
});
});
listEl.classList.remove('hidden');
}