mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(web): CronPage crash when rendering schedule object
The cron API returns schedule as {kind, expr, display} object but
CronPage.tsx rendered it directly as a React child, crashing with
'Objects are not valid as a React child'.
- Update CronJob interface in api.ts to match actual API response
- Use schedule_display (string) instead of schedule (object)
- Use state instead of status for job state
- Use last_error instead of error for error display
This commit is contained in:
parent
8dfee98d06
commit
70f490a12a
2 changed files with 19 additions and 12 deletions
|
|
@ -222,12 +222,14 @@ export interface CronJob {
|
|||
id: string;
|
||||
name?: string;
|
||||
prompt: string;
|
||||
schedule: string;
|
||||
status: "enabled" | "paused" | "error";
|
||||
schedule: { kind: string; expr: string; display: string };
|
||||
schedule_display: string;
|
||||
enabled: boolean;
|
||||
state: string;
|
||||
deliver?: string;
|
||||
last_run_at?: string | null;
|
||||
next_run_at?: string | null;
|
||||
error?: string | null;
|
||||
last_error?: string | null;
|
||||
}
|
||||
|
||||
export interface SkillInfo {
|
||||
|
|
|
|||
|
|
@ -19,10 +19,14 @@ function formatTime(iso?: string | null): string {
|
|||
|
||||
const STATUS_VARIANT: Record<string, "success" | "warning" | "destructive"> = {
|
||||
enabled: "success",
|
||||
scheduled: "success",
|
||||
paused: "warning",
|
||||
error: "destructive",
|
||||
exhausted: "destructive",
|
||||
};
|
||||
|
||||
|
||||
|
||||
export default function CronPage() {
|
||||
const [jobs, setJobs] = useState<CronJob[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
|
@ -75,7 +79,8 @@ export default function CronPage() {
|
|||
|
||||
const handlePauseResume = async (job: CronJob) => {
|
||||
try {
|
||||
if (job.status === "paused") {
|
||||
const isPaused = job.state === "paused";
|
||||
if (isPaused) {
|
||||
await api.resumeCronJob(job.id);
|
||||
showToast(`Resumed "${job.name || job.prompt.slice(0, 30)}"`, "success");
|
||||
} else {
|
||||
|
|
@ -212,8 +217,8 @@ export default function CronPage() {
|
|||
<span className="font-medium text-sm truncate">
|
||||
{job.name || job.prompt.slice(0, 60) + (job.prompt.length > 60 ? "..." : "")}
|
||||
</span>
|
||||
<Badge variant={STATUS_VARIANT[job.status] ?? "secondary"}>
|
||||
{job.status}
|
||||
<Badge variant={STATUS_VARIANT[job.state] ?? "secondary"}>
|
||||
{job.state}
|
||||
</Badge>
|
||||
{job.deliver && job.deliver !== "local" && (
|
||||
<Badge variant="outline">{job.deliver}</Badge>
|
||||
|
|
@ -225,12 +230,12 @@ export default function CronPage() {
|
|||
</p>
|
||||
)}
|
||||
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
||||
<span className="font-mono">{job.schedule}</span>
|
||||
<span className="font-mono">{job.schedule_display}</span>
|
||||
<span>Last: {formatTime(job.last_run_at)}</span>
|
||||
<span>Next: {formatTime(job.next_run_at)}</span>
|
||||
</div>
|
||||
{job.error && (
|
||||
<p className="text-xs text-destructive mt-1">{job.error}</p>
|
||||
{job.last_error && (
|
||||
<p className="text-xs text-destructive mt-1">{job.last_error}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
|
@ -239,11 +244,11 @@ export default function CronPage() {
|
|||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
title={job.status === "paused" ? "Resume" : "Pause"}
|
||||
aria-label={job.status === "paused" ? "Resume job" : "Pause job"}
|
||||
title={job.state === "paused" ? "Resume" : "Pause"}
|
||||
aria-label={job.state === "paused" ? "Resume job" : "Pause job"}
|
||||
onClick={() => handlePauseResume(job)}
|
||||
>
|
||||
{job.status === "paused" ? (
|
||||
{job.state === "paused" ? (
|
||||
<Play className="h-4 w-4 text-success" />
|
||||
) : (
|
||||
<Pause className="h-4 w-4 text-warning" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue