feat(remote): add Fernsteuerung settings panel with token management and status display

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Administrator 2026-03-12 06:58:29 +01:00
parent d1513a58b3
commit f13bf7f5bc

View File

@ -2023,6 +2023,97 @@ function renderSettings() {
} }
}); });
// --- Remote Control Panel ---
const remoteSettings = globalSettings.remote || {};
const remotePanel = document.createElement('div');
remotePanel.className = 'hoster-settings-panel';
remotePanel.innerHTML = `
<div class="hoster-panel-header" data-hoster="remote">
<span class="panel-arrow">&#9654;</span>
<span class="panel-title">Fernsteuerung</span>
<span class="panel-status${remoteSettings.enabled ? ' active' : ''}" id="remoteStatusBadge">${remoteSettings.enabled ? 'Aktiv' : 'Inaktiv'}</span>
</div>
<div class="hoster-panel-body" data-panel="remote" style="display:none">
<div class="settings-section-label">Server</div>
<div class="settings-grid-mini">
<div class="settings-row checkbox-row">
<label>Aktiviert</label>
<input type="checkbox" class="settings-autosave" id="remoteEnabledInput" ${remoteSettings.enabled ? 'checked' : ''}>
</div>
<div class="settings-row checkbox-row">
<label>Input erlauben</label>
<input type="checkbox" class="settings-autosave" id="remoteAllowInputInput" ${remoteSettings.allowInput !== false ? 'checked' : ''}>
</div>
</div>
<div class="settings-row">
<label>Port</label>
<input type="number" class="hs-input settings-autosave" id="remotePortInput" value="${remoteSettings.port || 9100}" min="1024" max="65535" style="width:100px">
</div>
<div class="settings-row">
<label>API-Token</label>
<input type="text" class="key-input" id="remoteTokenInput" value="${remoteSettings.token || ''}" readonly style="flex:1">
<button class="btn btn-xs btn-secondary" id="remoteCopyTokenBtn" title="Kopieren">Kopieren</button>
<button class="btn btn-xs btn-secondary" id="remoteRegenerateTokenBtn" title="Neu generieren">Neu</button>
</div>
<div class="settings-section-label">Status</div>
<div class="settings-row">
<span id="remoteConnectionStatus" style="color:#94a3b8">Prüfe...</span>
</div>
</div>
`;
container.appendChild(remotePanel);
// Toggle remote panel
remotePanel.querySelector('.hoster-panel-header').addEventListener('click', () => {
const body = remotePanel.querySelector('.hoster-panel-body');
const arrow = remotePanel.querySelector('.panel-arrow');
const isOpen = body.style.display !== 'none';
body.style.display = isOpen ? 'none' : 'block';
arrow.innerHTML = isOpen ? '&#9654;' : '&#9660;';
});
// Copy token
document.getElementById('remoteCopyTokenBtn').addEventListener('click', async () => {
const token = document.getElementById('remoteTokenInput').value;
if (token) {
await window.api.copyToClipboard(token);
document.getElementById('remoteCopyTokenBtn').textContent = 'Kopiert!';
setTimeout(() => { document.getElementById('remoteCopyTokenBtn').textContent = 'Kopieren'; }, 1500);
}
});
// Regenerate token
document.getElementById('remoteRegenerateTokenBtn').addEventListener('click', async () => {
const newToken = await window.api.remoteGenerateToken();
document.getElementById('remoteTokenInput').value = newToken;
scheduleSettingsSave();
});
// Update status
window.api.remoteStatus().then(status => {
const el = document.getElementById('remoteConnectionStatus');
if (!el) return;
if (status.running) {
el.textContent = `Aktiv auf Port ${status.port}${status.clientCount} Client(s) verbunden`;
el.style.color = '#10b981';
} else {
el.textContent = 'Nicht aktiv';
el.style.color = '#94a3b8';
}
}).catch(() => {});
// Live client count updates
window.api.onRemoteClientCount((count) => {
const el = document.getElementById('remoteConnectionStatus');
if (el && el.style.color === 'rgb(16, 185, 129)') {
window.api.remoteStatus().then(status => {
if (status.running) {
el.textContent = `Aktiv auf Port ${status.port}${status.clientCount} Client(s) verbunden`;
}
}).catch(() => {});
}
});
// --- Backup Panel --- // --- Backup Panel ---
const backupPanel = document.createElement('div'); const backupPanel = document.createElement('div');
backupPanel.className = 'hoster-settings-panel'; backupPanel.className = 'hoster-settings-panel';
@ -2190,6 +2281,12 @@ async function saveSettings(options = {}) {
delaySec: Math.max(1, parseInt(document.getElementById('fmDelaySecInput')?.value || '3', 10) || 3), delaySec: Math.max(1, parseInt(document.getElementById('fmDelaySecInput')?.value || '3', 10) || 3),
autoStart: !!document.getElementById('fmAutoStartInput')?.checked, autoStart: !!document.getElementById('fmAutoStartInput')?.checked,
hosters: Array.from(document.querySelectorAll('.fm-hoster-checkbox:checked')).map(el => el.dataset.fmHoster) hosters: Array.from(document.querySelectorAll('.fm-hoster-checkbox:checked')).map(el => el.dataset.fmHoster)
},
remote: {
enabled: !!document.getElementById('remoteEnabledInput')?.checked,
port: Math.max(1024, Math.min(65535, parseInt(document.getElementById('remotePortInput')?.value || '9100', 10) || 9100)),
token: (document.getElementById('remoteTokenInput')?.value || '').trim(),
allowInput: !!document.getElementById('remoteAllowInputInput')?.checked
} }
}; };
@ -2241,6 +2338,31 @@ async function saveSettings(options = {}) {
if (badge) { badge.textContent = 'Inaktiv'; badge.className = 'panel-status'; } if (badge) { badge.textContent = 'Inaktiv'; badge.className = 'panel-status'; }
} }
// Start/stop remote server based on settings
const remoteSettings = globalSettings.remote;
const remoteBadge = document.getElementById('remoteStatusBadge');
if (remoteSettings) {
try {
await window.api.remoteSaveSettings(remoteSettings);
if (remoteBadge) {
remoteBadge.textContent = remoteSettings.enabled ? 'Aktiv' : 'Inaktiv';
remoteBadge.className = `panel-status${remoteSettings.enabled ? ' active' : ''}`;
}
// Update status display
const status = await window.api.remoteStatus();
const statusEl = document.getElementById('remoteConnectionStatus');
if (statusEl) {
if (status.running) {
statusEl.textContent = `Aktiv auf Port ${status.port}${status.clientCount} Client(s) verbunden`;
statusEl.style.color = '#10b981';
} else {
statusEl.textContent = 'Nicht aktiv';
statusEl.style.color = '#94a3b8';
}
}
} catch {}
}
const feedback = document.getElementById('saveFeedback'); const feedback = document.getElementById('saveFeedback');
feedback.textContent = feedbackText; feedback.textContent = feedbackText;
setTimeout(() => { setTimeout(() => {