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:
parent
d1513a58b3
commit
f13bf7f5bc
122
renderer/app.js
122
renderer/app.js
@ -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">▶</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 ? '▶' : '▼';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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(() => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user