// Monitoring View Component class MonitoringViewComponent extends Component { constructor(container, viewModel, eventBus) { super(container, viewModel, eventBus); logger.debug('MonitoringViewComponent: Constructor called'); logger.debug('MonitoringViewComponent: Container:', container); logger.debug('MonitoringViewComponent: Container ID:', container?.id); // Track if we've already loaded data to prevent unnecessary reloads this.dataLoaded = false; // Drawer state for desktop this.drawer = new DrawerComponent(); } mount() { logger.debug('MonitoringViewComponent: Mounting...'); super.mount(); // Set up refresh button event listener this.setupRefreshButton(); // Only load data if we haven't already or if the view model is empty const clusterMembers = this.viewModel.get('clusterMembers'); if (!this.dataLoaded || !clusterMembers || clusterMembers.length === 0) { this.loadData(); } // Subscribe to view model changes this.setupSubscriptions(); } setupRefreshButton() { const refreshBtn = this.findElement('#refresh-monitoring-btn'); if (refreshBtn) { refreshBtn.addEventListener('click', () => { this.refreshData(); }); } } setupSubscriptions() { // Subscribe to cluster members changes this.viewModel.subscribe('clusterMembers', () => { this.render(); }); // Subscribe to node resources changes this.viewModel.subscribe('nodeResources', () => { this.render(); }); // Subscribe to cluster summary changes this.viewModel.subscribe('clusterSummary', () => { this.render(); }); // Subscribe to loading state changes this.viewModel.subscribe('isLoading', () => { this.render(); }); // Subscribe to error changes this.viewModel.subscribe('error', () => { this.render(); }); } async loadData() { logger.debug('MonitoringViewComponent: Loading data...'); this.dataLoaded = true; await this.viewModel.loadClusterData(); } async refreshData() { logger.debug('MonitoringViewComponent: Refreshing data...'); await this.viewModel.refresh(); } // Determine if we should use desktop drawer behavior isDesktop() { return this.drawer.isDesktop(); } // Open drawer for a specific node openDrawerForNode(nodeData) { const { ip, hostname } = nodeData; // Get display name for drawer title let displayName = ip; if (hostname && ip) { displayName = `${hostname} - ${ip}`; } else if (hostname) { displayName = hostname; } else if (ip) { displayName = ip; } // Open drawer with content callback this.drawer.openDrawer(displayName, (contentContainer, setActiveComponent) => { // Load and mount NodeDetails into drawer const nodeDetailsVM = new NodeDetailsViewModel(); const nodeDetailsComponent = new NodeDetailsComponent(contentContainer, nodeDetailsVM, this.eventBus); setActiveComponent(nodeDetailsComponent); nodeDetailsVM.loadNodeDetails(ip).then(() => { nodeDetailsComponent.mount(); }).catch((error) => { logger.error('Failed to load node details for drawer:', error); contentContainer.innerHTML = `