webui: automation settings panel, set-location, responsive layout
- Automation tab: settings form (define_settings) beside the editor, stacking above it when narrow; script/settings save split. - Set location modal: current location + reset checkbox. - saveScriptSettings/setSavePath API wiring; plugins panel. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5a5b5f4330
commit
9a1d67acd4
11 changed files with 741 additions and 13 deletions
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
import { api } from './api.js';
|
||||
import * as f from './format.js';
|
||||
import { pluginDetailTabs, renderPluginDetailPanels, renderPluginDetailTab } from './plugins.js';
|
||||
|
||||
const TABS = ['general', 'trackers', 'peers', 'content', 'pieces'];
|
||||
const BUILTIN_TABS = ['general', 'trackers', 'peers', 'content', 'pieces'];
|
||||
let activeTab = 'general';
|
||||
let currentHash = null;
|
||||
let refreshTimer = null;
|
||||
|
|
@ -22,7 +23,7 @@ export function renderDetailShell(hash, host) {
|
|||
<div class="detail" id="detailPanel">
|
||||
<div class="detail-resize" id="detailResize" title="Drag to resize"></div>
|
||||
<div class="detail-tabs">
|
||||
${TABS.map((t) => `<button class="dtab ${t === activeTab ? 'active' : ''}" data-dtab="${t}">${tabLabel(t)}</button>`).join('')}
|
||||
${detailTabs().map((t) => `<button class="dtab ${t.id === activeTab ? 'active' : ''}" data-dtab="${t.id}">${t.label}</button>`).join('')}
|
||||
<button class="dtab detail-close" data-act="closeDetail" title="Close detail (Esc)">✕</button>
|
||||
</div>
|
||||
<div class="detail-body" id="detailBody"></div>
|
||||
|
|
@ -39,6 +40,13 @@ function tabLabel(t) {
|
|||
return { general: 'General', trackers: 'Trackers', peers: 'Peers', content: 'Content', pieces: 'Pieces' }[t];
|
||||
}
|
||||
|
||||
function detailTabs() {
|
||||
return [
|
||||
...BUILTIN_TABS.map((id) => ({ id, label: tabLabel(id) })),
|
||||
...pluginDetailTabs().map((tab) => ({ id: tab.id, label: tab.label })),
|
||||
];
|
||||
}
|
||||
|
||||
export function closeDetail() {
|
||||
currentHash = null;
|
||||
if (refreshTimer) clearInterval(refreshTimer);
|
||||
|
|
@ -58,6 +66,7 @@ async function loadTab() {
|
|||
else if (activeTab === 'peers') body.innerHTML = renderPeers(await api.peers(currentHash));
|
||||
else if (activeTab === 'content') { body.innerHTML = renderFiles(await api.files(currentHash)); bindFilePriorities(body); }
|
||||
else if (activeTab === 'pieces') body.innerHTML = renderPieces(await api.pieces(currentHash));
|
||||
else await renderPluginDetailTab(activeTab, body, { api, f, hash: currentHash });
|
||||
} catch { /* ignore transient */ }
|
||||
};
|
||||
await render();
|
||||
|
|
@ -107,6 +116,7 @@ function renderGeneral(t) {
|
|||
${row('Auto TMM', t.autoTMM ? 'On' : 'Off')}
|
||||
${row('Force start', t.forceStart ? 'On' : 'Off')}
|
||||
${t.comment ? row('Comment', f.esc(t.comment)) : ''}
|
||||
${renderPluginDetailPanels(t, { api, f, hash: t.hash })}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue