Make existing controls real + add robustness pass

Wire up controls that were rendered but inert, expose unused server
actions, and harden the live update path.

Controls now functional:
- File priority dropdowns (Content tab) now persist via new
  setFilePriority server action
- Context menu: Set location, Limit download/upload rate, Set share
  limit (wire setSavePath/setDownLimit/setUpLimit/setRatioLimit)
- Trackers sidebar filter actually filters (snapshot now carries
  per-torrent trackerHosts)

Robustness:
- Grid updates cells in place when row order/columns are unchanged
  (preserves text selection/scroll, no per-second listener re-bind)
- Boot retries until the server responds; SSE drops show a
  "Reconnecting" banner; failed actions/add/delete surface a toast
- Prune selection/detail for torrents that disappear
- Drop Backspace-as-delete (kept Delete)

Cleanup:
- Remove pseudo DHT/PeX/LSD names from the real-tracker host pool in
  mock data (they leaked into announce URLs and the sidebar)
- Remove dead detailTab import/export

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ookami125 2026-06-16 21:24:20 -04:00
parent bc1be49a37
commit 0b35571565
5 changed files with 172 additions and 21 deletions

View file

@ -48,7 +48,7 @@ const TAGS = ['archive', 'public', 'private', 'seed-forever', 'hit-and-run', 've
const TRACKER_HOSTS = [
'tracker.opentrackr.org:1337', 'open.demonii.com:1337', 'tracker.torrent.eu.org:451',
'exodus.desync.com:6969', 'tracker.openbittorrent.com:6969', 'private.tracker.lan:2710',
'tracker.dler.org:6969', 'open.stealth.si:80', '** [DHT] **', '** [PeX] **', '** [LSD] **',
'tracker.dler.org:6969', 'open.stealth.si:80',
];
const NAME_TEMPLATES = [

View file

@ -68,10 +68,18 @@ function snapshot() {
forceStart: t.forceStart,
timeActive: t.timeActive,
private: t.private,
trackerHosts: trackerHostsOf(t),
})),
};
}
function hostOf(url) {
try { return new URL(url).host; } catch { return url; }
}
function trackerHostsOf(t) {
return t.trackers.filter((tr) => tr.tier >= 0).map((tr) => hostOf(tr.url));
}
function json(res, data, code = 200) {
const body = JSON.stringify(data);
res.writeHead(code, { 'Content-Type': 'application/json; charset=utf-8' });
@ -107,6 +115,7 @@ const ACTIONS = {
setDownLimit: (t, p) => { t.downLimit = p.limit ?? 0; },
setUpLimit: (t, p) => { t.upLimit = p.limit ?? 0; },
setRatioLimit: (t, p) => { t.ratioLimit = p.limit ?? -1; },
setFilePriority: (t, p) => { if (t.files[p.index]) t.files[p.index].priority = p.priority; },
topPriority: (t) => { t.priority = 1; },
bottomPriority: (t) => { t.priority = 99; },
increasePriority: (t) => { t.priority = Math.max(1, (t.priority || 1) - 1); },