feat(settings): move per-hoster upload settings into the Accounts tab
Declutters the Einstellungen tab: the per-hoster panels (Retries, Max Speed, Parallel Uploads, Restart-below, Interval, Max Size, log-to-file) are no longer listed there. Each hoster group in the Accounts tab now has a collapsible "Upload-Einstellungen" section with exactly those controls, so everything about a hoster lives in one place. The Einstellungen tab shows a short pointer to where they moved. Per-hoster edits in Accounts save via a dedicated lightweight handler (scheduleHosterSettingsSave → saveHosterSettings) that touches only hosterSettings — it deliberately does NOT route through the global saveSettings, so tweaking a hoster slider can't re-run the folder-monitor start/stop or clobber global fields. The global saveSettings still reads .hs-input[data-hoster] wherever they live, and global inputs (which have no data-hoster) are unaffected. The new inputs drop the .settings-autosave class and bind via delegation on the persistent accounts container so they survive re-renders. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
68c4007c82
commit
b1826eae00
170
renderer/app.js
170
renderer/app.js
@ -3281,81 +3281,10 @@ function renderSettings() {
|
||||
document.getElementById('exportBackupBtn').addEventListener('click', () => doBackupExport());
|
||||
document.getElementById('importBackupBtn').addEventListener('click', () => doBackupImport());
|
||||
|
||||
// --- Separator before hoster panels ---
|
||||
const separator = document.createElement('div');
|
||||
separator.style.cssText = 'height:16px';
|
||||
container.appendChild(separator);
|
||||
|
||||
if (configuredAccounts.length === 0) {
|
||||
const empty = document.createElement('div');
|
||||
empty.className = 'settings-empty';
|
||||
empty.innerHTML = '<p>Noch keine Account-Einstellungen vorhanden.</p><span class="hint">Sobald du einen Account anlegst, erscheinen hier die passenden Upload-Einstellungen.</span>';
|
||||
container.appendChild(empty);
|
||||
}
|
||||
|
||||
for (const { name } of configuredAccounts) {
|
||||
const hs = hosterSettings[name] || {};
|
||||
const maxSpeedMbs = hs.maxSpeedKbs > 0 ? (hs.maxSpeedKbs / 1024).toFixed(2).replace(/\.00$/, '') : '0';
|
||||
|
||||
const panel = document.createElement('div');
|
||||
panel.className = 'hoster-settings-panel';
|
||||
|
||||
panel.innerHTML = `
|
||||
<div class="hoster-panel-header" data-hoster="${name}">
|
||||
<span class="panel-arrow">▶</span>
|
||||
<span class="panel-title">${escapeHtml(getHosterLabel(name))}</span>
|
||||
<span class="panel-status active">Aktiv</span>
|
||||
</div>
|
||||
<div class="hoster-panel-body" data-panel="${name}" style="display:none">
|
||||
<h4>Upload-Einstellungen</h4>
|
||||
<div class="settings-grid-mini">
|
||||
<div class="settings-row">
|
||||
<label>Retries</label>
|
||||
<input type="number" class="hs-input settings-autosave" data-hoster="${name}" data-hs="retries" value="${hs.retries ?? 3}" min="0" max="500">
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Max Speed (MB/s)</label>
|
||||
<input type="number" class="hs-input settings-autosave" data-hoster="${name}" data-hs="maxSpeedMbs" value="${maxSpeedMbs}" min="0" step="0.1">
|
||||
<span class="hint">0 = unbegrenzt</span>
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Parallele Uploads</label>
|
||||
<input type="number" class="hs-input settings-autosave" data-hoster="${name}" data-hs="parallelCount" value="${hs.parallelCount ?? 2}" min="1" max="100">
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Restart unter (kB/s)</label>
|
||||
<input type="number" class="hs-input settings-autosave" data-hoster="${name}" data-hs="restartBelowKbs" value="${hs.restartBelowKbs ?? 0}" min="0">
|
||||
<span class="hint">0 = aus</span>
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Intervall (s)</label>
|
||||
<input type="number" class="hs-input settings-autosave" data-hoster="${name}" data-hs="timeIntervalSec" value="${hs.timeIntervalSec ?? 0}" min="0">
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Max Size (MB)</label>
|
||||
<input type="number" class="hs-input settings-autosave" data-hoster="${name}" data-hs="maxSizeMb" value="${hs.maxSizeMb ?? 0}" min="0">
|
||||
<span class="hint">0 = unbegrenzt</span>
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Links in Log schreiben</label>
|
||||
<input type="checkbox" class="hs-input settings-autosave" data-hoster="${name}" data-hs="logToFile" ${hs.logToFile !== false ? 'checked' : ''}>
|
||||
<span class="hint">Erfolgreiche Links in fileuploader.log. Aus = auch kein Doppel-Upload-Schutz beim Neustart für diesen Hoster.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.appendChild(panel);
|
||||
|
||||
// Toggle panel
|
||||
panel.querySelector('.hoster-panel-header').addEventListener('click', () => {
|
||||
const body = panel.querySelector('.hoster-panel-body');
|
||||
const arrow = panel.querySelector('.panel-arrow');
|
||||
const isOpen = body.style.display !== 'none';
|
||||
body.style.display = isOpen ? 'none' : 'block';
|
||||
arrow.innerHTML = isOpen ? '▶' : '▼';
|
||||
});
|
||||
}
|
||||
const hosterPointer = document.createElement('div');
|
||||
hosterPointer.className = 'settings-hoster-pointer';
|
||||
hosterPointer.innerHTML = 'Die <strong>Upload-Einstellungen pro Hoster</strong> (Retries, Speed, Parallel, Max-Größe, Log) sind jetzt im <strong>Accounts</strong>-Tab — direkt bei den jeweiligen Hostern unter „Upload-Einstellungen".';
|
||||
container.appendChild(hosterPointer);
|
||||
|
||||
document.getElementById('chooseLogFilePathBtn')?.addEventListener('click', chooseLogFilePath);
|
||||
document.getElementById('openLogFolderBtn')?.addEventListener('click', () => window.api.openLogFolder());
|
||||
@ -3708,6 +3637,78 @@ function _hosterGroupOpenState(name, summary) {
|
||||
|
||||
const _hosterGroupOpenMemory = new Map();
|
||||
|
||||
let _hosterSettingsSaveTimer = null;
|
||||
function scheduleHosterSettingsSave() {
|
||||
clearTimeout(_hosterSettingsSaveTimer);
|
||||
_hosterSettingsSaveTimer = setTimeout(() => { saveHosterSettingsFromDom().catch(() => {}); }, 350);
|
||||
}
|
||||
|
||||
async function saveHosterSettingsFromDom() {
|
||||
const newHosterSettings = { ...(config.hosterSettings || {}) };
|
||||
for (const name of HOSTERS) {
|
||||
const inputs = document.querySelectorAll(`.account-hoster-settings-body .hs-input[data-hoster="${name}"]`);
|
||||
if (!inputs.length) continue;
|
||||
const hs = { ...(newHosterSettings[name] || {}) };
|
||||
inputs.forEach(input => {
|
||||
const field = input.dataset.hs;
|
||||
if (input.type === 'checkbox') hs[field] = input.checked;
|
||||
else if (field === 'maxSpeedMbs') hs.maxSpeedKbs = Math.max(0, Math.round((parseFloat(input.value) || 0) * 1024));
|
||||
else hs[field] = parseInt(input.value, 10) || 0;
|
||||
});
|
||||
newHosterSettings[name] = hs;
|
||||
}
|
||||
await window.api.saveHosterSettings(newHosterSettings);
|
||||
config.hosterSettings = newHosterSettings;
|
||||
hosterSettings = newHosterSettings;
|
||||
}
|
||||
|
||||
function _buildHosterSettingsHtml(name) {
|
||||
const hs = (config.hosterSettings && config.hosterSettings[name]) || {};
|
||||
const maxSpeedMbs = hs.maxSpeedKbs > 0 ? String(+(hs.maxSpeedKbs / 1024).toFixed(2)) : '0';
|
||||
return `<div class="account-hoster-settings">
|
||||
<div class="account-hoster-settings-header" data-hoster-settings-toggle="${name}">
|
||||
<span class="panel-arrow">▶</span>
|
||||
<span>Upload-Einstellungen</span>
|
||||
</div>
|
||||
<div class="account-hoster-settings-body" style="display:none">
|
||||
<div class="settings-grid-mini">
|
||||
<div class="settings-row">
|
||||
<label>Retries</label>
|
||||
<input type="number" class="hs-input" data-hoster="${name}" data-hs="retries" value="${hs.retries ?? 3}" min="0" max="500">
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Max Speed (MB/s)</label>
|
||||
<input type="number" class="hs-input" data-hoster="${name}" data-hs="maxSpeedMbs" value="${maxSpeedMbs}" min="0" step="0.1">
|
||||
<span class="hint">0 = unbegrenzt</span>
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Parallele Uploads</label>
|
||||
<input type="number" class="hs-input" data-hoster="${name}" data-hs="parallelCount" value="${hs.parallelCount ?? 2}" min="1" max="100">
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Restart unter (kB/s)</label>
|
||||
<input type="number" class="hs-input" data-hoster="${name}" data-hs="restartBelowKbs" value="${hs.restartBelowKbs ?? 0}" min="0">
|
||||
<span class="hint">0 = aus</span>
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Intervall (s)</label>
|
||||
<input type="number" class="hs-input" data-hoster="${name}" data-hs="timeIntervalSec" value="${hs.timeIntervalSec ?? 0}" min="0">
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Max Size (MB)</label>
|
||||
<input type="number" class="hs-input" data-hoster="${name}" data-hs="maxSizeMb" value="${hs.maxSizeMb ?? 0}" min="0">
|
||||
<span class="hint">0 = unbegrenzt</span>
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Links in Log schreiben</label>
|
||||
<input type="checkbox" class="hs-input" data-hoster="${name}" data-hs="logToFile" ${hs.logToFile !== false ? 'checked' : ''}>
|
||||
<span class="hint">Erfolgreiche Links in fileuploader.log.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function _buildAccountHosterGroupHtml(name, accounts) {
|
||||
const summary = _summarizeHosterGroup(accounts);
|
||||
const isOpen = _hosterGroupOpenState(name, summary);
|
||||
@ -3734,7 +3735,7 @@ function _buildAccountHosterGroupHtml(name, accounts) {
|
||||
${summary.error ? `<span class="account-hoster-group-meta error">${summary.error} Fehler</span>` : ''}
|
||||
${lifeMeta}
|
||||
</div>
|
||||
<div class="account-hoster-group-body" ${bodyStyle}>${cardsHtml}</div>
|
||||
<div class="account-hoster-group-body" ${bodyStyle}>${cardsHtml}${_buildHosterSettingsHtml(name)}</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@ -3799,6 +3800,17 @@ function bindAccountListeners(container) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
const settingsHeader = e.target.closest('[data-hoster-settings-toggle]');
|
||||
if (settingsHeader) {
|
||||
const body = settingsHeader.nextElementSibling;
|
||||
const arrow = settingsHeader.querySelector('.panel-arrow');
|
||||
if (body) {
|
||||
const isOpen = body.style.display !== 'none';
|
||||
body.style.display = isOpen ? 'none' : '';
|
||||
if (arrow) arrow.innerHTML = isOpen ? '▶' : '▼';
|
||||
}
|
||||
return;
|
||||
}
|
||||
const btn = e.target.closest('button');
|
||||
if (!btn) return;
|
||||
if (btn.dataset.accountToggle) return toggleAccount(btn.dataset.accountToggle);
|
||||
@ -3819,6 +3831,12 @@ function bindAccountListeners(container) {
|
||||
}
|
||||
});
|
||||
|
||||
const onHosterSettingInput = (e) => {
|
||||
if (e.target && e.target.classList && e.target.classList.contains('hs-input')) scheduleHosterSettingsSave();
|
||||
};
|
||||
container.addEventListener('input', onHosterSettingInput);
|
||||
container.addEventListener('change', onHosterSettingInput);
|
||||
|
||||
let draggedCard = null;
|
||||
container.addEventListener('dragstart', (e) => {
|
||||
const card = e.target.closest('.account-card[draggable]');
|
||||
|
||||
@ -1024,6 +1024,39 @@ select.hs-input { max-width: none; width: auto; min-width: 140px; }
|
||||
.account-card.drag-over-above { border-top: 2px solid var(--accent); }
|
||||
.account-card.drag-over-below { border-bottom: 2px solid var(--accent); }
|
||||
|
||||
.account-hoster-settings {
|
||||
margin-top: 8px;
|
||||
border-top: 1px solid var(--border);
|
||||
padding-top: 6px;
|
||||
}
|
||||
.account-hoster-settings-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 4px;
|
||||
cursor: pointer;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.02em;
|
||||
text-transform: uppercase;
|
||||
border-radius: 6px;
|
||||
transition: background 0.1s, color 0.1s;
|
||||
}
|
||||
.account-hoster-settings-header:hover { background: rgba(255,255,255,0.03); color: var(--text); }
|
||||
.account-hoster-settings-header .panel-arrow { font-size: 10px; color: var(--text-dim); }
|
||||
.account-hoster-settings-body { padding: 6px 4px 4px; }
|
||||
|
||||
.settings-hoster-pointer {
|
||||
margin-top: 12px;
|
||||
padding: 10px 14px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-muted);
|
||||
background: rgba(62, 167, 255, 0.06);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.account-priority-badge {
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user