theaimoron's picture
Add 3 files
309ebd5 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FlowForge - No-Code Automation</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.node {
position: absolute;
width: 200px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
cursor: move;
overflow: hidden;
transition: all 0.2s ease;
z-index: 10;
}
.node:hover {
box-shadow: 0 4px 15px rgba(0,0,0,0.15);
}
.node-header {
padding: 8px 12px;
font-weight: 600;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
}
.node-body {
padding: 12px;
}
.node-port {
width: 12px;
height: 12px;
border-radius: 50%;
background: #555;
position: absolute;
cursor: pointer;
top: 50%;
transform: translateY(-50%);
}
.node-input {
left: -6px;
}
.node-output {
right: -6px;
}
.connection {
position: absolute;
pointer-events: none;
z-index: 5;
}
.workflow-area {
position: relative;
width: 100%;
height: calc(100vh - 60px);
background-color: #f8f9fa;
background-image:
linear-gradient(#e5e7eb 1px, transparent 1px),
linear-gradient(90deg, #e5e7eb 1px, transparent 1px);
background-size: 20px 20px;
overflow: hidden;
}
.node-option {
padding: 8px 12px;
border-radius: 4px;
margin-bottom: 4px;
cursor: pointer;
}
.node-option:hover {
background: #f0f4f8;
}
.node-selected {
box-shadow: 0 0 0 2px #3b82f6;
}
.connection-path {
stroke: #888;
stroke-width: 2;
fill: none;
}
.sidebar {
transition: all 0.3s ease;
}
.node-config {
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.page {
display: none;
height: 100%;
}
.page.active {
display: block;
}
.nav-link {
position: relative;
}
.nav-link.active:after {
content: '';
position: absolute;
bottom: -12px;
left: 0;
width: 100%;
height: 2px;
background: #3b82f6;
}
.tutorial-step {
display: none;
}
.tutorial-step.active {
display: block;
}
.tutorial-highlight {
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5);
transition: all 0.3s ease;
}
.drag-preview {
position: absolute;
pointer-events: none;
z-index: 1000;
opacity: 0.7;
}
.template-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.execution-log {
font-family: monospace;
white-space: pre-wrap;
background-color: #1e293b;
color: #f8fafc;
padding: 1rem;
border-radius: 0.5rem;
max-height: 300px;
overflow-y: auto;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
z-index: 100;
justify-content: center;
align-items: center;
}
.modal.active {
display: flex;
}
.modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
max-width: 800px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
}
.notification {
position: fixed;
bottom: 20px;
right: 20px;
padding: 12px 20px;
border-radius: 8px;
color: white;
display: flex;
align-items: center;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
z-index: 1000;
opacity: 0;
transition: opacity 0.3s ease;
}
.notification.show {
opacity: 1;
}
.notification.success {
background-color: #10b981;
}
.notification.error {
background-color: #ef4444;
}
</style>
</head>
<body class="bg-gray-100 h-screen flex flex-col">
<!-- Header -->
<header class="bg-white shadow-sm py-3 px-6 flex items-center justify-between">
<div class="flex items-center space-x-4">
<div class="text-indigo-600 font-bold text-xl flex items-center">
<i class="fas fa-project-diagram mr-2"></i>
<span>FlowForge</span>
</div>
<nav class="hidden md:flex space-x-6">
<a href="#" class="nav-link text-indigo-600 font-medium active" data-page="workflows">Workflows</a>
<a href="#" class="nav-link text-gray-600 hover:text-indigo-600" data-page="templates">Templates</a>
<a href="#" class="nav-link text-gray-600 hover:text-indigo-600" data-page="executions">Executions</a>
<a href="#" class="nav-link text-gray-600 hover:text-indigo-600" data-page="integrations">Integrations</a>
</nav>
</div>
<div class="flex items-center space-x-4">
<button class="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 flex items-center" id="execute-btn">
<i class="fas fa-play mr-2"></i>
<span>Run Workflow</span>
</button>
<button class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 flex items-center" id="tutorial-btn">
<i class="fas fa-graduation-cap mr-2"></i>
<span>Quick Start</span>
</button>
<div class="w-8 h-8 rounded-full bg-gray-300 flex items-center justify-center cursor-pointer" id="user-profile-btn">
<i class="fas fa-user text-gray-600"></i>
</div>
</div>
</header>
<!-- Main Content -->
<div class="flex flex-1 overflow-hidden">
<!-- Left Sidebar - Nodes Palette -->
<div class="sidebar w-64 bg-white border-r border-gray-200 flex flex-col" id="nodes-palette">
<div class="p-4 border-b border-gray-200">
<h2 class="font-semibold text-lg">Building Blocks</h2>
<div class="mt-2 relative">
<input type="text" placeholder="Search blocks..." class="w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
<i class="fas fa-search absolute right-3 top-2.5 text-gray-400"></i>
</div>
</div>
<div class="flex-1 overflow-y-auto p-2">
<div class="mb-4">
<h3 class="text-sm font-medium text-gray-500 mb-2 px-2">TRIGGERS</h3>
<div class="node-option" data-type="trigger" data-name="Manual">
<i class="fas fa-hand-pointer mr-2 text-indigo-500"></i>
<span>Manual Trigger</span>
</div>
<div class="node-option" data-type="trigger" data-name="Schedule">
<i class="fas fa-clock mr-2 text-indigo-500"></i>
<span>Scheduled</span>
</div>
<div class="node-option" data-type="trigger" data-name="Webhook">
<i class="fas fa-link mr-2 text-indigo-500"></i>
<span>Webhook</span>
</div>
<div class="node-option" data-type="trigger" data-name="Email">
<i class="fas fa-envelope mr-2 text-indigo-500"></i>
<span>New Email</span>
</div>
</div>
<div class="mb-4">
<h3 class="text-sm font-medium text-gray-500 mb-2 px-2">ACTIONS</h3>
<div class="node-option" data-type="action" data-name="HTTP Request">
<i class="fas fa-globe mr-2 text-green-500"></i>
<span>HTTP Request</span>
</div>
<div class="node-option" data-type="action" data-name="Database">
<i class="fas fa-database mr-2 text-green-500"></i>
<span>Database Query</span>
</div>
<div class="node-option" data-type="action" data-name="Email">
<i class="fas fa-paper-plane mr-2 text-green-500"></i>
<span>Send Email</span>
</div>
<div class="node-option" data-type="action" data-name="Slack">
<i class="fab fa-slack mr-2 text-green-500"></i>
<span>Slack Message</span>
</div>
</div>
<div class="mb-4">
<h3 class="text-sm font-medium text-gray-500 mb-2 px-2">DATA TRANSFORM</h3>
<div class="node-option" data-type="transform" data-name="Set">
<i class="fas fa-pen mr-2 text-purple-500"></i>
<span>Set Variable</span>
</div>
<div class="node-option" data-type="transform" data-name="Merge">
<i class="fas fa-object-group mr-2 text-purple-500"></i>
<span>Merge Data</span>
</div>
<div class="node-option" data-type="transform" data-name="Filter">
<i class="fas fa-filter mr-2 text-purple-500"></i>
<span>Filter Data</span>
</div>
<div class="node-option" data-type="transform" data-name="Format">
<i class="fas fa-align-left mr-2 text-purple-500"></i>
<span>Format Text</span>
</div>
</div>
<div class="mb-4">
<h3 class="text-sm font-medium text-gray-500 mb-2 px-2">LOGIC</h3>
<div class="node-option" data-type="logic" data-name="Condition">
<i class="fas fa-code-branch mr-2 text-yellow-500"></i>
<span>Condition</span>
</div>
<div class="node-option" data-type="logic" data-name="Delay">
<i class="fas fa-hourglass-half mr-2 text-yellow-500"></i>
<span>Delay</span>
</div>
<div class="node-option" data-type="logic" data-name="Loop">
<i class="fas fa-redo mr-极 text-yellow-500"></i>
<span>Loop</span>
</div>
</div>
</div>
</div>
<!-- Pages -->
<div class="flex-1 relative overflow-hidden">
<!-- Workflows Page -->
<div id="workflows-page" class="page h-full active">
<div class="absolute top-0 left-0 right-0 bg-white border-b border-gray-200 p-2 flex items-center justify-between z-10">
<div class="flex items-center space-x-2">
<button class="p-2 rounded hover:bg-gray-100" id="new-workflow-btn">
<i class="fas fa-plus"></i>
</button>
<button class="p-2 rounded hover:bg-gray-100" id="save-workflow-btn">
<i class="fas fa-save"></i>
</button>
<button class="p-2 rounded hover:bg-gray-100" id="delete-workflow-btn">
<i class="fas fa-trash"></i>
</button>
<div class="text-sm font-medium ml-2">Current Workflow: <span id="current-workflow-name">My First Workflow</span></div>
</div>
<div class="flex items-center space-x-2">
<button class="p-2 rounded hover:bg-gray-100" id="zoom-in-btn">
<i class="fas fa-search-plus"></i>
</button>
<button class="p-2 rounded hover:bg-gray-100" id="zoom-out-btn">
<i class="fas fa-search-minus"></i>
</button>
<button class="p-2 rounded hover:bg-gray-100" id="zoom-reset-btn">
<i class="fas fa-expand"></i>
</button>
<div class="text-sm text-gray-500" id="zoom-level">
Zoom: 100%
</div>
</div>
</div>
<div class="workflow-area" id="workflow-area">
<!-- Nodes will be added here dynamically -->
</div>
</div>
<!-- Templates Page -->
<div id="templates-page" class="page h-full p-6 overflow-y-auto">
<div class="bg-white rounded-lg shadow-sm p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-semibold">Workflow Templates</h2>
<div class="flex space-x-2">
<div class="relative">
<input type="text" placeholder="Search templates..." class="w-64 px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
<i class="fas fa-search absolute right-3 top-2.5 text-gray-400"></i>
</div>
<select class="px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
<option>All Categories</option>
<option>Data Processing</option>
<option>Notifications</option>
<option>API Integrations</option>
<option>Database</option>
</select>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="template-card bg-white border border-gray-200 rounded-lg overflow-hidden shadow-sm transition-all duration-200 cursor-pointer">
<div class="p-4">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center mr-3">
<i class="fas fa-envelope text-indigo-600"></i>
</div>
<h3 class="font-medium">Email Digest</h3>
</div>
<p class="text-sm text-gray-600 mb-4">Collect data from multiple sources and send a daily summary email</p>
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500">Last used: 2 days ago</span>
<button class="text-xs bg-indigo-100 text-indigo-700 px-3 py-1 rounded-full hover:bg-indigo-200">
Use Template
</button>
</div>
</div>
</div>
<div class="template-card bg-white border border-gray-200 rounded-lg overflow-hidden shadow-sm transition-all duration-200 cursor-pointer">
<div class="p-4">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center mr-3">
<i class="fas fa-database text-green-600"></i>
</div>
<h3 class="font-medium">Database Backup</h3>
</div>
<p class="text-sm text-gray-600 mb-4">Automatically backup your database to cloud storage on a schedule</p>
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500">Last used: 1 week ago</span>
<button class="text-xs bg-green-100 text-green-700 px-3 py-1 rounded-full hover:bg-green-200">
Use Template
</button>
</div>
</div>
</div>
<div class="template-card bg-white border border-gray-200 rounded-lg overflow-hidden shadow-sm transition-all duration-200 cursor-pointer">
<div class="p-4">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
<i class="fab fa-slack text-blue-600"></i>
</div>
<h3 class="font-medium">Slack Notifier</h3>
</div>
<p class="text-sm text-gray-600 mb-4">Send notifications to Slack when specific events occur</p>
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500">Last used: 3 days ago</span>
<button class="text-xs bg-blue-100 text-blue-700 px-3 py-1 rounded-full hover:bg-blue-200">
Use Template
</button>
</div>
</div>
</div>
<div class="template-card bg-white border border-gray-200 rounded-lg overflow-hidden shadow-sm transition-all duration-200 cursor-pointer">
<div class="p-4">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center mr-3">
<i class="fas fa-sync-alt text-purple-600"></i>
</div>
<h3 class="font-medium">Data Sync</h3>
</div>
<p class="text-sm text-gray-600 mb-4">Sync data between two different systems or APIs</p>
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500">Last used: 5 days ago</span>
<button class="text-xs bg-purple-100 text-purple-700 px-3 py-1 rounded-full hover:bg-purple-200">
Use Template
</button>
</div>
</div>
</div>
<div class="template-card bg-white border border-gray-200 rounded-lg overflow-hidden shadow-sm transition-all duration-200 cursor-pointer">
<div class="p-4">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-yellow-100 flex items-center justify-center mr-3">
<i class="fas fa-file-export text-yellow-600"></i>
</div>
<h3 class="font-medium">CSV Exporter</h3>
</div>
<p class="text-sm text-gray-600 mb-4">Query data and export to CSV file on a schedule</>
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500">Last used: 1 day ago</span>
<button class="text-xs bg-yellow-100 text-yellow-700 px-3 py-1 rounded-full hover:bg-yellow-200">
Use Template
</button>
</div>
</div>
</div>
<div class="template-card bg-white border border-gray-200 rounded-lg overflow-hidden shadow-sm transition-all duration-200 cursor-pointer">
< class="p-4">
<div class="flex items-center mb-3">
<div class="w-10 h-10 rounded-full bg-red-100 flex items-center justify-center mr-3">
<i class="fas fa-bell text-red-600"></i>
</div>
<h3 class="font-medium">Alert System</h3>
</div>
<p class="text-sm text-gray-600 mb-4">Monitor systems and send alerts via email/SMS when thresholds are exceeded</p>
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500">Last used: 2 weeks ago</span>
<button class="text-xs bg-red-100 text-red-700 px-3 py-1 rounded-full hover:bg-red-200">
Use Template
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Executions Page -->
<div id="executions-page" class="page h-full p-6 overflow-y-auto">
<div class="bg-white rounded-lg shadow-sm p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-semibold">Workflow Executions</h2>
<div class="flex space-x-2">
<div class="relative">
<input type="text" placeholder="Search executions..." class="w-64 px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
<i class="fas fa-search absolute right-3 top-2.5 text-gray-400"></i>
</div>
<select class="px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
<option>All Workflows</option>
<option>Email Digest</option>
<option>Database Backup</option>
<option>Slack Notifier</option>
</select>
<select class="px-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
<option>All Statuses</option>
<option>Success</option>
<option>Error</option>
<option>Running</option>
</select>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Workflow</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Start Time</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Duration</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white divide极 divide-gray-200">
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-500">#23567</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Email Digest</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">
Success
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2023-06-15 14:30:22</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">1.2s</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button class="text-indigo-600 hover:text-indigo-800 mr-3 view-execution-btn" data-id="23567">
<i class="fas fa-eye"></i>
</button>
<button class="text-indigo-600 hover:text-indigo-800 rerun-execution-btn" data-id="23567">
<i class="fas fa-redo"></i>
</button>
</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-500">#23566</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Database Backup</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">
Success
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2023-极-15 04:30:00</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">45.7s</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button class="text-indigo-600 hover:text-indigo-800 mr-3 view-execution-btn" data-id="23566">
<i class="fas fa-eye"></i>
</button>
<button class="text-indigo-600 hover:text-indigo-800 rerun-execution-btn" data-id="23566">
<i class="fas fa-redo"></i>
</button>
</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-500">#23565</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Slack Notifier</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">
Error
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2023-06-14 22:15:33</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">0.4s</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button class="text-indigo-600 hover:text-indigo-800 mr-3 view-execution-btn" data-id="23565">
<i class="fas fa-eye"></i>
</button>
<button class="text-indigo-600 hover:text-indigo-800 rerun-execution-btn" data-id="23565">
<i class="fas fa-redo"></i>
</button>
</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-500">#23564</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Email Digest</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">
Success
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2023-06-14 14:30:22</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">1.1s</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button class="text-indigo-600 hover:text-indigo-800 mr-3 view-execution-btn" data-id="23564">
<i class="fas fa-eye"></i>
</button>
<button class="text-indigo-600 hover:text-indigo-800 rerun-execution-btn" data-id="23564">
<i class="fas fa-redo"></i>
</button>
</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-500">#23563</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Data Sync</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">
Running
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2023-06-14 12:45:18</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2m 37s</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button class="text-indigo-600 hover:text-indigo-800 mr-3 view-execution-btn" data-id="23563">
<i class="fas fa-eye"></i>
</button>
<button class="text-indigo-600 hover:text-indigo-800 rerun-execution-btn" data-id="23563">
<i class="fas fa-redo"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Integrations Page -->
<div id="integrations-page" class="page h-full p-6 overflow-y-auto">
<div class="bg-white rounded-lg shadow-sm p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-semibold">Connected Integrations</h2>
<button class="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 flex items-center" id="new-integration-btn">
<i class="fas fa-plus mr-2"></i>
<span>Add Integration</span>
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="bg-white border border-gray-200 rounded-lg p-4">
<div class="flex items-center mb-3">
<div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center mr-3">
<i class="fab fa-slack text-blue-600 text-xl"></i>
</div>
<div>
<h3 class="font-medium">Slack</h3>
<p class="text-sm text-gray-500">Connected to workspace</p>
</div>
</div>
<div class="flex justify-between items-center mt-4">
<span class="text-xs text-gray-500">Last used: 2 hours ago</span>
<button class="text-xs bg-gray-100 text-gray-700 px-3 py-1 rounded-full hover:bg-gray-200">
Configure
</button>
</div>
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<div class="flex items-center mb-3">
<div class="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center mr-3">
<i class="fas fa-envelope text-green-600 text-xl"></i>
</div>
<div>
<h3 class="font-medium">Email (SMTP)</h3>
<p class="text-sm text-gray-500">Connected to Gmail</p>
</div>
</div>
<div class="flex justify-between items-center mt-4">
<span class="text-xs text-gray-500">Last used: 1 day ago</span>
<button class="text-xs bg-gray-100 text-gray-700 px-3 py-1 rounded-full hover:bg-gray-200">
Configure
</button>
</div>
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<div class="flex items-center mb-3">
<div class="w-12 h-12 rounded-full bg-red-100 flex items-center justify-center mr-3">
<i class="fab fa-google-drive text-red-600 text-xl"></i>
</div>
<div>
<h3 class="font-medium">Google Drive</h3>
<p class="text-sm text-gray-500">Connected to account</p>
</div>
</div>
<div class="flex justify-between items-center mt-4">
<span class="text-xs text-gray-500">Last used: 3 days ago</span>
<button class="text-xs bg-gray-100 text-gray-700 px-3 py-1 rounded-full hover:bg-gray-200">
Configure
</button>
</div>
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<div class="flex items-center mb-3">
<div class="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center mr-3">
<i class="fas fa-database text-purple-600 text-xl"></i>
</div>
<div>
<h3 class="font-medium">MySQL</h3>
<p class="text-sm text-gray-500">Connected to production</p>
</div>
</div>
<div class="flex justify-between items-center mt-4">
<span class="text-xs text-gray-500">Last used: 5 hours ago</span>
<button class="text-xs bg-gray-100 text-gray-700 px-3 py-1 rounded-full hover:bg-gray-200">
Configure
</button>
</div>
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<div class="flex items-center mb-3">
<div class="w-12 h-12 rounded-full bg-yellow-100 flex items-center justify-center mr-3">
<i class="fas fa-server text-yellow-600 text-xl"></i>
</div>
<div>
<h3 class="font-medium">REST API</h3>
<p class="text-sm text-gray-500">3 endpoints configured</p>
</div>
</div>
<div class="flex justify-between items-center mt-4">
<span class="text-xs text-gray-500">Last used: 2 days ago</span>
<button class="text-xs bg-gray-100 text-gray-700 px-3 py-1 rounded-full hover:bg-gray-200">
Configure
</button>
</div>
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<div class="flex items-center mb-3">
<div class="w-12 h-12 rounded-full bg-indigo-100 flex items-center justify-center mr-3">
<i class="fas fa-plus text-indigo-600 text-xl"></i>
</div>
<div>
<h3 class="font-medium">Add New</h3>
<p class="text-sm text-gray-500">Connect another service</p>
</div>
</div>
<div class="flex justify-between items-center mt-4">
<span class="text-xs text-gray-500">100+ available</span>
<button class="text-xs bg-indigo-100 text-indigo-700 px-3 py-1 rounded-full hover:bg-indigo-200">
Browse
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Right Sidebar - Node Configuration -->
<div class="sidebar w-96 bg-white border-l border-gray-200 flex flex-col" id="node-config-sidebar">
<div class="p-4 border-b border-gray-200">
<h2 class="font-semibold text-lg">Node Configuration</h2>
</div>
<div class="flex-1 overflow-y-auto p-4">
<div id="node-config" class="node-config p-4">
<div class="text-center text-gray-500 py-8">
<i class="fas fa-mouse-pointer text-3xl mb-2"></i>
<p>Select a node to configure it</p>
</div>
</div>
</div>
<div class="p-4 border-t border-gray-200">
<button class="w-full bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700" id="save-node-config">
Save Changes
</button>
</div>
</div>
</div>
<!-- Tutorial Modal -->
<div id="tutorial-modal" class="modal">
<div class="modal-content">
<div class="p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">FlowForge Quick Start</h3>
<button id="close-tutorial-modal" class="text-gray-400 hover:text-gray-500">
<i class="fas fa-times"></i>
</button>
</div>
<div class="space-y-6">
<!-- Step 1 -->
<div class="tutorial-step active" data-step="1">
<h4 class="font-medium text-lg mb-2">Welcome to FlowForge!</h4>
<p class="text-gray-600 mb-4">This quick guide will help you create your first automation workflow in just a few minutes.</p>
<div class极="bg-indigo-50 border-l-4 border-indigo-400 p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-info-circle text-indigo-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-indigo-700">
FlowForge lets you connect apps and automate tasks without writing any code.
</p>
</div>
</div>
</div>
<div class="flex justify-between mt-6">
<button class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:极bg-gray-50" disabled>
Previous
</button>
<button class="next-step-btn bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 text-sm font-medium" data-next="2">
Next: Create a Workflow
</button>
</div>
</div>
<!-- Step 2 -->
<div class="tutorial-step" data-step="2">
<h4 class="font-medium text-lg mb-2">1. Create a New Workflow</h4>
<p class="text-gray-600 mb-4">Workflows are sequences of automated steps that perform tasks for you.</p>
<div class="bg-indigo-50 border-l-4 border-indigo-400 p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-lightbulb text-indigo-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-indigo-700">
Click the <span class="font-medium">+</span> button in the top left to create a new workflow.
</p>
</div>
</div>
</div>
<div class="flex justify-between mt-6">
<button class="prev-step-btn px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" data-prev="1">
Previous
</button>
<button class="next-step-btn bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 text-sm font-medium" data-next="3">
Next: Add a Trigger
</button>
</div>
</div>
<!-- Step 3 -->
<div class="tutorial-step" data-step="3">
<h4 class="font-medium text-lg mb-2">2. Add a Trigger</h4>
<p class="text-gray-600 mb-4">Every workflow starts with a trigger - an event that starts the automation.</p>
<div class="bg-indigo-50 border-l-4 border-indigo-400 p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-hand-pointer text-indigo-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-indigo-700">
From the left sidebar under <span class="font-medium">Triggers</span>, drag a <span class="font-medium">Manual Trigger</span> to the canvas.
</p>
</div>
</div>
</div>
<div class="flex justify-between mt-6">
<button class="prev-step-btn px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" data-prev="2">
Previous
</button>
<button class="next-step-btn bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 text-sm font-medium" data-next="4">
Next: Add an Action
</button>
</div>
</div>
<!-- Step 4 -->
<div class="tutorial-step" data-step="4">
<h4 class="font-medium text-lg mb-2">3. Add an Action</h4>
<p class="text-gray-600 mb-4">Actions are the steps that perform tasks after the trigger activates.</p>
<div class="bg-indigo-50 border-l-4 border-indigo-400 p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-bolt text-indigo-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-indigo-700">
From the <span class="font-medium">Actions</span> section, drag an <span class="font-medium">HTTP Request</span> node to the canvas.
</p>
</div>
</div>
</div>
<div class="flex justify-between mt-6">
<button class="prev-step-btn px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" data-prev="3">
Previous
</button>
<button class="next-step-btn bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 text-sm font-medium" data-next="5">
Next: Connect Nodes
</button>
</div>
</div>
<!-- Step 5 -->
<div class="tutorial-step" data-step="5">
<h4 class="font-medium text-lg mb-2">4. Connect the Nodes</h4>
<p class="text-gray-600 mb-4">Nodes need to be connected to define the flow of your automation.</p>
<div class="bg-indigo-50 border-l-4 border-indigo-400 p-极 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-link text-indigo-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text极indigo-700">
Click and drag from the <span class="font-medium">output port</span> (right side) of the Manual Trigger to the <span class="font-medium">input port</span> (left side) of the HTTP Request.
</p>
</div>
</div>
</div>
<div class="flex justify-between mt-6">
<button class="prev-step-btn px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" data-prev="4">
Previous
</button>
<button class="next-step-btn bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 text-sm font-medium" data-next="6">
Next: Configure Nodes
</button>
</div>
</div>
<!-- Step 6 -->
<div class="tutorial-step" data-step="6">
<h4 class="font-medium text-lg mb-2">5. Configure Your Nodes</h4>
<p class="text-gray-600 mb-4">Each node has settings that define what it does.</p>
<div class="bg-indigo-50 border-l-4 border-indigo-400 p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-cog text-indigo-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-indigo-700">
Click on the <span class="font-medium">HTTP Request</span> node, then in the right sidebar enter a URL like <span class="font-mono">https://api.example.com/data</span>
</p>
</div>
</div>
</div>
<div class="flex justify-between mt-6">
<button class="prev-step-btn px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" data-prev="5">
Previous
</button>
<button class="next-step-btn bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 text-sm font-medium" data-next="7">
Next: Run Your Workflow
</button>
</div>
</div>
<!-- Step 7 -->
<div class="tutorial-step" data-step="7">
<h4 class="font-medium text-lg mb-2">6. Run Your Workflow</h4>
<p class="text-gray-600 mb-4">Test your workflow to make sure it works as expected.</p>
<div class="bg-indigo-50 border-l-4 border-indigo-400 p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-play text-indigo-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-indigo-700">
Click the <span class="font-medium">Run Workflow</span> button in the top right to execute your workflow manually.
</p>
</div>
</div>
</div>
<div class="flex justify-between mt-6">
<button class="prev-step-btn px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" data-prev="6">
Previous
</button>
<button class="next-step-btn bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 text-sm font-medium" data-next="8">
Next: Save Your Workflow
</button>
</div>
</div>
<!-- Step 8 -->
<div class="tutorial-step" data-step="8">
<h4 class="font-medium text-lg mb-2">7. Save Your Workflow</h4>
<p class="text-gray-600 mb-4">Always save your work to avoid losing your progress.</p>
<div class="bg-indigo-50 border-l-4 border-indigo-400 p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-save text-indigo-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-indigo-700">
Click the <span class="font-medium">Save</span> button in the top left or press <span class="font-mono">Ctrl+S</span> (Mac: <span class="font-mono">Cmd+S</span>).
</p>
</div>
</div>
</div>
<div class="flex justify-between mt-6">
<button class="prev-step-btn px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50" data-prev="7">
Previous
</button>
<button id="finish-tutorial" class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 text-sm font-medium">
Finish Tutorial
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Execution Results Modal -->
<div id="execution-modal" class="modal">
<div class="modal-content">
<div class="p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">Execution Results - <span id="execution-id">#23567</span></h3>
<button id="close-execution-modal" class="text-gray-400 hover:text-gray-500">
<i class="fas fa-times"></i>
</button>
</div>
<div class="mb-6">
<div class="flex items-center mb-2">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800 mr-3">
Success
</span>
<span class="text-sm text-gray-600">Workflow: <span class="font-medium" id="execution-workflow">Email Digest</span></span>
</div>
<div class="text-sm text-gray-600 mb-1">Started: <span id="execution-start">2023-06-15 14:30:22</span></div>
<div class="text-sm text-gray-600">Duration: <span id="execution-duration">1.2 seconds</span></div>
</div>
<div class="border-t border-gray-200 pt-4">
<h4 class="font-medium mb-3">Execution Steps</h4>
<div class="space-y-3" id="execution-steps">
<!-- Steps will be added here dynamically -->
</div>
</div>
<div class="border-t border-gray-200 mt-6 pt-4">
<h4 class="font-medium mb-3">Execution Log</h4>
<div class="execution-log" id="execution-log-content">
[2023-06-15 14:30:22] Workflow started
[2023-06-15 14:30:22] Trigger: Manual trigger activated
[2023-06-15 14:30:22] HTTP Request: Making GET request to https://api.example.com/data
[2023-06-15 14:30:22] HTTP Request: Received 200 OK response (25 items)
[2023-06-15 14:30:22] Filter: Applied filter criteria (10 items match)
[2023-06-15 14:30:23] Email: Sending digest to [email protected]
[2023-06-15 14:30:23] Email: Successfully sent
[2023-06-15 14:30:23] Workflow completed successfully
</div>
</div>
<div class="flex justify-end mt-6">
<button id="close-execution-modal" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 mr-3">
Close
</button>
<button class="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 text-sm font-medium">
<i class="fas fa-redo mr-2"></i> Run Again
</button>
</div>
</div>
</div>
</div>
<!-- New Integration Modal -->
<div id="new-integration-modal" class="modal">
<div class="modal-content">
<div class="p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">Add New Integration</h3>
<button id="close-integration-modal" class="text-gray-400 hover:text-gray-500">
<i class="fas fa-times"></i>
</button>
</div>
<div class="mb-6">
<div class="relative">
<input type="text" placeholder="Search integrations..." class="w-full px-4 py-3 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
<i class="fas fa-search absolute right-3 top-3.5 text-gray-400"></i>
</div>
</div>
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
<div class="border border-gray-200 rounded-lg p-4 text-center cursor-pointer hover:bg-gray-50">
<div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center mx-auto mb-3">
<i class="fab fa-slack text-blue-600 text-xl"></i>
</div>
<h4 class="font-medium text-sm">Slack</h4>
</div>
<div class="border border-gray-200 rounded-lg p-4 text-center cursor-pointer hover:bg-gray-50">
<div class="w-12 h-12 rounded-full bg-red-100 flex items-center justify-center mx-auto mb-3">
<i class="fab fa-google text-red-600 text-xl"></i>
</div>
<h4 class="font-medium text-sm">Google Workspace</h4>
</div>
<div class="border border-gray-200 rounded-lg p-4 text-center cursor-pointer hover:bg-gray-50">
<div class="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center mx-auto mb-3">
<i class="fas fa-envelope text-green-600 text-xl"></i>
</div>
<h4 class="font-medium text-sm">Email (SMTP)</h4>
</div>
<div class="border border-gray-200 rounded-lg p-4 text-center cursor-pointer hover:bg-gray-50">
<div class="w-12 h-12 rounded-full bg-yellow-100 flex items-center justify-center mx-auto mb-3">
<i class="fab fa-microsoft text-yellow-600 text-xl"></i>
</div>
<h4 class="font-medium text-sm">Microsoft 365</h4>
</div>
<div class="border border-gray-200 rounded-lg p-4 text-center cursor-pointer hover:bg-gray-50">
<div class="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center mx-auto mb-3">
<i class="fas fa-database text-purple-600 text-xl"></i>
</div>
<h4 class="font-medium text-sm">Database</h4>
</div>
<div class="border border-gray-200 rounded-lg p-4 text-center cursor-pointer hover:bg-gray-50">
<div class="w-12 h-12 rounded-full bg-indigo-100 flex items-center justify-center mx-auto mb-3">
<i class="fas fa-server text-indigo-600 text-xl"></i>
</div>
<h4 class="font-medium text-sm">REST API</h4>
</div>
</div>
<div class="flex justify-end mt-6">
<button id="cancel-integration" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
Cancel
</button>
</div>
</div>
</div>
</div>
<!-- User Profile Dropdown -->
<div id="user-profile-dropdown" class="hidden absolute right-6 top-16 w-48 bg-white rounded-md shadow-lg py-1 z-50">
<div class="px-4 py-2 border-b border-gray-200">
<div class="text-sm font-medium">John Doe</div>
<div class="text-xs text-gray-500">[email protected]</div>
</div>
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a>
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Settings</a>
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Help</a>
<div class="border-t border-gray-200"></div>
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Sign out</a>
</div>
<!-- Success Notification -->
<div id="success-notification" class="notification success">
<i class="fas fa-check-circle mr-2"></i>
<span id="success-message">Operation completed successfully!</span>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Page navigation
const navLinks = document.querySelectorAll('.nav-link');
const pages = document.querySelectorAll('.page');
navLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
// Update active nav link
navLinks.forEach(l => l.classList.remove('active', 'text-indigo-600'));
navLinks.forEach(l => l.classList.add('text-gray-600'));
this.classList.add('active', 'text-indigo-600');
this.classList.remove('text-gray-600');
// Show the selected page
const pageId = this.getAttribute('data-page') + '-page';
pages.forEach(page => page.classList.remove('active'));
document.getElementById(pageId).classList.add('active');
// Show/hide sidebars based on page
if (pageId === 'workflows-page') {
document.getElementById('nodes-palette').classList.remove('hidden');
document.getElementById('node-config-sidebar').classList.remove('hidden');
document.getElementById('execute-btn').classList.remove('hidden');
} else {
document.getElementById('nodes-palette').classList.add('hidden');
document.getElementById('node-config-sidebar').classList.add('hidden');
document.getElementById('execute-btn').classList.add('hidden');
}
});
});
// Tutorial functionality
const tutorialBtn = document.getElementById('tutorial-btn');
const tutorialModal = document.getElementById('tutorial-modal');
const closeTutorialModal = document.getElementById('close-tutorial-modal');
const nextStepBtns = document.querySelectorAll('.next-step-btn');
const prevStepBtns = document.querySelectorAll('.prev-step-btn');
const finishTutorialBtn = document.getElementById('finish-tutorial');
const tutorialSteps = document.querySelectorAll('.tutorial-step');
tutorialBtn.addEventListener('click', function() {
tutorialModal.classList.add('active');
// Reset to first step
tutorialSteps.forEach(step => step.classList.remove('active'));
document.querySelector('.tutorial-step[data-step="1"]').classList.add('active');
});
closeTutorialModal.addEventListener('click', function() {
tutorialModal.classList.remove('active');
});
nextStepBtns.forEach(btn => {
btn.addEventListener('click', function() {
const nextStep = this.getAttribute('data-next');
tutorialSteps.forEach(step => step.classList.remove('active'));
document.querySelector(`.tutorial-step[data-step="${nextStep}"]`).classList.add('active');
});
});
prevStepBtns.forEach(btn => {
btn.addEventListener('click', function() {
const prevStep = this.getAttribute('data-prev');
tutorialSteps.forEach(step => step.classList.remove('active'));
document.querySelector(`.tutorial-step[data-step="${prevStep}"]`).classList.add('active');
});
});
finishTutorialBtn.addEventListener('click', function() {
tutorialModal.classList.remove('active');
showSuccess('Tutorial completed! Ready to build your first workflow.');
});
// User profile dropdown
const userProfileBtn = document.getElementById('user-profile-btn');
const userProfileDropdown = document.getElementById('user-profile-dropdown');
userProfileBtn.addEventListener('click', function(e) {
e.stopPropagation();
userProfileDropdown.classList.toggle('hidden');
});
// Close dropdown when clicking elsewhere
document.addEventListener('click', function() {
userProfileDropdown.classList.add('hidden');
});
// Workflow editor functionality
const workflowArea = document.getElementById('workflow-area');
const nodeOptions = document.querySelectorAll('.node-option');
const nodeConfig = document.getElementById('node-config');
const saveNodeConfigBtn = document.getElementById('save-node-config');
const executeBtn = document.getElementById('execute-btn');
const zoomInBtn = document.getElementById('zoom-in-btn');
const zoomOutBtn = document.getElementById('zoom-out-btn');
const zoomResetBtn = document.getElementById('zoom-reset-btn');
const zoomLevel = document.getElementById('zoom-level');
const newIntegrationBtn = document.getElementById('new-integration-btn');
const newIntegrationModal = document.getElementById('new-integration-modal');
const closeIntegrationModal = document.getElementById('close-integration-modal');
const cancelIntegration = document.getElementById('cancel-integration');
const executionModal = document.getElementById('execution-modal');
const closeExecutionModal = document.getElementById('close-execution-modal');
const viewExecutionBtns = document.querySelectorAll('.view-execution-btn');
const rerunExecutionBtns = document.querySelectorAll('.rerun-execution-btn');
const successNotification = document.getElementById('success-notification');
let nodes = [];
let connections = [];
let selectedNode = null;
let isDragging = false;
let dragOffsetX = 0;
let dragOffsetY = 0;
let isConnecting = false;
let connectingFrom = null;
let currentZoom = 100;
let dragPreview = null;
// Add node to workflow area
nodeOptions.forEach(option => {
option.addEventListener('mousedown', function(e) {
if (e.button !== 0) return; // Only left mouse button
const type = this.getAttribute('data-type');
const name = this.getAttribute('data-name');
// Create drag preview
dragPreview = document.createElement('div');
dragPreview.className = 'drag-preview node';
dragPreview.style.width = '200px';
dragPreview.innerHTML = `
<div class="node-header">
<span>${name}</span>
</div>
<div class="node-body">
<div class="text-sm text-gray-500">Click to configure</div>
</div>
`;
document.body.appendChild(dragPreview);
// Position preview at cursor
updateDragPreviewPosition(e);
// Setup drag events
document.addEventListener('mousemove', handleNodeDrag);
document.addEventListener('mouseup', handleNodeDrop);
function handleNodeDrag(e) {
updateDragPreviewPosition(e);
}
function handleNodeDrop(e) {
// Remove drag preview
if (dragPreview) {
dragPreview.remove();
dragPreview = null;
}
// Remove event listeners
document.removeEventListener('mousemove', handleNodeDrag);
document.removeEventListener('mouseup', handleNodeDrop);
// Check if dropped on workflow area
if (e.target.closest('#workflow-area')) {
addNodeToWorkflow(type, name, e.clientX, e.clientY);
}
}
function updateDragPreviewPosition(e) {
if (!dragPreview) return;
const rect = workflowArea.getBoundingClientRect();
const x = e.clientX - rect.left - 100; // Center on cursor
const y = e.clientY - rect.top - 20;
dragPreview.style.left = (e.clientX - 100) + 'px';
dragPreview.style.top = (e.clientY - 20) + 'px';
}
});
});
function addNodeToWorkflow(type, name, clientX, clientY) {
// Generate a unique ID for the node
const nodeId = 'node-' + Date.now();
// Create node element
const node = document.createElement('div');
node.className = 'node';
node.id = nodeId;
// Position the node where dropped
const rect = workflowArea.getBoundingClientRect();
const x = clientX - rect.left - 100; // Center on cursor
const y = clientY - rect.top - 20;
node.style.left = x + 'px';
node.style.top = y + 'px';
// Node header
const header = document.createElement('div');
header.className = 'node-header';
header.innerHTML = `
<span>${name}</span>
<i class="fas fa-ellipsis-h text-gray-400"></i>
`;
// Node body
const body = document.createElement('div');
body.className = 'node-body';
body.innerHTML = `
<div class极text-sm text-gray-500">Click to configure</div>
`;
// Node ports
const input = document.createElement('div');
input.className = 'node-port node-input';
const output = document.createElement('div');
output.className = 'node-port node-output';
node.appendChild(header);
node.appendChild(body);
node.appendChild(input);
node.appendChild(output);
workflowArea.appendChild(node);
// Add node to our nodes array
nodes.push({
id: nodeId,
type: type,
name: name,
x: x,
y: y,
element: node,
config: {}
});
// Add drag functionality
setupNodeDrag(node);
// Add click handler for selection
node.addEventListener('click', function(e) {
if (e.target.classList.contains('node-port')) {
return;
}
// Deselect all nodes
document.querySelectorAll('.node').forEach(n => {
n.classList.remove('node-selected');
});
// Select this node
this.classList.add('node-selected');
selectedNode = nodes.find(n => n.id === this.id);
// Update node configuration panel
updateNodeConfig(selectedNode);
});
// Add port click handlers
input.addEventListener('mousedown', function(e) {
e.stopPropagation();
startConnection(this, nodeId, 'input');
});
output.addEventListener('mousedown', function(e) {
e.stopPropagation();
startConnection(this, nodeId, 'output');
});
// Show success message
showSuccess(`Added ${name} node to workflow`);
}
function setupNodeDrag(node) {
const header = node.querySelector('.node-header');
header.addEventListener('mousedown', function(e) {
if (e.button !== 0) return; // Only left mouse button
isDragging = true;
const rect = node.getBoundingClientRect();
dragOffsetX = e.clientX - rect.left;
dragOffsetY = e.clientY - rect.top;
document.addEventListener('mousemove', handleDrag);
document.addEventListener('mouseup', stopDrag);
function handleDrag(e) {
if (!isDragging) return;
const x = e.clientX - dragOffsetX;
const y = e.clientY - dragOffsetY;
node.style.left = x
</html>