openclaw/apps/web/app/components/cron/cron-session-view.tsx
kumarabhirup c21bbb6cea
feat(cron): overhaul dashboard with calendar/timeline/insights views and action bar
Add tabbed views (overview, calendar, timeline, insights) to the cron dashboard, run status filters and action buttons (run now, disable, delete) to job detail, reuse ChatMessage for session transcripts, and wire URL state through workspace content.
2026-03-05 21:20:18 -08:00

99 lines
3.1 KiB
TypeScript

"use client";
import type { CronJob, CronRunLogEntry } from "../../types/cron";
import { ChatPanel } from "../chat-panel";
function formatDuration(ms: number): string {
if (ms < 1000) return `${ms}ms`;
if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
return `${Math.floor(ms / 60_000)}m ${Math.floor((ms % 60_000) / 1000)}s`;
}
export function CronSessionView({
job,
run,
sessionId,
onBack,
onBackToJob,
}: {
job: CronJob;
run: CronRunLogEntry;
sessionId: string;
onBack: () => void;
onBackToJob: () => void;
}) {
const statusColor = run.status === "ok"
? "var(--color-success, #22c55e)"
: run.status === "error"
? "var(--color-error, #ef4444)"
: "var(--color-warning, #f59e0b)";
return (
<div className="h-full flex flex-col">
{/* Header bar */}
<div
className="px-4 py-3 flex items-center gap-3 flex-shrink-0"
style={{
borderBottom: "1px solid var(--color-border)",
background: "var(--color-bg-glass)",
}}
>
<button
type="button"
onClick={onBack}
className="p-1.5 rounded-lg flex-shrink-0 cursor-pointer"
style={{ color: "var(--color-text-muted)" }}
title="Back to Cron"
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="m12 19-7-7 7-7" />
<path d="M19 12H5" />
</svg>
</button>
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2">
<button
type="button"
onClick={onBackToJob}
className="text-sm font-semibold truncate cursor-pointer hover:underline"
style={{ color: "var(--color-text)" }}
title="Back to job detail"
>
{job.name}
</button>
<span
className="text-[10px] px-1.5 py-0.5 rounded-full flex-shrink-0"
style={{
background: `color-mix(in srgb, ${statusColor} 12%, transparent)`,
color: statusColor,
}}
>
{run.status ?? "unknown"}
</span>
</div>
<div className="flex items-center gap-3 text-xs" style={{ color: "var(--color-text-muted)" }}>
<span>{new Date(run.ts).toLocaleString()}</span>
{run.durationMs != null && (
<span>{formatDuration(run.durationMs)}</span>
)}
{run.summary && (
<span className="truncate">{run.summary}</span>
)}
</div>
</div>
</div>
{/* ChatPanel loads the session via initialSessionId.
The web-sessions API falls back to agent sessions, so this
transparently loads cron run transcripts. */}
<div className="flex-1 min-h-0">
<ChatPanel
initialSessionId={sessionId}
sessionTitle={`${job.name} - Run ${new Date(run.ts).toLocaleString()}`}
/>
</div>
</div>
);
}