feat: one Missing files page under Collection: folders gone, each with its album's want, last search or download, and Search, Releases and Remove; an album held before its files went is no longer shown as held again (M504 #5626)
release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m30s
release / go (push) Successful in 1m46s
release / integration (push) Successful in 5m23s
release / android (push) Successful in 5m43s
release / Build signed APK (releases and dev) (push) Successful in 6m2s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m30s
release / go (push) Successful in 1m46s
release / integration (push) Successful in 5m23s
release / android (push) Successful in 5m43s
release / Build signed APK (releases and dev) (push) Successful in 6m2s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { relativeTime } from '#lib/utils/relativeTime.js';
|
||||
import type { SearchResult, Want } from '#lib/api/types.js';
|
||||
|
||||
// How a want reads in a line, wherever it is shown: the Collection's lists
|
||||
// and the Missing page's folders (M504).
|
||||
|
||||
// What a Search the operator ran found, for its toast.
|
||||
export function searched(w: Want, r: SearchResult): string {
|
||||
let said: string;
|
||||
switch (r.outcome) {
|
||||
case 'grabbed':
|
||||
said = `Took ${r.grabbed ?? r.best_release}.`;
|
||||
break;
|
||||
case 'waiting':
|
||||
said = `Found ${r.considered}; nothing taken. Releases shows why.`;
|
||||
break;
|
||||
case 'nothing':
|
||||
said = r.considered ? `Found ${r.considered}, none of them ${w.title}.` : `Nothing found for ${w.title}.`;
|
||||
break;
|
||||
default:
|
||||
said = r.error ?? 'The search failed.';
|
||||
}
|
||||
if (r.narrowed.length) said += ` ${r.narrowed.map((n) => n.label).join(', ')} didn't answer.`;
|
||||
return said;
|
||||
}
|
||||
|
||||
// A download still running, in a line: how far it has got, or what its
|
||||
// import is doing or waiting on.
|
||||
export function downloading(w: Want): string | null {
|
||||
const g = w.grab;
|
||||
if (!g?.live) return null;
|
||||
switch (g.import_state) {
|
||||
case 'downloading':
|
||||
return `Downloading ${Math.floor(g.progress * 100)}% · ${g.name}`;
|
||||
case 'importing':
|
||||
return `Downloaded; checking it is the album and filing it · ${g.name}`;
|
||||
case 'waiting':
|
||||
return `Downloaded; ${g.import_reason || 'waiting to be imported'}`;
|
||||
case 'review':
|
||||
return `Needs you: ${g.import_reason}`;
|
||||
case 'failed':
|
||||
return `Import failed: ${g.import_reason}`;
|
||||
}
|
||||
const who = g.origin === 'operator' ? 'taken by you' : 'taken by the schedule';
|
||||
return `Downloading ${g.name}, ${who} ${relativeTime(g.grabbed_at)}`;
|
||||
}
|
||||
|
||||
// A download waiting on a person: an import to review, or one that failed.
|
||||
export const needsYou = (w: Want) =>
|
||||
!!w.grab?.live && (w.grab.import_state === 'review' || w.grab.import_state === 'failed');
|
||||
|
||||
// What the schedule last did about a want, in a line.
|
||||
export function wantStatus(w: Want): string {
|
||||
const live = downloading(w);
|
||||
if (live) return live;
|
||||
const s = w.search;
|
||||
let said = 'Not searched yet';
|
||||
if (s) {
|
||||
const when = `Searched ${relativeTime(s.searched_at)}`;
|
||||
switch (s.outcome) {
|
||||
case 'nothing':
|
||||
said = s.considered ? `${when}: ${s.considered} found, none of them this album` : `${when}: nothing found`;
|
||||
break;
|
||||
case 'waiting':
|
||||
said = `${when}: ${s.considered} found, nothing taken`;
|
||||
break;
|
||||
case 'grabbed':
|
||||
said = `${when}: took ${s.best_release}`;
|
||||
break;
|
||||
default:
|
||||
said = `${when}: ${s.error}`;
|
||||
}
|
||||
}
|
||||
const g = w.grab;
|
||||
if (g?.import_state === 'refused') said += `. Last download refused: ${g.import_reason}`;
|
||||
else if (g && !g.live && ['stalled', 'failed', 'gone'].includes(g.end_reason) && g.end_detail)
|
||||
said += `. Last download given up: ${g.end_detail}`;
|
||||
return said;
|
||||
}
|
||||
Reference in New Issue
Block a user