import { useState } from "react";
import { Link, Navigate, useNavigate, useSearchParams } from "react-router-dom";
import { LuActivity, LuCopy, LuPencil, LuPlay, LuPlus, LuRefreshCw, LuTrash2, LuTriangleAlert } from "react-icons/lu";
import { errorMessage } from "../api/client.js";
import {
useDeleteWorkflow,
useDownloadWorkflowBackup,
useRestoreWorkflowBackup,
useReregisterWorkflows,
useRunWorkflow,
useSetWorkflowEnabled,
useWorkflows,
} from "../api/hooks.js";
import { DuplicateWorkflowDialog } from "../components/DuplicateWorkflowDialog.jsx";
import { WorkflowFileIcon } from "../components/WorkflowFileIcon.jsx";
import { formatTime, WorkflowStatusBadge } from "../lib/format.jsx";
import { useNotifications } from "../notifications.jsx";
export function WorkflowsPage() {
const navigate = useNavigate();
const [params] = useSearchParams();
const editParam = params.get("edit");
const { data: workflows = [], isLoading } = useWorkflows();
const [confirmDelete, setConfirmDelete] = useState(null);
const [duplicateSource, setDuplicateSource] = useState(null);
const [runError, setRunError] = useState(null);
const del = useDeleteWorkflow();
const run = useRunWorkflow();
const setEnabled = useSetWorkflowEnabled();
const reregister = useReregisterWorkflows();
const backup = useDownloadWorkflowBackup();
const restoreBackup = useRestoreWorkflowBackup();
const { notify } = useNotifications();
const [restoreMode, setRestoreMode] = useState("merge");
if (editParam) {
const slash = editParam.indexOf("/");
if (slash !== -1) {
const owner = editParam.slice(0, slash);
const file = editParam.slice(slash + 1);
return (
);
}
}
function onRun(w) {
setRunError(null);
run.mutate(
{ owner: w.owner, file: w.file },
{
onSuccess: (data) => {
if (data?.runId) navigate(`/events/${data.runId}`);
},
onError: (err) => {
const runId = err?.response?.data?.runId;
if (runId) {
navigate(`/events/${runId}`);
return;
}
setRunError(`${w.key}: ${errorMessage(err)}`);
},
},
);
}
const runningKey =
run.isPending && run.variables ? `${run.variables.owner}/${run.variables.file}` : null;
const togglingKey =
setEnabled.isPending && setEnabled.variables
? `${setEnabled.variables.owner}/${setEnabled.variables.file}`
: null;
return (
Workflows
Trash
Add
{reregister.isError ? (
{errorMessage(reregister.error)}
) : null}
{runError ?
{runError}
: null}
{setEnabled.isError ? (
{errorMessage(setEnabled.error)}
) : null}
{isLoading ? (
) : (
)}
{duplicateSource ? (
setDuplicateSource(null)}
onDuplicated={(data) => {
setDuplicateSource(null);
navigate(
`/workflows/${encodeURIComponent(data.owner)}/${encodeURIComponent(data.file)}/edit`,
);
}}
/>
) : null}
{confirmDelete ? (
) : null}
);
}
function triggerLabel(t) {
const type = String(t?.type ?? "").toLowerCase();
if (type === "cron") return t.schedule || "cron";
if (type === "http") return t.path || "/";
if (type === "workflow") return "";
return t?.type ?? "—";
}
function triggerKind(t) {
const type = String(t?.type ?? "").toLowerCase();
if (type === "http") return t.method || "POST";
if (type === "workflow") return "workflow";
return t?.type ?? "—";
}
function TriggerList({ triggers }) {
if (!triggers?.length) return —;
return (
{triggers.map((t, i) => (
-
{triggerKind(t)} {triggerLabel(t)}
))}
);
}