feat: complete node task 2a

This commit is contained in:
Ayobami
2025-07-28 06:42:00 +01:00
parent fe95626d9f
commit bd70df60b9
17 changed files with 1968 additions and 170 deletions
+227
View File
@@ -0,0 +1,227 @@
// DOM elements
const createFlowBtn = document.getElementById("create-flow-btn");
const flowNameInput = document.getElementById("flow-name");
const flowDescriptionInput = document.getElementById("flow-description");
const flowSelect = document.getElementById("flow-select");
const actionTypeSelect = document.getElementById("action-type");
const taskInput = document.getElementById("task-input");
const orderIndexInput = document.getElementById("order-index");
const addTaskBtn = document.getElementById("add-task-btn");
const flowDetails = document.getElementById("flow-details");
const executeFlowSelect = document.getElementById("execute-flow-select");
const executePayloadInput = document.getElementById("execute-payload");
const executeBtn = document.getElementById("execute-btn");
const webhookBtn = document.getElementById("webhook-btn");
const executionResults = document.getElementById("execution-results");
let currentFlows = [];
// Create new flow
async function createFlow() {
const name = flowNameInput.value.trim();
const description = flowDescriptionInput.value.trim();
if (!name) {
alert("Flow name is required");
return;
}
try {
const response = await fetch("/flow", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, description }),
});
if (response.ok) {
const flow = await response.json();
alert(`Flow "${flow.name}" created successfully!`);
flowNameInput.value = "";
flowDescriptionInput.value = "";
loadFlows();
} else {
const error = await response.json();
alert(`Error: ${error.error}`);
}
} catch (err) {
alert("Failed to create flow");
}
}
// Load all flows
async function loadFlows() {
try {
const response = await fetch("/flows");
const flows = await response.json();
currentFlows = flows;
// Update flow selects
flowSelect.innerHTML = '<option value="">Select Flow</option>';
executeFlowSelect.innerHTML =
'<option value="">Select Flow to Execute</option>';
flows.forEach((flow) => {
flowSelect.innerHTML += `<option value="${flow.id}">${flow.name}</option>`;
executeFlowSelect.innerHTML += `<option value="${flow.id}">${flow.name}</option>`;
});
} catch (err) {
console.error("Failed to load flows");
}
}
// Add task to flow
async function addTask() {
const flowId = flowSelect.value;
const actionType = actionTypeSelect.value;
const inputData = taskInput.value.trim();
const orderIndex = parseInt(orderIndexInput.value);
if (!flowId || !actionType || !inputData || isNaN(orderIndex)) {
alert("All fields are required");
return;
}
try {
const response = await fetch(`/flow/${flowId}/task`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
action_type: actionType,
input_data: inputData,
order_index: orderIndex,
}),
});
if (response.ok) {
const task = await response.json();
alert(`Task "${task.action_type}" added successfully!`);
taskInput.value = "";
orderIndexInput.value = "";
loadFlowDetails(flowId);
} else {
const error = await response.json();
alert(`Error: ${error.error}`);
}
} catch (err) {
alert("Failed to add task");
}
}
// Load flow details
async function loadFlowDetails(flowId) {
if (!flowId) return;
try {
const response = await fetch(`/flow/${flowId}`);
const data = await response.json();
flowDetails.innerHTML = `
<div class="border rounded p-4">
<h3 class="font-semibold text-lg">${data.flow.name}</h3>
<p class="text-gray-600">${
data.flow.description || "No description"
}</p>
<div class="mt-4">
<h4 class="font-medium">Tasks:</h4>
<div class="space-y-2 mt-2">
${data.tasks
.map(
(task) => `
<div class="bg-gray-100 p-2 rounded">
<div class="font-medium">${task.action_type}</div>
<div class="text-sm text-gray-600">Input: ${task.input_data}</div>
<div class="text-xs text-gray-500">Order: ${task.order_index}</div>
</div>
`
)
.join("")}
</div>
</div>
</div>
`;
} catch (err) {
console.error("Failed to load flow details");
}
}
// Execute flow
async function executeFlow() {
const flowId = executeFlowSelect.value;
const payload = executePayloadInput.value.trim();
if (!flowId) {
alert("Please select a flow to execute");
return;
}
try {
const response = await fetch(`/flow/${flowId}/execute`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ payload }),
});
if (response.ok) {
const result = await response.json();
showExecutionResults(result);
} else {
const error = await response.json();
alert(`Error: ${error.error}`);
}
} catch (err) {
alert("Failed to execute flow");
}
}
// Show execution results
function showExecutionResults(result) {
executionResults.innerHTML = `
<h4 class="font-semibold mb-2">Execution Results:</h4>
<div class="space-y-2">
${result.results
.map(
(r) => `
<div class="p-2 ${
r.status === "success" ? "bg-green-100" : "bg-red-100"
} rounded">
<div class="font-medium">Task ${r.task_id}</div>
<div class="text-sm">${r.result}</div>
<div class="text-xs text-gray-600">Status: ${r.status}</div>
</div>
`
)
.join("")}
</div>
`;
executionResults.classList.remove("hidden");
}
// Get webhook URL
function getWebhookUrl() {
const flowId = executeFlowSelect.value;
if (!flowId) {
alert("Please select a flow");
return;
}
const webhookUrl = `${window.location.origin}/flow/${flowId}/trigger?payload=test@example.com`;
alert(
`Webhook URL:\n${webhookUrl}\n\nCopy this URL to trigger the flow via webhook.`
);
}
// Event listeners
createFlowBtn.addEventListener("click", createFlow);
addTaskBtn.addEventListener("click", addTask);
executeBtn.addEventListener("click", executeFlow);
webhookBtn.addEventListener("click", getWebhookUrl);
flowSelect.addEventListener("change", (e) => {
if (e.target.value) {
loadFlowDetails(e.target.value);
}
});
// Initialize
loadFlows();