Schedule pickers, and target progress at one row
"Check feeds every" becomes a number plus a unit dropdown in both global and per-feed settings; parse_interval gained weeks to back it. The per-feed dropdown can select the global default, clearing the override. Fixes progress painting every pending row: the event carried no enclosure id, so the handler had nothing to target and set the width on all of them. Adding a feed looked like it was downloading everything. Progress, DownloadDone and DownloadError now carry the enclosure id. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdXho5tTkjFLeUXKbEjKBh
This commit is contained in:
@@ -39,7 +39,13 @@ const ctx = {
|
||||
window: { isSecureContext: false, addEventListener(){} },
|
||||
localStorage: { getItem: () => null, setItem(){}, removeItem(){} },
|
||||
navigator: { clipboard: undefined, sendBeacon(){}, mediaSession: undefined },
|
||||
fetch: () => Promise.resolve({ ok: true, status: 200, json: () => Promise.resolve([]), text: () => Promise.resolve('') }),
|
||||
fetch: (url) => Promise.resolve({
|
||||
ok: true, status: 200, text: () => Promise.resolve(''),
|
||||
json: () => Promise.resolve(
|
||||
String(url).includes('/api/settings')
|
||||
? { schedule: 'every 60m', every_mins: 60, download_dir: '/tmp', max_total_gb: 0, max_age_days: 0 }
|
||||
: []),
|
||||
}),
|
||||
EventSource: function () { this.close = () => {}; },
|
||||
MediaMetadata: function () {},
|
||||
Blob: function () {},
|
||||
@@ -59,6 +65,33 @@ try {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// The modals are built on demand, so a load-time check never reaches them. Drive the
|
||||
// ones that construct markup from live data, which is where a bad field reference hides.
|
||||
const feed = {
|
||||
id: 'f', url: 'https://x/rss', title: 'A Feed', image: null, folder: null,
|
||||
keywords: ['a'], allow_explicit: false, auto_download: true, max_new_per_check: 3,
|
||||
schedule: 'every 6h', schedule_mins: 360, every_mins: 360,
|
||||
last_checked: 1, next_check: 2, entries: 1, downloaded: 0, unread: 1, last_error: null,
|
||||
};
|
||||
const drive = [
|
||||
['settingsModal', () => ctx.settingsModal(feed)],
|
||||
['settingsModal (no override)', () => ctx.settingsModal({ ...feed, schedule: null, schedule_mins: null })],
|
||||
['downloadLatestModal', () => ctx.downloadLatestModal(feed)],
|
||||
['removeFeed', () => ctx.removeFeed(feed)],
|
||||
['prefsModal', () => ctx.prefsModal()],
|
||||
];
|
||||
for (const [name, fn] of drive) {
|
||||
try {
|
||||
const r = fn();
|
||||
if (r && typeof r.catch === 'function') r.catch(e => {
|
||||
console.error(`FAIL: ${name} rejected: ${e.message}`); process.exit(1);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`FAIL: ${name} threw: ${e.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (missing.length) {
|
||||
console.error('FAIL: handlers wired to elements that do not exist: ' + [...new Set(missing)].join(', '));
|
||||
process.exit(1);
|
||||
|
||||
Reference in New Issue
Block a user