feat: remove state preservation
This commit is contained in:
10
README.md
10
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
|
||||
|
||||
|
||||
@@ -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...');
|
||||
|
||||
@@ -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]));
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user