awa-ui 0.5.3

Web UI and JSON API for the Awa job queue
Documentation
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";

/** Simple human-readable description of common cron expressions. */
function describeCron(expr: string): string {
  const parts = expr.trim().split(/\s+/);
  if (parts.length < 5) return expr;

  const [minute, hour, dom, month, dow] = parts;

  // Every minute
  if (minute === "*" && hour === "*" && dom === "*" && month === "*" && dow === "*") {
    return "Every minute";
  }

  // Every N minutes
  if (minute?.startsWith("*/") && hour === "*" && dom === "*") {
    return `Every ${minute.slice(2)} minutes`;
  }

  // Every hour at :MM
  if (minute !== "*" && hour === "*" && dom === "*" && month === "*" && dow === "*") {
    return `Every hour at :${minute?.padStart(2, "0")}`;
  }

  // Daily at HH:MM
  if (minute !== "*" && hour !== "*" && dom === "*" && month === "*" && dow === "*") {
    return `Daily at ${hour?.padStart(2, "0")}:${minute?.padStart(2, "0")}`;
  }

  // Specific days of week
  const dayNames: Record<string, string> = {
    "0": "Sun", "1": "Mon", "2": "Tue", "3": "Wed",
    "4": "Thu", "5": "Fri", "6": "Sat", "7": "Sun",
  };

  if (minute !== "*" && hour !== "*" && dom === "*" && month === "*" && dow !== "*") {
    const days = dow?.split(",").map(d => dayNames[d] ?? d).join(", ");
    return `${days} at ${hour?.padStart(2, "0")}:${minute?.padStart(2, "0")}`;
  }

  // Monthly on day N
  if (minute !== "*" && hour !== "*" && dom !== "*" && month === "*" && dow === "*") {
    return `Monthly on day ${dom} at ${hour?.padStart(2, "0")}:${minute?.padStart(2, "0")}`;
  }

  return expr;
}

interface CronExprProps {
  expr: string;
}

export function CronExpr({ expr }: CronExprProps) {
  const description = describeCron(expr);
  const hasDescription = description !== expr;

  if (!hasDescription) {
    return <code className="font-mono">{expr}</code>;
  }

  return (
    <Tooltip>
      <TooltipTrigger className="cursor-default font-mono text-sm underline decoration-dotted decoration-muted-fg/50 underline-offset-4">
        {expr}
      </TooltipTrigger>
      <TooltipContent>
        <p>{description}</p>
      </TooltipContent>
    </Tooltip>
  );
}