diff --git a/public/scripts/api-client.js b/public/scripts/api-client.js index dd90201..bcd0f91 100644 --- a/public/scripts/api-client.js +++ b/public/scripts/api-client.js @@ -51,92 +51,56 @@ class ApiClient { } async getClusterMembers() { - try { - return await this.request('/api/cluster/members', { method: 'GET' }); - } catch (error) { - throw new Error(`Request failed: ${error.message}`); - } + return this.request('/api/cluster/members', { method: 'GET' }); } async getClusterMembersFromNode(ip) { - try { - return await this.request(`/api/cluster/members`, { - method: 'GET', - query: { ip: ip } - }); - } catch (error) { - throw new Error(`Request failed: ${error.message}`); - } + return this.request(`/api/cluster/members`, { + method: 'GET', + query: { ip: ip } + }); } async getDiscoveryInfo() { - try { - return await this.request('/api/discovery/nodes', { method: 'GET' }); - } catch (error) { - throw new Error(`Request failed: ${error.message}`); - } + return this.request('/api/discovery/nodes', { method: 'GET' }); } async selectRandomPrimaryNode() { - try { - return await this.request('/api/discovery/random-primary', { - method: 'POST', - body: { timestamp: new Date().toISOString() } - }); - } catch (error) { - throw new Error(`Request failed: ${error.message}`); - } + return this.request('/api/discovery/random-primary', { + method: 'POST', + body: { timestamp: new Date().toISOString() } + }); } async getNodeStatus(ip) { - try { - return await this.request(`/api/node/status/${encodeURIComponent(ip)}`, { method: 'GET' }); - } catch (error) { - throw new Error(`Request failed: ${error.message}`); - } + return this.request(`/api/node/status/${encodeURIComponent(ip)}`, { method: 'GET' }); } async getTasksStatus(ip) { - try { - return await this.request('/api/tasks/status', { method: 'GET', query: ip ? { ip } : undefined }); - } catch (error) { - throw new Error(`Request failed: ${error.message}`); - } + return this.request('/api/tasks/status', { method: 'GET', query: ip ? { ip } : undefined }); } async getCapabilities(ip) { - try { - return await this.request('/api/capabilities', { method: 'GET', query: ip ? { ip } : undefined }); - } catch (error) { - throw new Error(`Request failed: ${error.message}`); - } + return this.request('/api/capabilities', { method: 'GET', query: ip ? { ip } : undefined }); } async callCapability({ ip, method, uri, params }) { - try { - return await this.request('/api/proxy-call', { - method: 'POST', - body: { ip, method, uri, params } - }); - } catch (error) { - throw new Error(`Request failed: ${error.message}`); - } + return this.request('/api/proxy-call', { + method: 'POST', + body: { ip, method, uri, params } + }); } async uploadFirmware(file, nodeIp) { - try { - const formData = new FormData(); - formData.append('file', file); - return await this.request(`/api/node/update`, { - method: 'POST', - query: { ip: nodeIp }, - body: formData, - isForm: true, - headers: {}, - }); - } catch (error) { - throw new Error(`Upload failed: ${error.message}`); - } + const formData = new FormData(); + formData.append('file', file); + return this.request(`/api/node/update`, { + method: 'POST', + query: { ip: nodeIp }, + body: formData, + isForm: true, + headers: {}, + }); } } diff --git a/public/scripts/components.js b/public/scripts/components.js index b81e452..11cb776 100644 --- a/public/scripts/components.js +++ b/public/scripts/components.js @@ -285,22 +285,11 @@ class ClusterMembersComponent extends Component { // Check if we should skip rendering during view switches shouldSkipRender() { - // Skip rendering if we're in the middle of a view switch - const isViewSwitching = document.querySelectorAll('.view-content.active').length === 0; - if (isViewSwitching) { - console.log('ClusterMembersComponent: View switching in progress, skipping render'); + // Rely on lifecycle flags controlled by App + if (!this.isMounted || this.isPaused) { + logger.debug('ClusterMembersComponent: Not mounted or paused, skipping render'); return true; } - - // Skip rendering if the component is not visible - const isVisible = this.container.style.display !== 'none' && - this.container.style.opacity !== '0' && - this.container.classList.contains('active'); - if (!isVisible) { - console.log('ClusterMembersComponent: Component not visible, skipping render'); - return true; - } - return false; } @@ -308,11 +297,12 @@ class ClusterMembersComponent extends Component { updateMembersPartially(newMembers, previousMembers) { console.log('ClusterMembersComponent: Performing partial update to preserve UI state'); - // Update only the data that changed, preserving expanded states and active tabs - newMembers.forEach((newMember, index) => { - const prevMember = previousMembers[index]; + // Build previous map by IP for stable diffs + const prevByIp = new Map((previousMembers || []).map(m => [m.ip, m])); + newMembers.forEach((newMember) => { + const prevMember = prevByIp.get(newMember.ip); if (prevMember && this.hasMemberChanged(newMember, prevMember)) { - this.updateMemberCard(newMember, index); + this.updateMemberCard(newMember); } }); } @@ -325,7 +315,7 @@ class ClusterMembersComponent extends Component { } // Update a specific member card without re-rendering the entire component - updateMemberCard(member, index) { + updateMemberCard(member) { const card = this.findElement(`[data-member-ip="${member.ip}"]`); if (!card) return; @@ -451,9 +441,9 @@ class ClusterMembersComponent extends Component {