({ jobs }: CronWeeklyTimelineProps)
| 88 | } |
| 89 | |
| 90 | export function CronWeeklyTimeline({ jobs }: CronWeeklyTimelineProps) { |
| 91 | const now = useMemo(() => new Date(), []); |
| 92 | const sevenDaysOut = useMemo( |
| 93 | () => new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000), |
| 94 | [now] |
| 95 | ); |
| 96 | |
| 97 | const days = useMemo<DayColumn[]>(() => { |
| 98 | const enabledJobs = jobs.filter((j) => j.enabled); |
| 99 | |
| 100 | // Compute all events for next 7 days |
| 101 | const allEvents: ScheduledEvent[] = []; |
| 102 | const intervalJobMap = new Map< |
| 103 | string, |
| 104 | { job: CronJob; color: string; intervalLabel: string } |
| 105 | >(); |
| 106 | |
| 107 | enabledJobs.forEach((job, idx) => { |
| 108 | const color = getJobColor(idx); |
| 109 | const expr = getScheduleExpr(job.schedule); |
| 110 | const intervalMs = getIntervalMs(job.schedule); |
| 111 | const atTime = getAtTime(job.schedule); |
| 112 | |
| 113 | if (expr && isValidCron(expr)) { |
| 114 | // Cron: compute next N runs |
| 115 | const runs = getNextRuns(expr, 50, now); |
| 116 | runs |
| 117 | .filter((r) => r >= startOfDay(now) && r <= sevenDaysOut) |
| 118 | .forEach((time) => { |
| 119 | allEvents.push({ job, time, color, isInterval: false }); |
| 120 | }); |
| 121 | } else if (intervalMs) { |
| 122 | // Interval job: show in each day but don't enumerate every tick |
| 123 | // Just mark the days it's "active" |
| 124 | const label = formatIntervalLabel(intervalMs); |
| 125 | if (!intervalJobMap.has(job.id)) { |
| 126 | intervalJobMap.set(job.id, { job, color, intervalLabel: label }); |
| 127 | } |
| 128 | // If interval >= 24h, show individual occurrences |
| 129 | if (intervalMs >= 86400000) { |
| 130 | let next = job.nextRun ? new Date(job.nextRun) : now; |
| 131 | while (next <= sevenDaysOut) { |
| 132 | if (next >= startOfDay(now)) { |
| 133 | allEvents.push({ job, time: new Date(next), color, isInterval: true }); |
| 134 | } |
| 135 | next = new Date(next.getTime() + intervalMs); |
| 136 | } |
| 137 | } |
| 138 | } else if (atTime && atTime > now && atTime <= sevenDaysOut) { |
| 139 | // One-time job |
| 140 | allEvents.push({ job, time: atTime, color, isInterval: false }); |
| 141 | } |
| 142 | }); |
| 143 | |
| 144 | // Build day columns |
| 145 | const columns: DayColumn[] = []; |
| 146 | for (let i = 0; i < 7; i++) { |
| 147 | const date = addDays(startOfDay(now), i); |
nothing calls this directly
no test coverage detected