import { useState } from "react" import type { JobDetail } from "@/types" import { Field, TextField, FormFooter, useEnvSecrets } from "./fields" interface Props { job: JobDetail onSave: (name: string, config: Record) => Promise onDelete?: (name: string) => Promise } type Obj = Record const obj = (v: unknown): Obj => (v as Obj) ?? {} // A job is a systemd deployment; its launcher is editable like a service's. const LAUNCHERS = ["python", "command", "container", "compose", "node"] function applyLauncher(run: Obj, launcher: string, target: string): Obj { const out: Obj = { ...run, launcher } const t = target.trim() if (launcher === "command") { out.argv = t.split(/\s+/).filter(Boolean) delete out.program } else if (launcher === "python") { out.program = t delete out.argv } else if (launcher === "container") { if (t) out.image = t } else if (launcher === "node") { if (t) out.script = t } else if (launcher === "compose") { if (t) out.file = t } return out } /** Edit a job's deployment config (schedule / run / env). */ export function JobFields({ job, onSave, onDelete }: Props) { const m = job.manifest const run = obj(m.run) const [saving, setSaving] = useState(false) const [saved, setSaved] = useState(false) const [description, setDescription] = useState((m.description as string) ?? "") const [schedule, setSchedule] = useState((m.schedule as string) ?? "") const [launcher, setLauncher] = useState((run.launcher as string) ?? "command") const [runTarget, setRunTarget] = useState( (run.program as string) || ((run.argv as string[]) ?? []).join(" ") || (run.image as string) || (run.script as string) || (run.file as string) || "", ) const { element: envEditor, merged } = useEnvSecrets(obj(obj(m.defaults).env) as Record) const handleSave = async () => { setSaving(true) setSaved(false) try { const config: Record = JSON.parse(JSON.stringify(m)) delete config.id config.description = description || undefined config.schedule = schedule || undefined config.run = applyLauncher(obj(config.run), launcher, runTarget) const env = merged() if (Object.keys(env).length > 0) config.defaults = { ...obj(config.defaults), env } else if (config.defaults) delete (config.defaults as Obj).env await onSave(job.id, config) setSaved(true) setTimeout(() => setSaved(false), 2000) } finally { setSaving(false) } } return (
· setRunTarget(e.target.value)} className="w-56 bg-black/30 border border-[var(--border)] rounded px-2 py-1 text-xs font-mono focus:outline-none focus:border-[var(--primary)]" />
{envEditor} onDelete(job.id) : undefined} deleteLabel="Remove job" confirmMessage={`Remove job "${job.id}" from castle.yaml? Run a deploy afterward to tear down its timer.`} />
) }