FlowForge/frontend/integration-guide.md

6.0 KiB

FlowForge Frontend Integration Guide

This guide provides instructions for integrating the new components we've created into the existing WorkflowEditor.js file.

Step 1: Import New Components

Add these imports at the top of your WorkflowEditor.js file:

import Modal from '../components/common/Modal';
import WorkflowEditorTabs from '../components/workflow/WorkflowEditorTabs';
import WorkflowEditorActions from '../components/workflow/WorkflowEditorActions';
import NodeTester from '../components/workflow/NodeTester';
import ExecutionResults from '../components/execution/ExecutionResults';

Step 2: Add New State Variables

Add these state variables inside your WorkflowEditor component:

const [showNodeTester, setShowNodeTester] = useState(false);
const [showExecutionResults, setShowExecutionResults] = useState(false);
const [latestExecutionId, setLatestExecutionId] = useState(null);
const [currentVersion, setCurrentVersion] = useState(1);
const [showTabs, setShowTabs] = useState(true);

Step 3: Add New Methods

Add these methods inside your WorkflowEditor component:

// Duplicate a node
const handleDuplicateNode = (node) => {
  const newNode = {
    ...node,
    id: `${node.id}-copy-${Date.now()}`,
    position: {
      x: node.position.x + 50,
      y: node.position.y + 50
    }
  };
  
  setNodes((nds) => nds.concat(newNode));
};

// Delete a node
const handleDeleteNode = (node) => {
  setNodes((nds) => nds.filter((n) => n.id !== node.id));
  setEdges((eds) => eds.filter((e) => e.source !== node.id && e.target !== node.id));
  setSelectedNode(null);
};

// Handle workflow execution
const handleExecuteWorkflow = (executionId) => {
  setLatestExecutionId(executionId);
};

// Handle version restoration
const handleRestoreVersion = async (version) => {
  try {
    setIsLoading(true);
    const response = await api.get(`/api/workflows/${id}/versions/${version}`);
    const workflowData = response.data.workflow;
    
    // Update workflow data
    setWorkflow({
      ...workflow,
      name: workflowData.name,
      description: workflowData.description
    });
    
    // Convert backend nodes/connections to React Flow format
    const flowNodes = workflowData.nodes.map(node => ({
      id: node.id,
      type: 'customNode',
      position: { x: node.position_x, y: node.position_y },
      data: { 
        label: node.name,
        nodeType: node.type,
        config: node.config || {}
      }
    }));
    
    const flowEdges = workflowData.connections.map(conn => ({
      id: conn.id,
      source: conn.source_node_id,
      target: conn.target_node_id,
      sourceHandle: conn.source_handle,
      targetHandle: conn.target_handle
    }));
    
    setNodes(flowNodes);
    setEdges(flowEdges);
    setCurrentVersion(version);
    toast.success(`Restored workflow to version ${version}`);
  } catch (error) {
    console.error('Error restoring version:', error);
    toast.error('Failed to restore workflow version');
  } finally {
    setIsLoading(false);
  }
};

Step 4: Update the Return Statement

Replace the existing buttons in the workflow header with the WorkflowEditorActions component:

<div className="flex space-x-2">
  <button
    onClick={handleSave}
    disabled={isSaving}
    className="px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 disabled:opacity-50"
  >
    {isSaving ? 'Saving...' : 'Save'}
  </button>
  
  <WorkflowEditorActions
    workflowId={id}
    selectedNode={selectedNode}
    onDuplicateNode={handleDuplicateNode}
    onDeleteNode={handleDeleteNode}
    onExecuteWorkflow={handleExecuteWorkflow}
  />
</div>

Step 5: Add the Tabs Component

Add the WorkflowEditorTabs component at the bottom of your component, just before the closing div of the main container:

{/* Workflow Tabs */}
{id && id !== 'new' && showTabs && (
  <div className="border-t border-gray-200">
    <WorkflowEditorTabs
      workflowId={id}
      nodes={nodes}
      currentVersion={currentVersion}
      onRestoreVersion={handleRestoreVersion}
    />
  </div>
)}

Step 6: Add Toggle Button for Tabs

Add a button to toggle the tabs visibility in the workflow header:

<button
  onClick={() => setShowTabs(!showTabs)}
  className="ml-2 inline-flex items-center p-1 border border-gray-300 rounded text-gray-500 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
>
  {showTabs ? (
    <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
      <path fillRule="evenodd" d="M5 10a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1z" clipRule="evenodd" />
    </svg>
  ) : (
    <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
      <path fillRule="evenodd" d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z" clipRule="evenodd" />
    </svg>
  )}
</button>

Step 7: Fetch Current Version on Load

Update the fetchData method to get the current version:

// If editing existing workflow, fetch it
if (id && id !== 'new') {
  const workflowResponse = await api.get(`/api/workflows/${id}`);
  const workflowData = workflowResponse.data.workflow;
  
  setWorkflow({
    id: workflowData.id,
    name: workflowData.name,
    description: workflowData.description
  });
  
  // Set current version
  setCurrentVersion(workflowData.version || 1);
  
  // Rest of the existing code...
}

Testing Your Integration

After making these changes, you should be able to:

  1. Test individual nodes with the NodeTester component
  2. View execution history in the tabs
  3. Schedule workflows with the CronScheduler component
  4. Manage workflow versions with the VersionHistory component
  5. View and copy webhook URLs with the WebhookManager component

If you encounter any issues, check the browser console for errors and verify that all the components are properly imported and integrated.