/** * api/flow-templates.js — Client for the Hub /flow/templates CRUD endpoints. * * Mirrors services/targo-hub/lib/flow-templates.js. All requests go through * the Hub (which handles ERPNext auth server-side). * * Functions: * listFlowTemplates({ category?, applies_to?, trigger_event?, is_active?, q? }) * getFlowTemplate(name) * createFlowTemplate(body) * updateFlowTemplate(name, patch) * deleteFlowTemplate(name) * duplicateFlowTemplate(name, newName?) * * All functions return the parsed JSON body or throw on network / 4xx / 5xx. */ import { HUB_URL } from 'src/config/hub' /** Fetch helper with error normalization. */ async function hubFetch (path, { method = 'GET', body } = {}) { const opts = { method, headers: { 'Content-Type': 'application/json' } } if (body) opts.body = JSON.stringify(body) const res = await fetch(`${HUB_URL}${path}`, opts) const text = await res.text() let data try { data = text ? JSON.parse(text) : {} } catch { throw new Error(`Invalid JSON from ${path}: ${text.slice(0, 200)}`) } if (!res.ok) { const msg = data.error || `HTTP ${res.status}` const err = new Error(msg) err.status = res.status err.detail = data.detail throw err } return data } /** * List flow templates with optional filters. * @param {Object} filters { category, applies_to, trigger_event, is_active, q, limit } * @returns {Promise} list of templates (without flow_definition body) */ export async function listFlowTemplates (filters = {}) { const qs = new URLSearchParams() for (const [k, v] of Object.entries(filters)) { if (v !== undefined && v !== null && v !== '') qs.set(k, String(v)) } const path = `/flow/templates${qs.toString() ? '?' + qs.toString() : ''}` const data = await hubFetch(path) return data.templates || [] } /** * Fetch a single template with its parsed flow_definition. * @param {string} name FT-00001 etc. */ export async function getFlowTemplate (name) { const data = await hubFetch(`/flow/templates/${encodeURIComponent(name)}`) return data.template } /** * Create a new (user) template. is_system is forced to 0 by the API. * @param {Object} body { template_name, category, applies_to, flow_definition, ... } */ export async function createFlowTemplate (body) { const data = await hubFetch('/flow/templates', { method: 'POST', body }) return data.template } /** * Patch an existing template. Version is auto-bumped by the API. * @param {string} name * @param {Object} patch subset of fields */ export async function updateFlowTemplate (name, patch) { const data = await hubFetch(`/flow/templates/${encodeURIComponent(name)}`, { method: 'PUT', body: patch, }) return data.template } /** * Delete a template. Blocked server-side if is_system=1. * @param {string} name */ export async function deleteFlowTemplate (name) { await hubFetch(`/flow/templates/${encodeURIComponent(name)}`, { method: 'DELETE' }) } /** * Duplicate a template (e.g. to customize a system template). * Creates an inactive copy (is_active=0) for user to review before enabling. * @param {string} name * @param {string} [newName] optional override (defaults to " (copie)") */ export async function duplicateFlowTemplate (name, newName) { const body = newName ? { template_name: newName } : {} const data = await hubFetch(`/flow/templates/${encodeURIComponent(name)}/duplicate`, { method: 'POST', body, }) return data.template }