258 lines
6.9 KiB
JavaScript
258 lines
6.9 KiB
JavaScript
/**
|
|
* Allegro-Primus Dashboard JavaScript
|
|
* Handles real-time updates, charts, and interactivity
|
|
*/
|
|
|
|
// Auto-refresh configuration
|
|
const AUTO_REFRESH_INTERVAL = 30000; // 30 seconds
|
|
let refreshTimer = null;
|
|
|
|
// Initialize dashboard
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initDashboard();
|
|
startAutoRefresh();
|
|
initCharts();
|
|
});
|
|
|
|
function initDashboard() {
|
|
// Add click handlers for table rows
|
|
document.querySelectorAll('.data-table tbody tr').forEach(row => {
|
|
row.style.cursor = 'pointer';
|
|
row.addEventListener('click', function() {
|
|
this.classList.toggle('selected');
|
|
});
|
|
});
|
|
|
|
// Initialize tooltips if needed
|
|
initTooltips();
|
|
}
|
|
|
|
function initTooltips() {
|
|
// Simple tooltip implementation
|
|
document.querySelectorAll('[title]').forEach(el => {
|
|
el.addEventListener('mouseenter', showTooltip);
|
|
el.addEventListener('mouseleave', hideTooltip);
|
|
});
|
|
}
|
|
|
|
function showTooltip(e) {
|
|
const tooltip = document.createElement('div');
|
|
tooltip.className = 'tooltip';
|
|
tooltip.textContent = e.target.getAttribute('title');
|
|
document.body.appendChild(tooltip);
|
|
|
|
const rect = e.target.getBoundingClientRect();
|
|
tooltip.style.left = rect.left + 'px';
|
|
tooltip.style.top = (rect.bottom + 5) + 'px';
|
|
}
|
|
|
|
function hideTooltip() {
|
|
document.querySelectorAll('.tooltip').forEach(t => t.remove());
|
|
}
|
|
|
|
function initCharts() {
|
|
// Charts are initialized in individual templates
|
|
// This is for any global chart configuration
|
|
Chart.defaults.color = '#94a3b8';
|
|
Chart.defaults.borderColor = '#334155';
|
|
}
|
|
|
|
// Auto-refresh functionality
|
|
function startAutoRefresh() {
|
|
refreshTimer = setInterval(refreshData, AUTO_REFRESH_INTERVAL);
|
|
}
|
|
|
|
function stopAutoRefresh() {
|
|
if (refreshTimer) {
|
|
clearInterval(refreshTimer);
|
|
refreshTimer = null;
|
|
}
|
|
}
|
|
|
|
async function refreshData() {
|
|
try {
|
|
// Refresh metrics
|
|
const metricsResponse = await fetch('/api/metrics');
|
|
if (metricsResponse.ok) {
|
|
const data = await metricsResponse.json();
|
|
updateMetricsDisplay(data.current);
|
|
}
|
|
|
|
// Refresh status
|
|
const statusResponse = await fetch('/api/status');
|
|
if (statusResponse.ok) {
|
|
const status = await statusResponse.json();
|
|
updateStatusDisplay(status);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error refreshing data:', error);
|
|
}
|
|
}
|
|
|
|
function updateMetricsDisplay(metrics) {
|
|
// Update metric cards if they exist
|
|
const successRateEl = document.querySelector('.metric-card.success .metric-value');
|
|
if (successRateEl) {
|
|
successRateEl.textContent = (metrics.success_rate * 100).toFixed(1) + '%';
|
|
}
|
|
}
|
|
|
|
function updateStatusDisplay(status) {
|
|
// Update status indicators
|
|
console.log('Status updated:', status);
|
|
}
|
|
|
|
// API helper functions
|
|
const API = {
|
|
async getStatus() {
|
|
const response = await fetch('/api/status');
|
|
return response.json();
|
|
},
|
|
|
|
async getMetrics() {
|
|
const response = await fetch('/api/metrics');
|
|
return response.json();
|
|
},
|
|
|
|
async getJournal(limit = 50, offset = 0) {
|
|
const response = await fetch(`/api/journal?limit=${limit}&offset=${offset}`);
|
|
return response.json();
|
|
},
|
|
|
|
async getIssues(state = 'all') {
|
|
const response = await fetch(`/api/issues?state=${state}`);
|
|
return response.json();
|
|
},
|
|
|
|
async getKnowledge() {
|
|
const response = await fetch('/api/knowledge');
|
|
return response.json();
|
|
},
|
|
|
|
async healthCheck() {
|
|
const response = await fetch('/api/health');
|
|
return response.json();
|
|
}
|
|
};
|
|
|
|
// Export data functionality
|
|
function exportData(format) {
|
|
window.location.href = `/export/${format}`;
|
|
}
|
|
|
|
// Search functionality for journal
|
|
function searchJournal(query) {
|
|
const rows = document.querySelectorAll('.journal-table tbody tr');
|
|
rows.forEach(row => {
|
|
const text = row.textContent.toLowerCase();
|
|
row.style.display = text.includes(query.toLowerCase()) ? '' : 'none';
|
|
});
|
|
}
|
|
|
|
// Filter functionality
|
|
function filterByStatus(status) {
|
|
const rows = document.querySelectorAll('.journal-table tbody tr');
|
|
rows.forEach(row => {
|
|
const rowStatus = row.querySelector('.badge');
|
|
if (status === 'all' || (rowStatus && rowStatus.classList.contains(status))) {
|
|
row.style.display = '';
|
|
} else {
|
|
row.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
|
|
// Modal functionality
|
|
function showModal(content) {
|
|
const modal = document.getElementById('entryModal');
|
|
const modalContent = document.getElementById('modalContent');
|
|
|
|
if (modal && modalContent) {
|
|
modalContent.innerHTML = content;
|
|
modal.style.display = 'block';
|
|
}
|
|
}
|
|
|
|
function hideModal() {
|
|
const modal = document.getElementById('entryModal');
|
|
if (modal) {
|
|
modal.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
// Close modal when clicking outside
|
|
document.addEventListener('click', function(e) {
|
|
const modal = document.getElementById('entryModal');
|
|
if (e.target === modal) {
|
|
hideModal();
|
|
}
|
|
});
|
|
|
|
// Keyboard shortcuts
|
|
document.addEventListener('keydown', function(e) {
|
|
// ESC to close modal
|
|
if (e.key === 'Escape') {
|
|
hideModal();
|
|
}
|
|
|
|
// R to refresh
|
|
if (e.key === 'r' && !e.ctrlKey && !e.metaKey) {
|
|
refreshData();
|
|
}
|
|
});
|
|
|
|
// Notification system
|
|
function showNotification(message, type = 'info') {
|
|
const notification = document.createElement('div');
|
|
notification.className = `notification notification-${type}`;
|
|
notification.innerHTML = `
|
|
<i class="fas fa-${type === 'success' ? 'check' : type === 'error' ? 'exclamation' : 'info'}-circle"></i>
|
|
<span>${message}</span>
|
|
`;
|
|
|
|
document.body.appendChild(notification);
|
|
|
|
setTimeout(() => {
|
|
notification.classList.add('show');
|
|
}, 10);
|
|
|
|
setTimeout(() => {
|
|
notification.classList.remove('show');
|
|
setTimeout(() => notification.remove(), 300);
|
|
}, 3000);
|
|
}
|
|
|
|
// Utility functions
|
|
function formatDate(dateString) {
|
|
const date = new Date(dateString);
|
|
return date.toLocaleString();
|
|
}
|
|
|
|
function formatDuration(ms) {
|
|
if (ms < 1000) return ms + 'ms';
|
|
if (ms < 60000) return (ms / 1000).toFixed(1) + 's';
|
|
return (ms / 60000).toFixed(1) + 'm';
|
|
}
|
|
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
}
|
|
|
|
// Performance monitoring
|
|
function measurePerformance() {
|
|
const perfData = performance.getEntriesByType('navigation')[0];
|
|
console.log('Page load time:', perfData.loadEventEnd - perfData.loadEventStart, 'ms');
|
|
}
|
|
|
|
// Log dashboard load
|
|
console.log('🚀 Allegro-Primus Dashboard loaded');
|
|
console.log('Press R to refresh data');
|