|
<!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 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> |
|
|
|
|
|
<div class="flex flex-1 overflow-hidden"> |
|
|
|
<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> |
|
|
|
|
|
<div class="flex-1 relative overflow-hidden"> |
|
|
|
<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"> |
|
|
|
</div> |
|
</div> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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"> |
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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"> |
|
|
|
</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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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() { |
|
|
|
const navLinks = document.querySelectorAll('.nav-link'); |
|
const pages = document.querySelectorAll('.page'); |
|
|
|
navLinks.forEach(link => { |
|
link.addEventListener('click', function(e) { |
|
e.preventDefault(); |
|
|
|
|
|
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'); |
|
|
|
|
|
const pageId = this.getAttribute('data-page') + '-page'; |
|
pages.forEach(page => page.classList.remove('active')); |
|
document.getElementById(pageId).classList.add('active'); |
|
|
|
|
|
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'); |
|
} |
|
}); |
|
}); |
|
|
|
|
|
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'); |
|
|
|
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.'); |
|
}); |
|
|
|
|
|
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'); |
|
}); |
|
|
|
|
|
document.addEventListener('click', function() { |
|
userProfileDropdown.classList.add('hidden'); |
|
}); |
|
|
|
|
|
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; |
|
|
|
|
|
nodeOptions.forEach(option => { |
|
option.addEventListener('mousedown', function(e) { |
|
if (e.button !== 0) return; |
|
|
|
const type = this.getAttribute('data-type'); |
|
const name = this.getAttribute('data-name'); |
|
|
|
|
|
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); |
|
|
|
|
|
updateDragPreviewPosition(e); |
|
|
|
|
|
document.addEventListener('mousemove', handleNodeDrag); |
|
document.addEventListener('mouseup', handleNodeDrop); |
|
|
|
function handleNodeDrag(e) { |
|
updateDragPreviewPosition(e); |
|
} |
|
|
|
function handleNodeDrop(e) { |
|
|
|
if (dragPreview) { |
|
dragPreview.remove(); |
|
dragPreview = null; |
|
} |
|
|
|
|
|
document.removeEventListener('mousemove', handleNodeDrag); |
|
document.removeEventListener('mouseup', handleNodeDrop); |
|
|
|
|
|
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; |
|
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) { |
|
|
|
const nodeId = 'node-' + Date.now(); |
|
|
|
|
|
const node = document.createElement('div'); |
|
node.className = 'node'; |
|
node.id = nodeId; |
|
|
|
|
|
const rect = workflowArea.getBoundingClientRect(); |
|
const x = clientX - rect.left - 100; |
|
const y = clientY - rect.top - 20; |
|
|
|
node.style.left = x + 'px'; |
|
node.style.top = y + 'px'; |
|
|
|
|
|
const header = document.createElement('div'); |
|
header.className = 'node-header'; |
|
header.innerHTML = ` |
|
<span>${name}</span> |
|
<i class="fas fa-ellipsis-h text-gray-400"></i> |
|
`; |
|
|
|
|
|
const body = document.createElement('div'); |
|
body.className = 'node-body'; |
|
body.innerHTML = ` |
|
<div class极text-sm text-gray-500">Click to configure</div> |
|
`; |
|
|
|
|
|
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); |
|
|
|
|
|
nodes.push({ |
|
id: nodeId, |
|
type: type, |
|
name: name, |
|
x: x, |
|
y: y, |
|
element: node, |
|
config: {} |
|
}); |
|
|
|
|
|
setupNodeDrag(node); |
|
|
|
|
|
node.addEventListener('click', function(e) { |
|
if (e.target.classList.contains('node-port')) { |
|
return; |
|
} |
|
|
|
|
|
document.querySelectorAll('.node').forEach(n => { |
|
n.classList.remove('node-selected'); |
|
}); |
|
|
|
|
|
this.classList.add('node-selected'); |
|
selectedNode = nodes.find(n => n.id === this.id); |
|
|
|
|
|
updateNodeConfig(selectedNode); |
|
}); |
|
|
|
|
|
input.addEventListener('mousedown', function(e) { |
|
e.stopPropagation(); |
|
startConnection(this, nodeId, 'input'); |
|
}); |
|
|
|
output.addEventListener('mousedown', function(e) { |
|
e.stopPropagation(); |
|
startConnection(this, nodeId, 'output'); |
|
}); |
|
|
|
|
|
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; |
|
|
|
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> |