Files
jerapah-flow/packages/web/src/api/hooks/workflows.js
T
nsrb 7456dece00 feat(workflows): migrate legacy workflows and enhance example handling
- Migrated legacy workflow files from `packages/server/workflows/` to `packages/server/data/workflows/` when the new store is empty.
- Introduced new API endpoints to list and retrieve example workflows.
- Added a dialog component for selecting example workflows when creating new workflows.
- Updated workflow paths and configurations to reflect the new structure.
- Enhanced the README and AGENTS.md documentation to clarify workflow management and usage.

Co-authored-by: Nasyarobby Putra <nasyarobby@gmail.com>
2026-08-22 18:09:22 +07:00

281 lines
8.6 KiB
JavaScript

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "../client.js";
export function useWorkflows(owner) {
return useQuery({
queryKey: ["workflows", owner ?? "all"],
queryFn: async () => {
const params = owner ? { owner } : {};
return (await api.get("/workflows", { params })).data.workflows;
},
});
}
export function useWorkflow(owner, file, enabled = true) {
return useQuery({
queryKey: ["workflows", owner, file],
queryFn: async () =>
(await api.get(`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}`))
.data,
enabled: Boolean(owner && file) && enabled,
});
}
export function useOwners() {
return useQuery({
queryKey: ["owners"],
queryFn: async () => (await api.get("/owners")).data.owners,
});
}
export function useWorkflowExamples() {
return useQuery({
queryKey: ["workflow-examples"],
queryFn: async () => (await api.get("/workflow-examples")).data.examples,
});
}
export function useSaveWorkflow() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file, content, saveAnyway }) =>
(
await api.put(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}`,
{ content, ...(saveAnyway ? { saveAnyway: true } : {}) },
)
).data,
onSuccess: (_data, vars) => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["owners"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
qc.invalidateQueries({
queryKey: ["workflows", vars.owner, vars.file, "revisions"],
});
qc.invalidateQueries({ queryKey: ["workflows", vars.owner, vars.file] });
},
});
}
export function useSetWorkflowEnabled() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file, enabled }) =>
(
await api.patch(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}`,
{ enabled },
)
).data,
onSuccess: (_data, vars) => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["workflows", vars.owner, vars.file] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useDeleteWorkflow() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file }) =>
(
await api.delete(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}`,
)
).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["workflows", "trash"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useDuplicateWorkflow() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file, destOwner, destFile }) =>
(
await api.post(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}/duplicate`,
{
...(destOwner ? { owner: destOwner } : {}),
...(destFile ? { file: destFile } : {}),
},
)
).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["owners"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useRunWorkflow() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file, data }) =>
(
await api.post(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}/run`,
data !== undefined ? { data } : {},
)
).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["runs"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useReregisterWorkflows() {
const qc = useQueryClient();
return useMutation({
mutationFn: async () => (await api.post("/workflows/reregister")).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["scripts"] });
qc.invalidateQueries({ queryKey: ["owners"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useWorkflowTrash() {
return useQuery({
queryKey: ["workflows", "trash"],
queryFn: async () => (await api.get("/workflows/trash")).data.items,
});
}
export function useRestoreWorkflowTrash() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (id) =>
(await api.post(`/workflows/trash/${encodeURIComponent(id)}/restore`)).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["workflows", "trash"] });
qc.invalidateQueries({ queryKey: ["owners"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function usePurgeWorkflowTrash() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (id) =>
(await api.delete(`/workflows/trash/${encodeURIComponent(id)}`)).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows", "trash"] });
},
});
}
export function useWorkflowRevisions(owner, file, enabled = true) {
return useQuery({
queryKey: ["workflows", owner, file, "revisions"],
queryFn: async () =>
(
await api.get(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}/revisions`,
)
).data,
enabled: Boolean(owner && file) && enabled,
});
}
export function useWorkflowRevision(owner, file, revision) {
return useQuery({
queryKey: ["workflows", owner, file, "revisions", revision],
queryFn: async () =>
(
await api.get(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}/revisions/${revision}`,
)
).data,
enabled: Boolean(owner && file && revision != null),
});
}
export function useRevertWorkflowRevision() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, file, revision, saveAnyway }) =>
(
await api.post(
`/workflows/${encodeURIComponent(owner)}/${encodeURIComponent(file)}/revisions/${revision}/revert`,
saveAnyway ? { saveAnyway: true } : {},
)
).data,
onSuccess: (_data, vars) => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["workflows", vars.owner, vars.file] });
qc.invalidateQueries({
queryKey: ["workflows", vars.owner, vars.file, "revisions"],
});
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useCreateWorkflow() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ owner, content, file, saveAnyway }) =>
(
await api.post(`/workflows/${encodeURIComponent(owner)}`, {
content,
...(file ? { file } : {}),
...(saveAnyway ? { saveAnyway: true } : {}),
})
).data,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["owners"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
},
});
}
export function useDownloadWorkflowBackup() {
return useMutation({
mutationFn: async () => {
const res = await api.get("/workflows/backup", { responseType: "blob" });
const disposition = res.headers["content-disposition"] ?? "";
const match = disposition.match(/filename="([^"]+)"/);
const filename = match?.[1] ?? "jerapah-flow-backup.zip";
const url = URL.createObjectURL(res.data);
const a = document.createElement("a");
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
return { ok: true };
},
});
}
export function useRestoreWorkflowBackup() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ file, mode }) => {
const buffer = await file.arrayBuffer();
const zipBase64 = btoa(String.fromCharCode(...new Uint8Array(buffer)));
return (await api.post("/workflows/backup/restore", { zipBase64, mode })).data;
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["workflows"] });
qc.invalidateQueries({ queryKey: ["owners"] });
qc.invalidateQueries({ queryKey: ["scripts"] });
qc.invalidateQueries({ queryKey: ["dashboard"] });
qc.invalidateQueries({ queryKey: ["ops-status"] });
},
});
}