|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>SyncFlow Pro - Database Harmony Orchestrator</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<script src="https://unpkg.com/feather-icons"></script> |
|
|
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> |
|
|
<script> |
|
|
tailwind.config = { |
|
|
theme: { |
|
|
extend: { |
|
|
colors: { |
|
|
primary: '#667eea', |
|
|
secondary: '#764ba2', |
|
|
success: '#2ecc71', |
|
|
warning: '#f39c12', |
|
|
danger: '#e74c3c', |
|
|
dark: '#2c3e50', |
|
|
light: '#ecf0f1' |
|
|
}, |
|
|
animation: { |
|
|
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite', |
|
|
'bounce-slow': 'bounce 2s infinite', |
|
|
'float': 'float 6s ease-in-out infinite', |
|
|
}, |
|
|
keyframes: { |
|
|
float: { |
|
|
'0%, 100%': { transform: 'translateY(0px)' }, |
|
|
'50%': { transform: 'translateY(-20px)' }, |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
</script> |
|
|
<style> |
|
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); |
|
|
|
|
|
* { |
|
|
margin: 0; |
|
|
padding: 0; |
|
|
box-sizing: border-box; |
|
|
} |
|
|
|
|
|
body { |
|
|
font-family: 'Inter', sans-serif; |
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
|
min-height: 100vh; |
|
|
} |
|
|
|
|
|
.glass-effect { |
|
|
background: rgba(255, 255, 255, 0.95); |
|
|
backdrop-filter: blur(20px); |
|
|
border: 1px solid rgba(255, 255, 255, 0.2); |
|
|
} |
|
|
|
|
|
.gradient-text { |
|
|
background: linear-gradient(45deg, #667eea, #764ba2); |
|
|
-webkit-background-clip: text; |
|
|
-webkit-text-fill-color: transparent; |
|
|
background-clip: text; |
|
|
} |
|
|
|
|
|
.status-glow { |
|
|
box-shadow: 0 0 20px rgba(46, 204, 113, 0.4); |
|
|
} |
|
|
|
|
|
.sync-pulse { |
|
|
animation: pulse 2s infinite; |
|
|
} |
|
|
|
|
|
@keyframes pulse { |
|
|
0% { transform: scale(1); } |
|
|
50% { transform: scale(1.05); } |
|
|
100% { transform: scale(1); } |
|
|
} |
|
|
|
|
|
.progress-gradient { |
|
|
background: linear-gradient(90deg, #2ecc71, #3498db, #9b59b6); |
|
|
background-size: 200% 100%; |
|
|
animation: gradientShift 3s ease infinite; |
|
|
} |
|
|
|
|
|
@keyframes gradientShift { |
|
|
0% { background-position: 0% 50%; } |
|
|
50% { background-position: 100% 50%; } |
|
|
100% { background-position: 0% 50%; } |
|
|
} |
|
|
|
|
|
.log-entry { |
|
|
border-left: 3px solid; |
|
|
padding-left: 10px; |
|
|
margin: 5px 0; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.log-entry:hover { |
|
|
transform: translateX(5px); |
|
|
background: rgba(255, 255, 255, 0.1); |
|
|
} |
|
|
|
|
|
.floating-card { |
|
|
animation: float 6s ease-in-out infinite; |
|
|
} |
|
|
|
|
|
.holographic-effect { |
|
|
background: linear-gradient(45deg, |
|
|
rgba(102, 126, 234, 0.1), |
|
|
rgba(118, 75, 162, 0.1), |
|
|
rgba(46, 204, 113, 0.1)); |
|
|
position: relative; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.holographic-effect::before { |
|
|
content: ''; |
|
|
position: absolute; |
|
|
top: -50%; |
|
|
left: -50%; |
|
|
width: 200%; |
|
|
height: 200%; |
|
|
background: linear-gradient(45deg, |
|
|
transparent, |
|
|
rgba(255, 255, 255, 0.1), |
|
|
transparent); |
|
|
transform: rotate(45deg); |
|
|
animation: shine 3s infinite; |
|
|
} |
|
|
|
|
|
@keyframes shine { |
|
|
0% { transform: translateX(-100%) translateY(-100%) rotate(45deg); } |
|
|
100% { transform: translateX(100%) translateY(100%) rotate(45deg); } |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="min-h-screen relative overflow-x-hidden"> |
|
|
|
|
|
<div id="vanta-bg" class="absolute inset-0 z-0"></div> |
|
|
|
|
|
|
|
|
<div class="relative z-10 min-h-screen flex items-center justify-center p-4"> |
|
|
<div class="w-full max-w-7xl mx-auto"> |
|
|
|
|
|
<div class="text-center mb-12 floating-card"> |
|
|
<div class="glass-effect rounded-2xl p-8 shadow-2xl border border-white/20"> |
|
|
<h1 class="text-5xl md:text-6xl font-bold gradient-text mb-4"> |
|
|
π SyncFlow Pro |
|
|
</h1> |
|
|
<p class="text-xl text-gray-600 mb-6">Database Harmony Orchestrator</p> |
|
|
<div class="flex justify-center space-x-4"> |
|
|
<span class="px-4 py-2 bg-green-100 text-green-800 rounded-full text-sm font-medium flex items-center"> |
|
|
<span class="w-2 h-2 bg-green-500 rounded-full mr-2 animate-pulse"></span> |
|
|
Real-time Monitoring |
|
|
</span> |
|
|
<span class="px-4 py-2 bg-blue-100 text-blue-800 rounded-full text-sm font-medium flex items-center"> |
|
|
<span class="w-2 h-2 bg-blue-500 rounded-full mr-2"></span> |
|
|
AI-Powered Mapping |
|
|
</span> |
|
|
<span class="px-4 py-2 bg-purple-100 text-purple-800 rounded-full text-sm font-medium flex items-center"> |
|
|
<span class="w-2 h-2 bg-purple-500 rounded-full mr-2"></span> |
|
|
Enterprise Ready |
|
|
</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="glass-effect rounded-2xl p-6 shadow-2xl border border-white/20 mb-8"> |
|
|
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center"> |
|
|
<i data-feather="activity" class="mr-3"></i> |
|
|
Connection Dashboard |
|
|
</h2> |
|
|
<div id="connection-status" class="grid grid-cols-1 md:grid-cols-4 gap-4"> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-8"> |
|
|
|
|
|
<div class="glass-effect rounded-2xl p-6 shadow-2xl border border-white/20"> |
|
|
<h3 class="text-xl font-bold text-gray-800 mb-4 flex items-center"> |
|
|
<i data-feather="map-pin" class="mr-2"></i> |
|
|
π Regions & Tables |
|
|
</h3> |
|
|
<div id="regions-list" class="space-y-4"> |
|
|
<div class="flex items-center justify-center py-8"> |
|
|
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div> |
|
|
<span class="ml-3 text-gray-600">Loading configuration...</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="glass-effect rounded-2xl p-6 shadow-2xl border border-white/20"> |
|
|
<h3 class="text-xl font-bold text-gray-800 mb-4 flex items-center"> |
|
|
<i data-feather="database" class="mr-2"></i> |
|
|
π Tables to Sync |
|
|
</h3> |
|
|
<div id="tables-list" class="h-64 overflow-y-auto"> |
|
|
<div class="text-center py-8 text-gray-500"> |
|
|
<i data-feather="database" class="w-12 h-12 mx-auto mb-4 text-gray-300"></i> |
|
|
<p>Select a region to see available tables</p> |
|
|
</div> |
|
|
</div> |
|
|
<div class="mt-4 p-4 bg-blue-50 rounded-lg"> |
|
|
<div class="flex justify-between items-center"> |
|
|
<span class="font-medium text-blue-800">Selected Tables:</span> |
|
|
<span id="selected-count" class="text-2xl font-bold text-blue-600">0</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="glass-effect rounded-2xl p-6 shadow-2xl border border-white/20"> |
|
|
<h3 class="text-xl font-bold text-gray-800 mb-4 flex items-center"> |
|
|
<i data-feather="settings" class="mr-2"></i> |
|
|
βοΈ Sync Configuration |
|
|
</h3> |
|
|
<div class="space-y-4"> |
|
|
<div class="holographic-effect rounded-lg p-4 text-center"> |
|
|
<div class="text-3xl font-bold text-gray-800 mb-2" id="mapping-percentage">0%</div> |
|
|
<div class="text-sm text-gray-600">Auto-Mapping Complete</div> |
|
|
<div class="w-full bg-gray-200 rounded-full h-2 mt-2"> |
|
|
<div id="mapping-progress" class="progress-gradient h-2 rounded-full transition-all duration-500" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="grid grid-cols-2 gap-4"> |
|
|
<div class="bg-green-50 p-3 rounded-lg text-center"> |
|
|
<div class="text-2xl font-bold text-green-600" id="mapped-count">0</div> |
|
|
<div class="text-sm text-green-800">Mapped Columns</div> |
|
|
</div> |
|
|
<div class="bg-orange-50 p-3 rounded-lg text-center"> |
|
|
<div class="text-2xl font-bold text-orange-600" id="unmapped-count">0</div> |
|
|
<div class="text-sm text-orange-800">Needs Review</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="column-mapping" class="glass-effect rounded-2xl p-6 shadow-2xl border border-white/20 mb-8 hidden"> |
|
|
<h3 class="text-xl font-bold text-gray-800 mb-4 flex items-center"> |
|
|
<i data-feather="link" class="mr-2"></i> |
|
|
π Intelligent Column Mapping |
|
|
</h3> |
|
|
<div id="mapping-container" class="space-y-4"> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="glass-effect rounded-2xl p-6 shadow-2xl border border-white/20 mb-8"> |
|
|
<div class="flex flex-wrap gap-4 justify-center"> |
|
|
<button onclick="loadConfiguration()" class="px-6 py-3 bg-gray-600 text-white rounded-lg font-medium hover:bg-gray-700 transition-all duration-300 transform hover:scale-105 flex items-center"> |
|
|
<i data-feather="folder" class="mr-2"></i> |
|
|
π Load Config |
|
|
</button> |
|
|
<button onclick="saveConfigurationWithName()" class="px-6 py-3 bg-purple-600 text-white rounded-lg font-medium hover:bg-purple-700 transition-all duration-300 transform hover:scale-105 flex items-center"> |
|
|
<i data-feather="save" class="mr-2"></i> |
|
|
πΎ Save Config |
|
|
</button> |
|
|
<button onclick="selectAllTables()" class="px-6 py-3 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-all duration-300 transform hover:scale-105 flex items-center"> |
|
|
<i data-feather="check-square" class="mr-2"></i> |
|
|
π Select All Tables |
|
|
</button> |
|
|
<button onclick="startSync()" id="sync-button" class="px-8 py-3 bg-gradient-to-r from-green-500 to-blue-500 text-white rounded-lg font-bold hover:from-green-600 hover:to-blue-600 transition-all duration-300 transform hover:scale-105 sync-pulse flex items-center"> |
|
|
<i data-feather="play" class="mr-2"></i> |
|
|
π Start Sync |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="progress-container" class="glass-effect rounded-2xl p-6 shadow-2xl border border-white/20 hidden"> |
|
|
<h3 class="text-xl font-bold text-gray-800 mb-4 flex items-center"> |
|
|
<i data-feather="bar-chart-2" class="mr-2"></i> |
|
|
π Sync Progress |
|
|
</h3> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<div class="flex justify-between mb-2"> |
|
|
<span class="font-medium text-gray-700">Sync Progress</span> |
|
|
<span id="progress-percentage" class="font-bold text-blue-600">0%</span> |
|
|
</div> |
|
|
<div class="w-full bg-gray-200 rounded-full h-4"> |
|
|
<div id="progress-fill" class="progress-gradient h-4 rounded-full transition-all duration-500" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="bg-gray-900 rounded-lg p-4"> |
|
|
<div class="flex justify-between items-center mb-3"> |
|
|
<span class="text-white font-medium">Sync Logs</span> |
|
|
<button onclick="clearLogs()" class="text-gray-400 hover:text-white text-sm"> |
|
|
<i data-feather="trash-2" class="w-4 h-4"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div id="sync-log" class="h-48 overflow-y-auto font-mono text-sm text-green-400 bg-black/30 rounded p-3"> |
|
|
<div class="log-entry border-l-green-500">Ready to start synchronization...</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="saveConfigModal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden"> |
|
|
<div class="glass-effect rounded-2xl p-8 max-w-md w-full mx-4 shadow-2xl border border-white/20"> |
|
|
<h3 class="text-2xl font-bold text-gray-800 mb-4 flex items-center"> |
|
|
<i data-feather="save" class="mr-3"></i> |
|
|
πΎ Save Configuration |
|
|
</h3> |
|
|
<p class="text-gray-600 mb-4">Enter a name for your configuration file:</p> |
|
|
<input type="text" id="configNameInput" class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:border-blue-500 transition-colors" placeholder="e.g., weekly-sync-config"> |
|
|
<div class="flex gap-3 mt-6"> |
|
|
<button onclick="closeSaveConfigModal()" class="flex-1 px-4 py-3 bg-gray-500 text-white rounded-lg font-medium hover:bg-gray-600 transition-colors"> |
|
|
Cancel |
|
|
</button> |
|
|
<button onclick="saveConfigWithName()" class="flex-1 px-4 py-3 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors"> |
|
|
Save Configuration |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
|
|
|
VANTA.GLOBE({ |
|
|
el: "#vanta-bg", |
|
|
mouseControls: true, |
|
|
touchControls: true, |
|
|
gyroControls: false, |
|
|
minHeight: 200.00, |
|
|
minWidth: 200.00, |
|
|
scale: 1.00, |
|
|
scaleMobile: 1.00, |
|
|
color: 0x667eea, |
|
|
color2: 0x764ba2, |
|
|
backgroundColor: 0x0 |
|
|
}); |
|
|
|
|
|
|
|
|
const API_BASE = '/api'; |
|
|
|
|
|
let configData = {}; |
|
|
let selectedTables = []; |
|
|
let columnMappings = {}; |
|
|
let sourceColumnsCache = {}; |
|
|
let targetColumnsCache = {}; |
|
|
|
|
|
|
|
|
async function initializeInterface() { |
|
|
await loadConfig(); |
|
|
await checkConnections(); |
|
|
feather.replace(); |
|
|
} |
|
|
|
|
|
async function loadConfig() { |
|
|
try { |
|
|
showLoading('regions-list', 'Loading configuration...'); |
|
|
const response = await fetch(`${API_BASE}/config`); |
|
|
const data = await response.json(); |
|
|
|
|
|
if (data.success) { |
|
|
configData = data.config; |
|
|
loadRegions(); |
|
|
} else { |
|
|
showError('Failed to load configuration: ' + data.error); |
|
|
} |
|
|
} catch (error) { |
|
|
showError('Error loading configuration: ' + error.message); |
|
|
} |
|
|
} |
|
|
|
|
|
async function checkConnections() { |
|
|
const statusContainer = document.getElementById('connection-status'); |
|
|
const regions = ['webapp', ...Object.keys(configData)]; |
|
|
|
|
|
statusContainer.innerHTML = ''; |
|
|
|
|
|
for (const region of regions) { |
|
|
const statusCard = document.createElement('div'); |
|
|
statusCard.className = 'bg-white/80 rounded-xl p-4 shadow-lg border'; |
|
|
statusCard.innerHTML = ` |
|
|
<div class="flex items-center justify-between mb-2"> |
|
|
</body> |
|
|
</html> |