bigbasealpha
Version:
Enterprise-Grade NoSQL Database System with Modular Logger & Offline HSM Security - Complete database platform with professional text-based logging, encryption, caching, indexing, JWT authentication, auto-generated REST API, real-time dashboard, and maste
1,202 lines (1,071 loc) • 46.3 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BigBaseAlpha - Stream Processing Dashboard</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #333;
line-height: 1.6;
min-height: 100vh;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 30px;
background: rgba(255, 255, 255, 0.95);
padding: 30px;
border-radius: 15px;
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
backdrop-filter: blur(4px);
border: 1px solid rgba(255, 255, 255, 0.18);
}
.header h1 {
color: #4f46e5;
font-size: 2.5em;
margin-bottom: 10px;
background: linear-gradient(45deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.header p {
font-size: 1.2em;
color: #666;
}
.nav-tabs {
display: flex;
background: rgba(255, 255, 255, 0.9);
border-radius: 10px;
padding: 5px;
margin-bottom: 20px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.nav-tab {
flex: 1;
text-align: center;
padding: 15px;
background: transparent;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 1.1em;
font-weight: 600;
transition: all 0.3s ease;
color: #666;
}
.nav-tab.active {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}
.nav-tab:hover:not(.active) {
background: rgba(102, 126, 234, 0.1);
color: #4f46e5;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.dashboard-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 25px;
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
backdrop-filter: blur(4px);
border: 1px solid rgba(255, 255, 255, 0.18);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.dashboard-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 40px rgba(31, 38, 135, 0.45);
}
.card-header {
display: flex;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 2px solid #f0f0f0;
}
.card-icon {
width: 40px;
height: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
font-size: 1.5em;
color: white;
}
.card-title {
font-size: 1.3em;
font-weight: 600;
color: #333;
}
.metric {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #f0f0f0;
}
.metric:last-child {
border-bottom: none;
}
.metric-label {
font-weight: 500;
color: #666;
}
.metric-value {
font-weight: 700;
font-size: 1.1em;
color: #4f46e5;
}
.stream-card {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
border: none;
}
.processor-card {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
border: none;
}
.analytics-card {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
color: white;
border: none;
}
.performance-card {
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
color: white;
border: none;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 1em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
margin: 5px;
text-decoration: none;
display: inline-block;
text-align: center;
}
.btn-primary {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
}
.btn-primary:hover {
background: linear-gradient(45deg, #5a6fd8, #6a4190);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.btn-success {
background: linear-gradient(45deg, #43e97b, #38f9d7);
color: white;
}
.btn-warning {
background: linear-gradient(45deg, #fa709a, #fee140);
color: white;
}
.btn-danger {
background: linear-gradient(45deg, #ff6b6b, #ffa500);
color: white;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #333;
}
.form-control {
width: 100%;
padding: 12px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 1em;
transition: border-color 0.3s ease;
}
.form-control:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.stream-item {
background: rgba(255, 255, 255, 0.1);
border-radius: 8px;
padding: 15px;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.stream-info {
flex: 1;
}
.stream-name {
font-weight: 600;
margin-bottom: 5px;
}
.stream-stats {
font-size: 0.9em;
opacity: 0.8;
}
.stream-actions {
display: flex;
gap: 10px;
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
margin-right: 8px;
}
.status-active { background-color: #4CAF50; }
.status-inactive { background-color: #f44336; }
.status-processing { background-color: #ff9800; }
.realtime-chart {
height: 200px;
background: rgba(255, 255, 255, 0.1);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: rgba(255, 255, 255, 0.7);
margin-top: 15px;
}
.alert {
padding: 15px;
margin-bottom: 20px;
border-radius: 8px;
font-weight: 500;
}
.alert-info {
background: rgba(67, 233, 123, 0.1);
color: #43e97b;
border: 1px solid rgba(67, 233, 123, 0.2);
}
.alert-warning {
background: rgba(255, 193, 7, 0.1);
color: #ffc107;
border: 1px solid rgba(255, 193, 7, 0.2);
}
.table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}
.table th,
.table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.table th {
font-weight: 600;
background: rgba(255, 255, 255, 0.1);
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 1000;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
border-radius: 15px;
padding: 30px;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 2px solid #f0f0f0;
}
.modal-title {
font-size: 1.5em;
font-weight: 600;
color: #333;
}
.close {
background: none;
border: none;
font-size: 2em;
cursor: pointer;
color: #999;
}
.close:hover {
color: #333;
}
@media (max-width: 768px) {
.dashboard-grid {
grid-template-columns: 1fr;
}
.nav-tabs {
flex-direction: column;
}
.nav-tab {
margin-bottom: 5px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🚀 Stream Processing Dashboard</h1>
<p>Real-time Data Stream Management & Analytics</p>
</div>
<div class="nav-tabs">
<button class="nav-tab active" onclick="switchTab('overview')">📊 Overview</button>
<button class="nav-tab" onclick="switchTab('streams')">🌊 Streams</button>
<button class="nav-tab" onclick="switchTab('processors')">⚙️ Processors</button>
<button class="nav-tab" onclick="switchTab('analytics')">📈 Analytics</button>
<button class="nav-tab" onclick="switchTab('monitoring')">🔍 Monitoring</button>
</div>
<!-- Overview Tab -->
<div id="overview" class="tab-content active">
<div class="dashboard-grid">
<div class="dashboard-card stream-card">
<div class="card-header">
<div class="card-icon" style="background: rgba(255,255,255,0.2);">🌊</div>
<div class="card-title">Active Streams</div>
</div>
<div class="metric">
<span class="metric-label">Total Streams</span>
<span class="metric-value" id="totalStreams">0</span>
</div>
<div class="metric">
<span class="metric-label">Active Streams</span>
<span class="metric-value" id="activeStreams">0</span>
</div>
<div class="metric">
<span class="metric-label">Events/sec</span>
<span class="metric-value" id="eventsPerSecond">0</span>
</div>
</div>
<div class="dashboard-card processor-card">
<div class="card-header">
<div class="card-icon" style="background: rgba(255,255,255,0.2);">⚙️</div>
<div class="card-title">Stream Processors</div>
</div>
<div class="metric">
<span class="metric-label">Total Processors</span>
<span class="metric-value" id="totalProcessors">0</span>
</div>
<div class="metric">
<span class="metric-label">Running</span>
<span class="metric-value" id="runningProcessors">0</span>
</div>
<div class="metric">
<span class="metric-label">Processing Rate</span>
<span class="metric-value" id="processingRate">0 ops/s</span>
</div>
</div>
<div class="dashboard-card analytics-card">
<div class="card-header">
<div class="card-icon" style="background: rgba(255,255,255,0.2);">📈</div>
<div class="card-title">Analytics</div>
</div>
<div class="metric">
<span class="metric-label">Windows Active</span>
<span class="metric-value" id="activeWindows">0</span>
</div>
<div class="metric">
<span class="metric-label">Continuous Queries</span>
<span class="metric-value" id="continuousQueries">0</span>
</div>
<div class="metric">
<span class="metric-label">Stream Joins</span>
<span class="metric-value" id="streamJoins">0</span>
</div>
</div>
<div class="dashboard-card performance-card">
<div class="card-header">
<div class="card-icon" style="background: rgba(255,255,255,0.2);">🚀</div>
<div class="card-title">Performance</div>
</div>
<div class="metric">
<span class="metric-label">Avg Latency</span>
<span class="metric-value" id="avgLatency">0ms</span>
</div>
<div class="metric">
<span class="metric-label">Throughput</span>
<span class="metric-value" id="throughput">0 MB/s</span>
</div>
<div class="metric">
<span class="metric-label">Memory Usage</span>
<span class="metric-value" id="memoryUsage">0%</span>
</div>
</div>
</div>
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #667eea, #764ba2);">📊</div>
<div class="card-title">Real-time Processing Chart</div>
</div>
<div class="realtime-chart">
📈 Real-time processing visualization will appear here
</div>
</div>
</div>
<!-- Streams Tab -->
<div id="streams" class="tab-content">
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #667eea, #764ba2);">🌊</div>
<div class="card-title">Stream Management</div>
</div>
<button class="btn btn-primary" onclick="showCreateStreamModal()">➕ Create New Stream</button>
<button class="btn btn-success" onclick="refreshStreams()">🔄 Refresh</button>
</div>
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #43e97b, #38f9d7);">📋</div>
<div class="card-title">Active Streams</div>
</div>
<div id="streamsList">
<div class="alert alert-info">No streams created yet. Create your first stream to get started!</div>
</div>
</div>
</div>
<!-- Processors Tab -->
<div id="processors" class="tab-content">
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #667eea, #764ba2);">⚙️</div>
<div class="card-title">Processor Management</div>
</div>
<button class="btn btn-primary" onclick="showCreateProcessorModal()">➕ Create Processor</button>
<button class="btn btn-warning" onclick="showCreateWindowModal()">🪟 Create Window</button>
<button class="btn btn-success" onclick="refreshProcessors()">🔄 Refresh</button>
</div>
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #4facfe, #00f2fe);">🔧</div>
<div class="card-title">Active Processors</div>
</div>
<div id="processorsList">
<div class="alert alert-info">No processors configured yet.</div>
</div>
</div>
</div>
<!-- Analytics Tab -->
<div id="analytics" class="tab-content">
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #667eea, #764ba2);">📊</div>
<div class="card-title">Stream Analytics</div>
</div>
<button class="btn btn-primary" onclick="createAggregationStream()">📈 Create Aggregation</button>
<button class="btn btn-warning" onclick="createContinuousQuery()">🔍 Continuous Query</button>
<button class="btn btn-success" onclick="refreshAnalytics()">🔄 Refresh</button>
</div>
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #43e97b, #38f9d7);">📈</div>
<div class="card-title">Analytics Results</div>
</div>
<div id="analyticsResults">
<div class="alert alert-info">No analytics configured yet.</div>
</div>
</div>
</div>
<!-- Monitoring Tab -->
<div id="monitoring" class="tab-content">
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #667eea, #764ba2);">🔍</div>
<div class="card-title">System Monitoring</div>
</div>
<button class="btn btn-success" onclick="startMonitoring()">▶️ Start Monitoring</button>
<button class="btn btn-danger" onclick="stopMonitoring()">⏹️ Stop Monitoring</button>
<button class="btn btn-primary" onclick="refreshMonitoring()">🔄 Refresh</button>
</div>
<div class="dashboard-grid">
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #fa709a, #fee140);">⚡</div>
<div class="card-title">Performance Metrics</div>
</div>
<div id="performanceMetrics">
<div class="metric">
<span class="metric-label">CPU Usage</span>
<span class="metric-value">0%</span>
</div>
<div class="metric">
<span class="metric-label">Memory Usage</span>
<span class="metric-value">0 MB</span>
</div>
<div class="metric">
<span class="metric-label">Network I/O</span>
<span class="metric-value">0 KB/s</span>
</div>
</div>
</div>
<div class="dashboard-card">
<div class="card-header">
<div class="card-icon" style="background: linear-gradient(45deg, #4facfe, #00f2fe);">📊</div>
<div class="card-title">System Status</div>
</div>
<div id="systemStatus">
<div class="metric">
<span class="metric-label">Engine Status</span>
<span class="metric-value">
<span class="status-indicator status-active"></span>Running
</span>
</div>
<div class="metric">
<span class="metric-label">Uptime</span>
<span class="metric-value">0 minutes</span>
</div>
<div class="metric">
<span class="metric-label">Error Rate</span>
<span class="metric-value">0%</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Create Stream Modal -->
<div id="createStreamModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">Create New Stream</h2>
<button class="close" onclick="closeModal('createStreamModal')">×</button>
</div>
<form id="createStreamForm">
<div class="form-group">
<label class="form-label">Stream ID</label>
<input type="text" class="form-control" id="streamId" required>
</div>
<div class="form-group">
<label class="form-label">Stream Type</label>
<select class="form-control" id="streamType">
<option value="unbounded">Unbounded (Continuous)</option>
<option value="bounded">Bounded (Finite)</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Data Format</label>
<select class="form-control" id="dataFormat">
<option value="json">JSON</option>
<option value="csv">CSV</option>
<option value="avro">Avro</option>
<option value="protobuf">Protocol Buffers</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Description</label>
<input type="text" class="form-control" id="streamDescription">
</div>
<button type="submit" class="btn btn-primary">Create Stream</button>
<button type="button" class="btn btn-secondary" onclick="closeModal('createStreamModal')">Cancel</button>
</form>
</div>
</div>
<!-- Create Processor Modal -->
<div id="createProcessorModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">Create Stream Processor</h2>
<button class="close" onclick="closeModal('createProcessorModal')">×</button>
</div>
<form id="createProcessorForm">
<div class="form-group">
<label class="form-label">Target Stream</label>
<select class="form-control" id="targetStream" required>
<option value="">Select a stream...</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Processor Type</label>
<select class="form-control" id="processorType" required>
<option value="filter">Filter</option>
<option value="map">Transform/Map</option>
<option value="reduce">Reduce</option>
<option value="aggregate">Aggregate</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Processing Function</label>
<textarea class="form-control" id="processingFunction" rows="4"
placeholder="Enter JavaScript function..."></textarea>
</div>
<button type="submit" class="btn btn-primary">Create Processor</button>
<button type="button" class="btn btn-secondary" onclick="closeModal('createProcessorModal')">Cancel</button>
</form>
</div>
</div>
<script>
// Global variables
let streamData = [];
let processorData = [];
let analyticsData = [];
let isMonitoring = false;
// Tab switching
function switchTab(tabName) {
// Hide all tabs
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
// Remove active class from all nav tabs
document.querySelectorAll('.nav-tab').forEach(tab => {
tab.classList.remove('active');
});
// Show selected tab
document.getElementById(tabName).classList.add('active');
// Add active class to clicked nav tab
event.target.classList.add('active');
// Load data for the selected tab
loadTabData(tabName);
}
// Load data for specific tabs
function loadTabData(tabName) {
switch(tabName) {
case 'overview':
loadOverviewData();
break;
case 'streams':
loadStreamsData();
break;
case 'processors':
loadProcessorsData();
break;
case 'analytics':
loadAnalyticsData();
break;
case 'monitoring':
loadMonitoringData();
break;
}
}
// Load overview data
function loadOverviewData() {
// Simulate API calls to BigBaseAlpha
fetch('/api/stream/analytics')
.then(response => response.json())
.then(data => {
document.getElementById('totalStreams').textContent = data.totalStreams || 0;
document.getElementById('activeStreams').textContent = data.activeStreams || 0;
document.getElementById('eventsPerSecond').textContent = data.eventsPerSecond || 0;
document.getElementById('totalProcessors').textContent = data.totalProcessors || 0;
document.getElementById('runningProcessors').textContent = data.runningProcessors || 0;
document.getElementById('processingRate').textContent = (data.processingRate || 0) + ' ops/s';
document.getElementById('activeWindows').textContent = data.activeWindows || 0;
document.getElementById('continuousQueries').textContent = data.continuousQueries || 0;
document.getElementById('streamJoins').textContent = data.streamJoins || 0;
document.getElementById('avgLatency').textContent = (data.avgLatency || 0) + 'ms';
document.getElementById('throughput').textContent = (data.throughput || 0) + ' MB/s';
document.getElementById('memoryUsage').textContent = (data.memoryUsage || 0) + '%';
})
.catch(error => {
console.error('Error loading overview data:', error);
// Set default values
setDefaultOverviewValues();
});
}
function setDefaultOverviewValues() {
document.getElementById('totalStreams').textContent = '0';
document.getElementById('activeStreams').textContent = '0';
document.getElementById('eventsPerSecond').textContent = '0';
document.getElementById('totalProcessors').textContent = '0';
document.getElementById('runningProcessors').textContent = '0';
document.getElementById('processingRate').textContent = '0 ops/s';
document.getElementById('activeWindows').textContent = '0';
document.getElementById('continuousQueries').textContent = '0';
document.getElementById('streamJoins').textContent = '0';
document.getElementById('avgLatency').textContent = '0ms';
document.getElementById('throughput').textContent = '0 MB/s';
document.getElementById('memoryUsage').textContent = '0%';
}
// Load streams data
function loadStreamsData() {
fetch('/api/streams')
.then(response => response.json())
.then(data => {
streamData = data;
renderStreams();
})
.catch(error => {
console.error('Error loading streams:', error);
streamData = [];
renderStreams();
});
}
function renderStreams() {
const streamsList = document.getElementById('streamsList');
if (streamData.length === 0) {
streamsList.innerHTML = '<div class="alert alert-info">No streams created yet. Create your first stream to get started!</div>';
return;
}
const streamsHTML = streamData.map(stream => `
<div class="stream-item">
<div class="stream-info">
<div class="stream-name">
<span class="status-indicator ${stream.active ? 'status-active' : 'status-inactive'}"></span>
${stream.id}
</div>
<div class="stream-stats">
Type: ${stream.type} | Format: ${stream.format} | Events: ${stream.eventCount || 0}
</div>
</div>
<div class="stream-actions">
<button class="btn btn-primary" onclick="publishToStream('${stream.id}')">📤 Publish</button>
<button class="btn btn-warning" onclick="viewStreamDetails('${stream.id}')">👁️ Details</button>
<button class="btn btn-danger" onclick="deleteStream('${stream.id}')">🗑️ Delete</button>
</div>
</div>
`).join('');
streamsList.innerHTML = streamsHTML;
}
// Load processors data
function loadProcessorsData() {
fetch('/api/processors')
.then(response => response.json())
.then(data => {
processorData = data;
renderProcessors();
})
.catch(error => {
console.error('Error loading processors:', error);
processorData = [];
renderProcessors();
});
}
function renderProcessors() {
const processorsList = document.getElementById('processorsList');
if (processorData.length === 0) {
processorsList.innerHTML = '<div class="alert alert-info">No processors configured yet.</div>';
return;
}
const processorsHTML = processorData.map(processor => `
<div class="stream-item">
<div class="stream-info">
<div class="stream-name">
<span class="status-indicator ${processor.active ? 'status-active' : 'status-inactive'}"></span>
${processor.id} (${processor.type})
</div>
<div class="stream-stats">
Stream: ${processor.streamId} | Processed: ${processor.processedCount || 0}
</div>
</div>
<div class="stream-actions">
<button class="btn btn-warning" onclick="viewProcessorDetails('${processor.id}')">👁️ Details</button>
<button class="btn btn-danger" onclick="deleteProcessor('${processor.id}')">🗑️ Delete</button>
</div>
</div>
`).join('');
processorsList.innerHTML = processorsHTML;
}
// Load analytics data
function loadAnalyticsData() {
fetch('/api/analytics')
.then(response => response.json())
.then(data => {
analyticsData = data;
renderAnalytics();
})
.catch(error => {
console.error('Error loading analytics:', error);
analyticsData = [];
renderAnalytics();
});
}
function renderAnalytics() {
const analyticsResults = document.getElementById('analyticsResults');
if (analyticsData.length === 0) {
analyticsResults.innerHTML = '<div class="alert alert-info">No analytics configured yet.</div>';
return;
}
const analyticsHTML = analyticsData.map(analytics => `
<div class="stream-item">
<div class="stream-info">
<div class="stream-name">${analytics.name} (${analytics.type})</div>
<div class="stream-stats">
Stream: ${analytics.streamId} | Last Result: ${analytics.lastResult || 'N/A'}
</div>
</div>
<div class="stream-actions">
<button class="btn btn-primary" onclick="viewAnalyticsDetails('${analytics.id}')">📊 View Results</button>
<button class="btn btn-danger" onclick="deleteAnalytics('${analytics.id}')">🗑️ Delete</button>
</div>
</div>
`).join('');
analyticsResults.innerHTML = analyticsHTML;
}
// Load monitoring data
function loadMonitoringData() {
if (isMonitoring) {
fetch('/api/stream/performance')
.then(response => response.json())
.then(data => {
updatePerformanceMetrics(data);
})
.catch(error => {
console.error('Error loading performance data:', error);
});
fetch('/api/stream/status')
.then(response => response.json())
.then(data => {
updateSystemStatus(data);
})
.catch(error => {
console.error('Error loading system status:', error);
});
}
}
function updatePerformanceMetrics(data) {
// Update performance metrics display
}
function updateSystemStatus(data) {
// Update system status display
}
// Modal functions
function showCreateStreamModal() {
document.getElementById('createStreamModal').style.display = 'block';
}
function showCreateProcessorModal() {
loadStreamOptions();
document.getElementById('createProcessorModal').style.display = 'block';
}
function showCreateWindowModal() {
// Implementation for window creation modal
alert('Window creation modal - Implementation pending');
}
function closeModal(modalId) {
document.getElementById(modalId).style.display = 'none';
}
function loadStreamOptions() {
const select = document.getElementById('targetStream');
select.innerHTML = '<option value="">Select a stream...</option>';
streamData.forEach(stream => {
const option = document.createElement('option');
option.value = stream.id;
option.textContent = stream.id;
select.appendChild(option);
});
}
// Form handlers
document.getElementById('createStreamForm').addEventListener('submit', function(e) {
e.preventDefault();
const streamData = {
id: document.getElementById('streamId').value,
type: document.getElementById('streamType').value,
format: document.getElementById('dataFormat').value,
description: document.getElementById('streamDescription').value
};
fetch('/api/streams', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(streamData)
})
.then(response => response.json())
.then(data => {
alert('Stream created successfully!');
closeModal('createStreamModal');
loadStreamsData();
document.getElementById('createStreamForm').reset();
})
.catch(error => {
console.error('Error creating stream:', error);
alert('Error creating stream: ' + error.message);
});
});
document.getElementById('createProcessorForm').addEventListener('submit', function(e) {
e.preventDefault();
const processorData = {
streamId: document.getElementById('targetStream').value,
type: document.getElementById('processorType').value,
function: document.getElementById('processingFunction').value
};
fetch('/api/processors', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(processorData)
})
.then(response => response.json())
.then(data => {
alert('Processor created successfully!');
closeModal('createProcessorModal');
loadProcessorsData();
document.getElementById('createProcessorForm').reset();
})
.catch(error => {
console.error('Error creating processor:', error);
alert('Error creating processor: ' + error.message);
});
});
// Action functions
function refreshStreams() {
loadStreamsData();
}
function refreshProcessors() {
loadProcessorsData();
}
function refreshAnalytics() {
loadAnalyticsData();
}
function refreshMonitoring() {
loadMonitoringData();
}
function publishToStream(streamId) {
const event = prompt('Enter event data (JSON format):');
if (event) {
try {
const eventData = JSON.parse(event);
fetch(`/api/streams/${streamId}/publish`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(eventData)
})
.then(response => response.json())
.then(data => {
alert('Event published successfully!');
loadStreamsData();
})
.catch(error => {
console.error('Error publishing event:', error);
alert('Error publishing event: ' + error.message);
});
} catch (e) {
alert('Invalid JSON format');
}
}
}
function deleteStream(streamId) {
if (confirm(`Are you sure you want to delete stream ${streamId}?`)) {
fetch(`/api/streams/${streamId}`, {
method: 'DELETE'
})
.then(response => response.json())
.then(data => {
alert('Stream deleted successfully!');
loadStreamsData();
})
.catch(error => {
console.error('Error deleting stream:', error);
alert('Error deleting stream: ' + error.message);
});
}
}
function startMonitoring() {
isMonitoring = true;
// Start periodic updates
setInterval(() => {
if (isMonitoring) {
loadMonitoringData();
}
}, 5000);
alert('Monitoring started');
}
function stopMonitoring() {
isMonitoring = false;
alert('Monitoring stopped');
}
function createAggregationStream() {
const sourceStream = prompt('Enter source stream ID:');
if (sourceStream) {
const config = {
type: 'sum',
field: 'value',
windowSize: 5000
};
fetch('/api/analytics/aggregation', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ sourceStreamId: sourceStream, config })
})
.then(response => response.json())
.then(data => {
alert('Aggregation stream created successfully!');
loadAnalyticsData();
})
.catch(error => {
console.error('Error creating aggregation stream:', error);
alert('Error creating aggregation stream: ' + error.message);
});
}
}
function createContinuousQuery() {
alert('Continuous query creation - Implementation pending');
}
// Initialize dashboard
document.addEventListener('DOMContentLoaded', function() {
loadOverviewData();
setDefaultOverviewValues();
// Set up periodic refresh for overview
setInterval(() => {
if (document.getElementById('overview').classList.contains('active')) {
loadOverviewData();
}
}, 10000);
});
// Close modals when clicking outside
window.addEventListener('click', function(event) {
const modals = document.querySelectorAll('.modal');
modals.forEach(modal => {
if (event.target === modal) {
modal.style.display = 'none';
}
});
});
</script>
</body>
</html>