Skip to content
Merged
18 changes: 18 additions & 0 deletions backend/backend/core/scheduler/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@
logger = logging.getLogger(__name__)



def _compute_next_run_time(periodic, last_run_at):
"""Derive the next run time from a PeriodicTask's schedule."""
if not periodic or not periodic.enabled:
return None
try:
schedule = periodic.schedule
reference = last_run_at or periodic.last_run_at or timezone.now()
remaining = schedule.remaining_estimate(reference)
Comment thread
abhizipstack marked this conversation as resolved.
return timezone.now() + remaining
except Exception:
Comment thread
abhizipstack marked this conversation as resolved.
logger.debug("Failed to compute next_run_time for %s", periodic, exc_info=True)
return None


def _is_valid_project_id(project_id):
"""Check if project_id is a real UUID (not a placeholder like '_all' or 'all')."""
try:
Expand Down Expand Up @@ -164,6 +179,9 @@ def _serialize_task(task):
"task_status": task.status,
"task_run_time": task.task_run_time,
"task_completion_time": task.task_completion_time,
"next_run_time": task.next_run_time or _compute_next_run_time(
periodic, task.task_run_time
),
"task_type": task_type,
"description": task.description,
"environment": {
Expand Down
35 changes: 26 additions & 9 deletions frontend/src/common/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,31 @@ const getRelativeTime = (dateString) => {
const now = new Date();
const then = new Date(dateString);
const diffMs = now - then;
const diffMins = Math.floor(diffMs / 60000);
if (diffMins < 1) return "just now";
if (diffMins < 60) return `${diffMins}m ago`;
const diffHrs = Math.floor(diffMins / 60);
if (diffHrs < 24) return `${diffHrs}h ago`;
const diffDays = Math.floor(diffHrs / 24);
if (diffDays < 30) return `${diffDays}d ago`;
const diffMonths = Math.floor(diffDays / 30);
return `${diffMonths}mo ago`;
const isPast = diffMs >= 0;
const absMs = Math.abs(diffMs);
const mins = Math.floor(absMs / 60000);
const fmt = (n, unit) => (isPast ? `${n}${unit} ago` : `in ${n}${unit}`);
if (mins < 1) return isPast ? "just now" : "in a moment";
if (mins < 60) return fmt(mins, "m");
const hrs = Math.floor(mins / 60);
if (hrs < 24) return fmt(hrs, "h");
const days = Math.floor(hrs / 24);
if (days < 30) return fmt(days, "d");
const months = Math.floor(days / 30);
return fmt(months, "mo");
};

const formatDateTime = (dateString) => {
if (!dateString) return "";
const d = new Date(dateString);
if (Number.isNaN(d.getTime())) return "";
return d.toLocaleString(undefined, {
month: "short",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit",
});
};

export {
Expand All @@ -388,4 +404,5 @@ export {
extractFormulaExpression,
validateFormulaExpression,
getRelativeTime,
formatDateTime,
};
Loading
Loading