Files
spore-ui/public/scripts/app.js

136 lines
5.4 KiB
JavaScript

// Main SPORE UI Application
// Initialize the application when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
console.log('=== SPORE UI Application Initialization ===');
// Initialize the framework (but don't navigate yet)
console.log('App: Creating framework instance...');
const app = window.app;
// Create view models
console.log('App: Creating view models...');
const clusterViewModel = new ClusterViewModel();
const firmwareViewModel = new FirmwareViewModel();
const topologyViewModel = new TopologyViewModel();
console.log('App: View models created:', { clusterViewModel, firmwareViewModel, topologyViewModel });
// Connect firmware view model to cluster data
clusterViewModel.subscribe('members', (members) => {
console.log('App: Members subscription triggered:', members);
if (members && members.length > 0) {
// Extract node information for firmware view
const nodes = members.map(member => ({
ip: member.ip,
hostname: member.hostname || member.ip,
labels: member.labels || {}
}));
firmwareViewModel.updateAvailableNodes(nodes);
console.log('App: Updated firmware view model with nodes:', nodes);
} else {
firmwareViewModel.updateAvailableNodes([]);
console.log('App: Cleared firmware view model nodes');
}
});
// Register routes with their view models
console.log('App: Registering routes...');
app.registerRoute('cluster', ClusterViewComponent, 'cluster-view', clusterViewModel);
app.registerRoute('topology', TopologyGraphComponent, 'topology-view', topologyViewModel);
app.registerRoute('firmware', FirmwareViewComponent, 'firmware-view', firmwareViewModel);
console.log('App: Routes registered and components pre-initialized');
// Initialize cluster status component for header badge
console.log('App: Initializing cluster status component...');
const clusterStatusComponent = new ClusterStatusComponent(
document.querySelector('.cluster-status'),
clusterViewModel,
app.eventBus
);
clusterStatusComponent.mount();
console.log('App: Cluster status component initialized');
// Set up navigation event listeners
console.log('App: Setting up navigation...');
app.setupNavigation();
// Now navigate to the default route
console.log('App: Navigating to default route...');
app.navigateTo('cluster');
console.log('=== SPORE UI Application initialization completed ===');
});
// Burger menu toggle for mobile
(function setupBurgerMenu(){
document.addEventListener('DOMContentLoaded', function(){
const nav = document.querySelector('.main-navigation');
const burger = document.getElementById('burger-btn');
const navLeft = nav ? nav.querySelector('.nav-left') : null;
if (!nav || !burger || !navLeft) return;
burger.addEventListener('click', function(e){
e.preventDefault();
nav.classList.toggle('mobile-open');
});
// Close menu when a nav tab is clicked
navLeft.addEventListener('click', function(e){
const btn = e.target.closest('.nav-tab');
if (btn && nav.classList.contains('mobile-open')) {
nav.classList.remove('mobile-open');
}
});
// Close menu on outside click
document.addEventListener('click', function(e){
if (!nav.contains(e.target) && nav.classList.contains('mobile-open')) {
nav.classList.remove('mobile-open');
}
});
});
})();
// Set up periodic updates with state preservation
function setupPeriodicUpdates() {
// Auto-refresh cluster members every 30 seconds using smart update
setInterval(() => {
if (window.app.currentView && window.app.currentView.viewModel) {
const viewModel = window.app.currentView.viewModel;
// Use smart update if available, otherwise fall back to regular update
if (viewModel.smartUpdate && typeof viewModel.smartUpdate === 'function') {
console.log('App: Performing smart update to preserve UI state...');
viewModel.smartUpdate();
} else if (viewModel.updateClusterMembers && typeof viewModel.updateClusterMembers === 'function') {
console.log('App: Performing regular update...');
viewModel.updateClusterMembers();
}
}
}, 30000);
// Update primary node display every 10 seconds (this is lightweight and doesn't affect UI state)
setInterval(() => {
if (window.app.currentView && window.app.currentView.viewModel) {
const viewModel = window.app.currentView.viewModel;
if (viewModel.updatePrimaryNodeDisplay && typeof viewModel.updatePrimaryNodeDisplay === 'function') {
viewModel.updatePrimaryNodeDisplay();
}
}
}, 10000);
}
// Global error handler
window.addEventListener('error', function(event) {
console.error('Global error:', event.error);
});
// Global unhandled promise rejection handler
window.addEventListener('unhandledrejection', function(event) {
console.error('Unhandled promise rejection:', event.reason);
});
// Clean up on page unload
window.addEventListener('beforeunload', function() {
if (window.app) {
console.log('App: Cleaning up cached components...');
window.app.cleanup();
}
});