From 0aca182de9c5733c4fa972bbe3744e0d3075cf69 Mon Sep 17 00:00:00 2001 From: Patrick Balsiger Date: Fri, 19 Sep 2025 21:12:15 +0200 Subject: [PATCH] feat: remove state preservation --- README.md | 10 +++---- public/scripts/app.js | 4 +-- .../components/ClusterMembersComponent.js | 20 ++++++------- .../components/NodeDetailsComponent.js | 10 +++---- public/scripts/framework.js | 12 ++------ public/scripts/view-models.js | 28 +++++++++---------- 6 files changed, 38 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index b481c32..dd01bae 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,13 @@ spore-ui/ ├── public/ # Frontend files │ ├── index.html # Main HTML page │ ├── styles.css # All CSS styles -│ ├── framework.js # Enhanced component framework with state preservation +│ ├── framework.js # Enhanced component framework │ ├── components.js # UI components with partial update support │ ├── view-models.js # Data models with UI state management │ ├── app.js # Main application logic -│ └── test-state-preservation.html # Test interface for state preservation +│ └── test-interface.html # Test interface ├── docs/ -│ └── STATE_PRESERVATION.md # Detailed documentation of state preservation system +│ └── FRAMEWORK_README.md # Framework documentation └── README.md # This file ``` @@ -48,7 +48,7 @@ spore-ui/ 1. **Install dependencies**: `npm install` 2. **Start the server**: `npm start` 3. **Open in browser**: `http://localhost:3001` -4. **Test state preservation**: `http://localhost:3001/test-state-preservation.html` +4. **Test interface**: `http://localhost:3001/test-interface.html` ## API Endpoints @@ -62,7 +62,7 @@ spore-ui/ - **Backend**: Express.js, Node.js - **Frontend**: Vanilla JavaScript, CSS3, HTML5 -- **Framework**: Custom component-based architecture with state preservation +- **Framework**: Custom component-based architecture - **API**: SPORE Embedded System API - **Design**: Glassmorphism, CSS Grid, Flexbox diff --git a/public/scripts/app.js b/public/scripts/app.js index ed17044..95f045c 100644 --- a/public/scripts/app.js +++ b/public/scripts/app.js @@ -90,7 +90,7 @@ document.addEventListener('DOMContentLoaded', async function() { }); })(); -// Set up periodic updates with state preservation +// Set up periodic updates function setupPeriodicUpdates() { // Auto-refresh cluster members every 30 seconds using smart update setInterval(() => { @@ -99,7 +99,7 @@ function setupPeriodicUpdates() { // Use smart update if available, otherwise fall back to regular update if (viewModel.smartUpdate && typeof viewModel.smartUpdate === 'function') { - logger.debug('App: Performing smart update to preserve UI state...'); + logger.debug('App: Performing smart update...'); viewModel.smartUpdate(); } else if (viewModel.updateClusterMembers && typeof viewModel.updateClusterMembers === 'function') { logger.debug('App: Performing regular update...'); diff --git a/public/scripts/components/ClusterMembersComponent.js b/public/scripts/components/ClusterMembersComponent.js index c2642e7..ff5f222 100644 --- a/public/scripts/components/ClusterMembersComponent.js +++ b/public/scripts/components/ClusterMembersComponent.js @@ -1,4 +1,4 @@ -// Cluster Members Component with enhanced state preservation +// Cluster Members Component class ClusterMembersComponent extends Component { constructor(container, viewModel, eventBus) { super(container, viewModel, eventBus); @@ -142,7 +142,7 @@ class ClusterMembersComponent extends Component { logger.debug('ClusterMembersComponent: View model listeners set up'); } - // Handle members update with state preservation + // Handle members update handleMembersUpdate(newMembers, previousMembers) { logger.debug('ClusterMembersComponent: Members updated:', { newMembers, previousMembers }); @@ -166,9 +166,9 @@ class ClusterMembersComponent extends Component { return; } - if (this.shouldPreserveState(newMembers, previousMembers)) { - // Perform partial update to preserve UI state - logger.debug('ClusterMembersComponent: Preserving state, performing partial update'); + if (this.shouldSkipFullRender(newMembers, previousMembers)) { + // Perform partial update + logger.debug('ClusterMembersComponent: Skipping full render, performing partial update'); this.updateMembersPartially(newMembers, previousMembers); } else { // Full re-render if structure changed significantly @@ -242,8 +242,8 @@ class ClusterMembersComponent extends Component { } } - // Check if we should preserve UI state during update - shouldPreserveState(newMembers, previousMembers) { + // Check if we should skip full re-render during update + shouldSkipFullRender(newMembers, previousMembers) { if (!previousMembers || !Array.isArray(previousMembers)) return false; if (!Array.isArray(newMembers)) return false; @@ -254,7 +254,7 @@ class ClusterMembersComponent extends Component { const newIps = new Set(newMembers.map(m => m.ip)); const prevIps = new Set(previousMembers.map(m => m.ip)); - // If IPs are the same, we can preserve state + // If IPs are the same, we can skip full re-render return newIps.size === prevIps.size && [...newIps].every(ip => prevIps.has(ip)); } @@ -269,9 +269,9 @@ class ClusterMembersComponent extends Component { return false; } - // Update members partially to preserve UI state + // Update members partially updateMembersPartially(newMembers, previousMembers) { - logger.debug('ClusterMembersComponent: Performing partial update to preserve UI state'); + logger.debug('ClusterMembersComponent: Performing partial update'); // Build previous map by IP for stable diffs const prevByIp = new Map((previousMembers || []).map(m => [m.ip, m])); diff --git a/public/scripts/components/NodeDetailsComponent.js b/public/scripts/components/NodeDetailsComponent.js index bcc0034..196518d 100644 --- a/public/scripts/components/NodeDetailsComponent.js +++ b/public/scripts/components/NodeDetailsComponent.js @@ -1,4 +1,4 @@ -// Node Details Component with enhanced state preservation +// Node Details Component class NodeDetailsComponent extends Component { constructor(container, viewModel, eventBus) { super(container, viewModel, eventBus); @@ -15,14 +15,14 @@ class NodeDetailsComponent extends Component { this.subscribeToProperty('monitoringResources', this.handleMonitoringResourcesUpdate.bind(this)); } - // Handle node status update with state preservation + // Handle node status update handleNodeStatusUpdate(newStatus, previousStatus) { if (newStatus && !this.viewModel.get('isLoading')) { this.renderNodeDetails(newStatus, this.viewModel.get('tasks'), this.viewModel.get('endpoints'), this.viewModel.get('monitoringResources')); } } - // Handle tasks update with state preservation + // Handle tasks update handleTasksUpdate(newTasks, previousTasks) { const nodeStatus = this.viewModel.get('nodeStatus'); if (nodeStatus && !this.viewModel.get('isLoading')) { @@ -51,7 +51,7 @@ class NodeDetailsComponent extends Component { this.updateActiveTab(newTab, previousTab); } - // Handle endpoints update with state preservation + // Handle endpoints update handleEndpointsUpdate(newEndpoints, previousEndpoints) { const nodeStatus = this.viewModel.get('nodeStatus'); const tasks = this.viewModel.get('tasks'); @@ -60,7 +60,7 @@ class NodeDetailsComponent extends Component { } } - // Handle monitoring resources update with state preservation + // Handle monitoring resources update handleMonitoringResourcesUpdate(newResources, previousResources) { const nodeStatus = this.viewModel.get('nodeStatus'); const tasks = this.viewModel.get('tasks'); diff --git a/public/scripts/framework.js b/public/scripts/framework.js index c33d474..68d0837 100644 --- a/public/scripts/framework.js +++ b/public/scripts/framework.js @@ -225,10 +225,7 @@ class ViewModel { // Batch update with change detection batchUpdate(updates, options = {}) { - const { preserveUIState = true, notifyChanges = true } = options; - - // Optionally preserve UI state snapshot - const currentUIState = preserveUIState ? new Map(this._uiState) : null; + const { notifyChanges = true } = options; // Track which keys actually change and what the previous values were const changedKeys = []; @@ -245,11 +242,6 @@ class ViewModel { } }); - // Restore UI state if requested - if (preserveUIState && currentUIState) { - this._uiState = currentUIState; - } - // Notify listeners for changed keys if (notifyChanges) { changedKeys.forEach(key => { @@ -259,7 +251,7 @@ class ViewModel { } } -// Base Component class with enhanced state preservation +// Base Component class class Component { constructor(container, viewModel, eventBus) { this.container = container; diff --git a/public/scripts/view-models.js b/public/scripts/view-models.js index 38cfba1..d6fe1bb 100644 --- a/public/scripts/view-models.js +++ b/public/scripts/view-models.js @@ -1,6 +1,6 @@ // View Models for SPORE UI Components -// Cluster View Model with enhanced state preservation +// Cluster View Model class ClusterViewModel extends ViewModel { constructor() { super(); @@ -23,7 +23,7 @@ class ClusterViewModel extends ViewModel { }, 100); } - // Update cluster members with state preservation + // Update cluster members async updateClusterMembers() { try { logger.debug('ClusterViewModel: updateClusterMembers called'); @@ -45,12 +45,12 @@ class ClusterViewModel extends ViewModel { ? members.filter(m => m && m.status && m.status.toUpperCase() === 'ACTIVE').length : 0; - // Use batch update to preserve UI state + // Use batch update this.batchUpdate({ members: members, lastUpdateTime: new Date().toISOString(), onlineNodes: onlineNodes - }, { preserveUIState: true }); + }); // Restore expanded cards and active tabs this.set('expandedCards', currentExpandedCards); @@ -69,12 +69,12 @@ class ClusterViewModel extends ViewModel { } } - // Update primary node display with state preservation + // Update primary node display async updatePrimaryNodeDisplay() { try { const discoveryInfo = await window.apiClient.getDiscoveryInfo(); - // Use batch update to preserve UI state + // Use batch update const updates = {}; if (discoveryInfo.primaryNode) { @@ -91,7 +91,7 @@ class ClusterViewModel extends ViewModel { updates.totalNodes = 0; } - this.batchUpdate(updates, { preserveUIState: true }); + this.batchUpdate(updates); } catch (error) { console.error('Failed to fetch discovery info:', error); @@ -208,7 +208,7 @@ class ClusterViewModel extends ViewModel { } } -// Node Details View Model with enhanced state preservation +// Node Details View Model class NodeDetailsViewModel extends ViewModel { constructor() { super(); @@ -225,7 +225,7 @@ class NodeDetailsViewModel extends ViewModel { }); } - // Load node details with state preservation + // Load node details async loadNodeDetails(ip) { try { // Store current UI state @@ -237,10 +237,10 @@ class NodeDetailsViewModel extends ViewModel { const nodeStatus = await window.apiClient.getNodeStatus(ip); - // Use batch update to preserve UI state + // Use batch update this.batchUpdate({ nodeStatus: nodeStatus - }, { preserveUIState: true }); + }); // Restore active tab this.set('activeTab', currentActiveTab); @@ -262,7 +262,7 @@ class NodeDetailsViewModel extends ViewModel { } } - // Load tasks data with state preservation + // Load tasks data async loadTasksData() { try { const ip = this.get('nodeIp'); @@ -276,7 +276,7 @@ class NodeDetailsViewModel extends ViewModel { } } - // Load endpoints data with state preservation + // Load endpoints data async loadEndpointsData() { try { const ip = this.get('nodeIp'); @@ -290,7 +290,7 @@ class NodeDetailsViewModel extends ViewModel { } } - // Load monitoring resources data with state preservation + // Load monitoring resources data async loadMonitoringResources() { try { const ip = this.get('nodeIp'); -- 2.49.1