refactor(components): split components.js into separate files and add loader; app waits for components before init
This commit is contained in:
90
public/scripts/components/PrimaryNodeComponent.js
Normal file
90
public/scripts/components/PrimaryNodeComponent.js
Normal file
@@ -0,0 +1,90 @@
|
||||
// Primary Node Component
|
||||
class PrimaryNodeComponent extends Component {
|
||||
constructor(container, viewModel, eventBus) {
|
||||
super(container, viewModel, eventBus);
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
const refreshBtn = this.findElement('.primary-node-refresh');
|
||||
if (refreshBtn) {
|
||||
this.addEventListener(refreshBtn, 'click', this.handleRandomSelection.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
setupViewModelListeners() {
|
||||
// Listen to primary node changes
|
||||
this.subscribeToProperty('primaryNode', this.render.bind(this));
|
||||
this.subscribeToProperty('clientInitialized', this.render.bind(this));
|
||||
this.subscribeToProperty('totalNodes', this.render.bind(this));
|
||||
this.subscribeToProperty('onlineNodes', this.render.bind(this));
|
||||
this.subscribeToProperty('error', this.render.bind(this));
|
||||
}
|
||||
|
||||
render() {
|
||||
const primaryNode = this.viewModel.get('primaryNode');
|
||||
const clientInitialized = this.viewModel.get('clientInitialized');
|
||||
const totalNodes = this.viewModel.get('totalNodes');
|
||||
const onlineNodes = this.viewModel.get('onlineNodes');
|
||||
const error = this.viewModel.get('error');
|
||||
|
||||
if (error) {
|
||||
this.setText('#primary-node-ip', '❌ Discovery Failed');
|
||||
this.setClass('#primary-node-ip', 'error', true);
|
||||
this.setClass('#primary-node-ip', 'discovering', false);
|
||||
this.setClass('#primary-node-ip', 'selecting', false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!primaryNode) {
|
||||
this.setText('#primary-node-ip', '🔍 No Nodes Found');
|
||||
this.setClass('#primary-node-ip', 'error', true);
|
||||
this.setClass('#primary-node-ip', 'discovering', false);
|
||||
this.setClass('#primary-node-ip', 'selecting', false);
|
||||
return;
|
||||
}
|
||||
|
||||
const status = clientInitialized ? '✅' : '⚠️';
|
||||
const nodeCount = (onlineNodes && onlineNodes > 0)
|
||||
? ` (${onlineNodes}/${totalNodes} online)`
|
||||
: (totalNodes > 1 ? ` (${totalNodes} nodes)` : '');
|
||||
|
||||
this.setText('#primary-node-ip', `${status} ${primaryNode}${nodeCount}`);
|
||||
this.setClass('#primary-node-ip', 'error', false);
|
||||
this.setClass('#primary-node-ip', 'discovering', false);
|
||||
this.setClass('#primary-node-ip', 'selecting', false);
|
||||
}
|
||||
|
||||
async handleRandomSelection() {
|
||||
try {
|
||||
// Show selecting state
|
||||
this.setText('#primary-node-ip', '🎲 Selecting...');
|
||||
this.setClass('#primary-node-ip', 'selecting', true);
|
||||
this.setClass('#primary-node-ip', 'discovering', false);
|
||||
this.setClass('#primary-node-ip', 'error', false);
|
||||
|
||||
await this.viewModel.selectRandomPrimaryNode();
|
||||
|
||||
// Show success briefly
|
||||
this.setText('#primary-node-ip', '🎯 Selection Complete');
|
||||
|
||||
// Update display after delay
|
||||
setTimeout(() => {
|
||||
this.viewModel.updatePrimaryNodeDisplay();
|
||||
}, 1500);
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Failed to select random primary node:', error);
|
||||
this.setText('#primary-node-ip', '❌ Selection Failed');
|
||||
this.setClass('#primary-node-ip', 'error', true);
|
||||
this.setClass('#primary-node-ip', 'selecting', false);
|
||||
this.setClass('#primary-node-ip', 'discovering', false);
|
||||
|
||||
// Revert to normal display after error
|
||||
setTimeout(() => {
|
||||
this.viewModel.updatePrimaryNodeDisplay();
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.PrimaryNodeComponent = PrimaryNodeComponent;
|
||||
Reference in New Issue
Block a user