UNPKG

@adaptabletools/adaptable

Version:

Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

226 lines (225 loc) 7.14 kB
import StringExtensions from '../../Extensions/StringExtensions'; import { getNextCronOccurrence, isCronExpressionValid as isCronExpressionValidInternal, } from './CronExpression'; const WEEKDAY_TO_CRON = { Sunday: 0, Monday: 1, Tuesday: 2, Wednesday: 3, Thursday: 4, Friday: 5, Saturday: 6, }; const CRON_WEEKDAY_NAMES = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', ]; export function buildCronExpression(preset, hour, minute, options) { const m = clampMinute(minute); const h = clampHour(hour); switch (preset) { case 'daily': return `${m} ${h} * * *`; case 'weekdays': return `${m} ${h} * * 1-5`; case 'selectedDays': { const days = options?.days?.length ? options.days : ['Monday']; const dow = days.map((d) => WEEKDAY_TO_CRON[d]).sort((a, b) => a - b).join(','); return `${m} ${h} * * ${dow}`; } case 'monthly': { const dom = options?.dayOfMonth ?? 1; return `${m} ${h} ${dom} * *`; } case 'custom': return options?.customExpression?.trim() || `${m} ${h} * * *`; default: return `${m} ${h} * * *`; } } export function buildRunAtIso(date, hour, minute) { const d = new Date(date); d.setHours(clampHour(hour), clampMinute(minute), 0, 0); return d.toISOString(); } export function parseTimeFromSchedule(schedule) { if (schedule.IsOneOff && schedule.RunAt) { const d = new Date(schedule.RunAt); return { hour: d.getHours(), minute: d.getMinutes() }; } const parts = schedule.CronExpression?.trim().split(/\s+/) ?? []; if (parts.length >= 2) { const minute = parseInt(parts[0], 10); const hour = parseInt(parts[1], 10); if (!Number.isNaN(minute) && !Number.isNaN(hour)) { return { hour, minute }; } } return { hour: 9, minute: 0 }; } export function inferPresetFromCron(cronExpression) { const cron = cronExpression?.trim(); if (!cron) { return { preset: 'weekdays', days: [], dayOfMonth: 1 }; } const parts = cron.split(/\s+/); if (parts.length < 5) { return { preset: 'custom', days: [], dayOfMonth: 1 }; } const [, , dom, month, dow] = parts; if (dom !== '*' || month !== '*') { if (dom !== '*' && month === '*') { const dayOfMonth = parseInt(dom, 10); return { preset: 'monthly', days: [], dayOfMonth: Number.isNaN(dayOfMonth) ? 1 : dayOfMonth, }; } return { preset: 'custom', days: [], dayOfMonth: 1 }; } if (dow === '*') { return { preset: 'daily', days: [], dayOfMonth: 1 }; } if (dow === '1-5') { return { preset: 'weekdays', days: [], dayOfMonth: 1 }; } const dayNumbers = dow.split(',').map((n) => parseInt(n.trim(), 10)); if (dayNumbers.every((n) => !Number.isNaN(n) && n >= 0 && n <= 6)) { const days = dayNumbers.map((n) => CRON_WEEKDAY_NAMES[n]).filter(Boolean); return { preset: 'selectedDays', days, dayOfMonth: 1 }; } return { preset: 'custom', days: [], dayOfMonth: 1 }; } export function parseOneOffDateFromRunAt(runAt) { if (!runAt) { return ''; } const d = new Date(runAt); if (Number.isNaN(d.getTime())) { return ''; } const y = d.getFullYear(); const mo = `${d.getMonth() + 1}`.padStart(2, '0'); const day = `${d.getDate()}`.padStart(2, '0'); return `${y}-${mo}-${day}`; } export function getNextRunDateFromSchedule(schedule) { if (!schedule) { return null; } try { if (schedule.IsOneOff) { if (!schedule.RunAt) { return null; } const date = new Date(schedule.RunAt); return date > new Date() ? date : null; } if (!schedule.CronExpression?.trim()) { return null; } const now = new Date(); const next = getNextCronOccurrence(schedule.CronExpression.trim(), now); return next && next > now ? next : null; } catch { return null; } } export function isScheduleValid(schedule) { if (!schedule) { return 'Schedule is not specified'; } if (schedule.IsOneOff) { if (!schedule.RunAt) { return 'A date and time is required for a one-off schedule'; } const date = new Date(schedule.RunAt); if (Number.isNaN(date.getTime())) { return 'One-off date is not valid'; } return true; } if (!schedule.CronExpression?.trim()) { return 'A recurring schedule is required'; } const { preset, days } = inferPresetFromCron(schedule.CronExpression); if (preset === 'selectedDays' && days.length === 0) { return 'Select at least one day'; } if (!isCronExpressionValidInternal(schedule.CronExpression.trim())) { return 'Cron expression is not valid'; } return true; } export function getScheduleDescription(schedule) { if (!schedule) { return '[No Schedule]'; } if (schedule.IsOneOff) { if (!schedule.RunAt) { return 'One-off (not set)'; } const d = new Date(schedule.RunAt); return `Once on ${d.toLocaleDateString()} @ ${pad2(d.getHours())}:${pad2(d.getMinutes())}`; } const { preset, days, dayOfMonth } = inferPresetFromCron(schedule.CronExpression); const { hour, minute } = parseTimeFromSchedule(schedule); const time = `@ ${pad2(hour)}:${pad2(minute)}`; switch (preset) { case 'daily': return `Every Day ${time}`; case 'weekdays': return `Weekdays ${time}`; case 'selectedDays': { const names = days.map((d) => getShortDay(d)).join(', '); return `${names || 'Selected Days'} ${time}`; } case 'monthly': return `Monthly on day ${dayOfMonth} ${time}`; case 'custom': return schedule.CronExpression?.trim() || 'Custom Cron'; default: return `${schedule.CronExpression ?? 'Custom'} ${time}`; } } function getShortDay(day) { switch (day) { case 'Sunday': return 'Sun'; case 'Monday': return 'Mon'; case 'Tuesday': return 'Tues'; case 'Wednesday': return 'Weds'; case 'Thursday': return 'Thurs'; case 'Friday': return 'Fri'; case 'Saturday': return 'Sat'; default: return day; } } function pad2(n) { return `${n}`.padStart(2, '0'); } function clampHour(h) { return Math.min(23, Math.max(0, h)); } function clampMinute(m) { return Math.min(59, Math.max(0, m)); } export function isValidCronExpression(expression) { if (StringExtensions.IsNullOrEmpty(expression)) { return false; } return isCronExpressionValidInternal(expression.trim()); }