mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 03:55:38 -04:00
Overhaul system health section with job trigger controls and live timestamps
Rebuild the background jobs card as a sortable table showing each job's schedule, last run time (live-updating via a new useTimeAgo hook), last duration, and a manual trigger button backed by a new POST /api/admin/jobs/trigger route. Extract StatusDot into a shared component. Add cronToHuman() to display schedule patterns as readable strings (e.g. "Every 6h", "Daily at 03:00"). Replace static formatDistanceToNow calls throughout the health section with a LiveTimeAgo component that refreshes every 30 seconds. Also swap a handful of section icons for better visual matches across settings cards.
This commit is contained in:
@@ -32,6 +32,8 @@ export interface SystemHealthData {
|
||||
};
|
||||
jobs: {
|
||||
jobName: string;
|
||||
cronPattern: string | null;
|
||||
nextRunAt: string | null;
|
||||
lastRunAt: string | null;
|
||||
lastDurationMs: number | null;
|
||||
lastStatus: "running" | "success" | "error" | null;
|
||||
@@ -143,6 +145,12 @@ async function getTmdbHealth(): Promise<SystemHealthData["tmdb"]> {
|
||||
}
|
||||
|
||||
function getJobsHealth(): SystemHealthData["jobs"] {
|
||||
// Lazy-import to avoid circular dependency issues at module level
|
||||
const { getJobSchedules } =
|
||||
require("@/lib/cron") as typeof import("@/lib/cron");
|
||||
const schedules = getJobSchedules();
|
||||
const scheduleMap = new Map(schedules.map((s) => [s.jobName, s]));
|
||||
|
||||
return JOB_NAMES.map((jobName) => {
|
||||
const latest = db
|
||||
.select()
|
||||
@@ -153,14 +161,18 @@ function getJobsHealth(): SystemHealthData["jobs"] {
|
||||
.get();
|
||||
|
||||
const isCurrentlyRunning = latest?.status === "running";
|
||||
const schedule = scheduleMap.get(jobName);
|
||||
|
||||
let lastDurationMs: number | null = null;
|
||||
if (latest?.finishedAt && latest.startedAt) {
|
||||
// Prefer the in-memory durationMs column; fall back to timestamp diff
|
||||
let lastDurationMs: number | null = latest?.durationMs ?? null;
|
||||
if (lastDurationMs === null && latest?.finishedAt && latest.startedAt) {
|
||||
lastDurationMs = latest.finishedAt.getTime() - latest.startedAt.getTime();
|
||||
}
|
||||
|
||||
return {
|
||||
jobName,
|
||||
cronPattern: schedule?.pattern ?? null,
|
||||
nextRunAt: schedule?.nextRunAt ?? null,
|
||||
lastRunAt: latest?.startedAt?.toISOString() ?? null,
|
||||
lastDurationMs,
|
||||
lastStatus: (latest?.status as "running" | "success" | "error") ?? null,
|
||||
|
||||
Reference in New Issue
Block a user