}) {
+ const { t } = useTranslation();
+ const phase = p.phase ? t(`scheduler.phase.${p.phase}`, p.phase) : null;
+ const pct =
+ p.total && p.total > 0 ? Math.min(100, Math.round((p.current / p.total) * 100)) : null;
+ return (
+
+
+ {phase}
+
+ {p.total != null
+ ? `${p.current.toLocaleString()} / ${p.total.toLocaleString()}`
+ : p.current.toLocaleString()}
+
+
+
+ {pct != null ? (
+
+ ) : (
+ // Indeterminate: total unknown, so a slim moving sliver instead of a fill.
+
+ )}
+
+
+ );
+}
+
function JobRow({
job,
onSave,
saving,
+ onRun,
+ runDisabled,
}: {
job: SchedulerJob;
onSave: (minutes: number) => void;
saving: boolean;
+ onRun: () => void;
+ runDisabled: boolean;
}) {
const { t } = useTranslation();
const [editing, setEditing] = useState(false);
@@ -153,6 +184,7 @@ function JobRow({
· {job.last_result}
) : null}
+ {job.running && job.progress &&
{job.running ? (
@@ -166,6 +198,16 @@ function JobRow({
"—"
)}
+