Merge bug/scheduler-progress-visibility: live progress for any scheduler job + parallel RSS polling

This commit is contained in:
npeter83 2026-06-19 02:45:36 +02:00
commit 7fd335aa90
9 changed files with 91 additions and 25 deletions

View file

@ -21,6 +21,8 @@ import { notify } from "../lib/notifications";
import Tooltip from "./Tooltip";
const POLL_MS = 4000;
// While any job is running, poll faster so short scheduled runs aren't missed between ticks.
const FAST_POLL_MS = 1500;
// Seconds until an ISO instant (negative = past).
function secsUntil(iso: string | null): number | null {
@ -73,19 +75,25 @@ function StatusLegend() {
);
}
function JobProgress({ p }: { p: NonNullable<SchedulerJob["progress"]> }) {
// Shown for ANY running job. With reported counts it's a determinate bar; for a job that
// runs but doesn't report progress (or hasn't yet) it falls back to a generic "working"
// label and an indeterminate sliver — so every active run is visible, not just the ones
// that report numbers.
function JobProgress({ p }: { p: SchedulerJob["progress"] }) {
const { t } = useTranslation();
const phase = p.phase ? t(`scheduler.phase.${p.phase}`, p.phase) : null;
const phase = p?.phase ? t(`scheduler.phase.${p.phase}`, p.phase) : t("scheduler.phase.working");
const pct =
p.total && p.total > 0 ? Math.min(100, Math.round((p.current / p.total) * 100)) : null;
p?.total && p.total > 0 ? Math.min(100, Math.round((p.current / p.total) * 100)) : null;
return (
<div className="mt-1.5">
<div className="flex items-center justify-between text-[11px] text-muted mb-0.5">
<span className="truncate">{phase}</span>
<span className="tabular-nums shrink-0">
{p.total != null
{p?.total != null
? `${p.current.toLocaleString()} / ${p.total.toLocaleString()}`
: p.current.toLocaleString()}
: p
? p.current.toLocaleString()
: ""}
</span>
</div>
<div className="h-1.5 rounded-full bg-border overflow-hidden">
@ -184,7 +192,7 @@ function JobRow({
<span> · {job.last_result}</span>
) : null}
</div>
{job.running && job.progress && <JobProgress p={job.progress} />}
{job.running && <JobProgress p={job.progress} />}
</div>
<div className="shrink-0 text-right text-[11px] text-muted tabular-nums">
{job.running ? (
@ -298,8 +306,10 @@ function Stat({
export default function Scheduler() {
const { t } = useTranslation();
const qc = useQueryClient();
// Poll faster while any job is running so live progress is smooth, then ease back when
// idle. Derived from the freshest data by react-query itself (see useLiveQuery).
const q = useLiveQuery<SchedulerStatus>(["scheduler"], api.schedulerStatus, {
intervalMs: POLL_MS,
intervalMs: (d) => (d?.jobs?.some((j) => j.running) ? FAST_POLL_MS : POLL_MS),
});
const data = q.data;