diff --git a/static/discovery.js b/static/discovery.js index 00e12b8..26171b4 100644 --- a/static/discovery.js +++ b/static/discovery.js @@ -1,6 +1,8 @@ // Simplified Discovery Integration // Updated for simplified signal names + tags architecture +console.log('=== DISCOVERY.JS FILE LOADED - START ==='); + class SimplifiedProtocolDiscovery { constructor() { this.currentScanId = 'simplified-scan-123'; @@ -8,74 +10,99 @@ class SimplifiedProtocolDiscovery { } init() { - this.bindDiscoveryEvents(); + console.log('Discovery.js: init() called'); + try { + this.bindDiscoveryEvents(); + console.log('Discovery.js: bindDiscoveryEvents() completed successfully'); + } catch (error) { + console.error('Discovery.js: Error in init():', error); + } } bindDiscoveryEvents() { + console.log('Binding discovery events...'); + // Discovery scan button const startScanBtn = document.getElementById('start-discovery-scan'); + console.log('Start scan button:', startScanBtn); if (startScanBtn) { startScanBtn.addEventListener('click', () => { + console.log('Start Discovery Scan button clicked!'); this.startDiscoveryScan(); }); + } else { + console.error('Start scan button not found!'); } + // Check if discovery results container exists + const resultsContainer = document.getElementById('discovery-results'); + console.log('Discovery results container during init:', resultsContainer); + // Auto-fill signal form from discovery - document.addEventListener('click', (e) => { - if (e.target.classList.contains('use-discovered-endpoint')) { - this.useDiscoveredEndpoint(e.target.dataset.endpointId); - } - }); + console.log('Setting up global click event listener for use-signal-btn'); + try { + const self = this; // Capture 'this' context + document.addEventListener('click', function(e) { + console.log('Global click event fired, target:', e.target.tagName, 'classes:', e.target.className); + console.log('Target dataset:', e.target.dataset); + + if (e.target.classList.contains('use-signal-btn')) { + console.log('Use This Signal button clicked!'); + console.log('Signal index from dataset:', e.target.dataset.signalIndex); + self.useDiscoveredEndpoint(e.target.dataset.signalIndex); + } else { + console.log('Clicked element is not a use-signal-btn'); + } + }); + console.log('Global click event listener set up successfully'); + } catch (error) { + console.error('Error setting up event listener:', error); + } } - async useDiscoveredEndpoint(endpointId) { - console.log('Using discovered endpoint:', endpointId); + async useDiscoveredEndpoint(signalIndex) { + console.log('Using discovered endpoint with index:', signalIndex); - // Mock endpoint data (in real implementation, this would come from discovery service) - const endpoints = { - 'device_001': { - device_id: 'device_001', - protocol_type: 'modbus_tcp', - device_name: 'Water Pump Controller', - address: '192.168.1.100', - port: 502, - data_point: 'Speed', - protocol_address: '40001' - }, - 'device_002': { - device_id: 'device_002', - protocol_type: 'opcua', - device_name: 'Temperature Sensor', - address: '192.168.1.101', - port: 4840, - data_point: 'Temperature', - protocol_address: 'ns=2;s=Temperature' - }, - 'device_003': { - device_id: 'device_003', - protocol_type: 'modbus_tcp', - device_name: 'Pressure Transmitter', - address: '192.168.1.102', - port: 502, - data_point: 'Pressure', - protocol_address: '30001' - } - }; + // Get the actual discovered endpoints from the mock scan + const discoveredEndpoints = await this.mockDiscoveryScan('192.168.1.0/24'); - const endpoint = endpoints[endpointId]; + // Map signal index to endpoint + const endpoint = discoveredEndpoints[signalIndex]; if (!endpoint) { - this.showNotification(`Endpoint ${endpointId} not found`, 'error'); + this.showNotification(`Endpoint with index ${signalIndex} not found`, 'error'); return; } // Convert to simplified signal format const signalData = this.convertEndpointToSignal(endpoint); - // Auto-populate the signal form - this.autoPopulateSignalForm(signalData); + // Auto-populate the signal form with retry logic + this.autoPopulateSignalFormWithRetry(signalData); this.showNotification(`Endpoint ${endpoint.device_name} selected for signal creation`, 'success'); } + + autoPopulateSignalFormWithRetry(signalData, retryCount = 0) { + console.log('Attempting to auto-populate signal form, attempt:', retryCount + 1); + + if (typeof window.autoPopulateSignalForm === 'function') { + console.log('Found window.autoPopulateSignalForm, calling it...'); + window.autoPopulateSignalForm(signalData); + } else { + console.error('autoPopulateSignalForm function not found'); + + // Retry after a delay if we haven't exceeded max retries + if (retryCount < 5) { + console.log(`Retrying in 500ms... (${retryCount + 1}/5)`); + setTimeout(() => { + this.autoPopulateSignalFormWithRetry(signalData, retryCount + 1); + }, 500); + } else { + console.error('Max retries exceeded, autoPopulateSignalForm function still not found'); + this.showNotification('Error: Could not open signal form. Please ensure the protocol mapping system is loaded.', 'error'); + } + } + } convertEndpointToSignal(endpoint) { // Generate human-readable signal name @@ -120,25 +147,7 @@ class SimplifiedProtocolDiscovery { } - autoPopulateSignalForm(signalData) { - console.log('Auto-populating signal form with:', signalData); - - // Ensure protocol mapping tab is active - if (typeof showTab === 'function') { - showTab('protocol-mapping'); - } - - // Use the simplified protocol mapping function - if (typeof window.autoPopulateSignalForm === 'function') { - // Add a small delay to ensure the tab is loaded - setTimeout(() => { - window.autoPopulateSignalForm(signalData); - }, 100); - } else { - console.error('Simplified protocol mapping functions not loaded'); - this.showNotification('Protocol mapping system not available', 'error'); - } - } // Start discovery scan + // Start discovery scan async startDiscoveryScan() { console.log('Starting discovery scan...'); @@ -249,6 +258,7 @@ class SimplifiedProtocolDiscovery { return; } + console.log('Found discovery results container:', resultsContainer); resultsContainer.innerHTML = '

Discovery Results

'; suggestedSignals.forEach((signal, index) => { @@ -274,13 +284,35 @@ class SimplifiedProtocolDiscovery { }); // Add event listeners for use buttons - resultsContainer.addEventListener('click', (e) => { + console.log('Adding event listener to results container'); + console.log('Results container:', resultsContainer); + console.log('Results container ID:', resultsContainer.id); + console.log('Number of use-signal-btn elements:', resultsContainer.querySelectorAll('.use-signal-btn').length); + + const clickHandler = (e) => { + console.log('Discovery results container clicked:', e.target); + console.log('Button classes:', e.target.classList); + console.log('Button tag name:', e.target.tagName); if (e.target.classList.contains('use-signal-btn')) { + console.log('Use This Signal button clicked!'); const signalIndex = parseInt(e.target.dataset.signalIndex); + console.log('Signal index:', signalIndex); const signal = suggestedSignals[signalIndex]; - this.autoPopulateSignalForm(signal); + console.log('Signal data:', signal); + + // Use the global function directly + if (typeof window.autoPopulateSignalForm === 'function') { + window.autoPopulateSignalForm(signal); + } else { + console.error('autoPopulateSignalForm function not found!'); + } + } else { + console.log('Clicked element is not a use-signal-btn'); } - }); + }; + + resultsContainer.addEventListener('click', clickHandler); + console.log('Event listener added to results container'); // Add "Apply All" button const applyAllButton = document.createElement('button'); @@ -308,8 +340,20 @@ class SimplifiedProtocolDiscovery { let successCount = 0; let errorCount = 0; + let duplicateCount = 0; + + // First, check which signals already exist + const existingSignals = await this.getExistingSignals(); + const existingSignalNames = new Set(existingSignals.map(s => s.signal_name)); for (const signal of signals) { + // Skip if signal with same name already exists + if (existingSignalNames.has(signal.signal_name)) { + console.log(`⚠ Skipping duplicate signal: ${signal.signal_name}`); + duplicateCount++; + continue; + } + try { const response = await fetch('/api/v1/dashboard/protocol-signals', { method: 'POST', @@ -322,9 +366,16 @@ class SimplifiedProtocolDiscovery { if (data.success) { successCount++; console.log(`✓ Created signal: ${signal.signal_name}`); + // Add to existing set to prevent duplicates in same batch + existingSignalNames.add(signal.signal_name); } else { errorCount++; console.error(`✗ Failed to create signal: ${signal.signal_name}`, data.detail); + + // Check if it's a duplicate error + if (data.detail && data.detail.includes('already exists')) { + duplicateCount++; + } } } catch (error) { errorCount++; @@ -333,14 +384,40 @@ class SimplifiedProtocolDiscovery { } // Show results - const message = `Created ${successCount} signals successfully. ${errorCount > 0 ? `${errorCount} failed.` : ''}`; - this.showNotification(message, errorCount > 0 ? 'warning' : 'success'); + let message = `Created ${successCount} signals successfully.`; + if (errorCount > 0) { + message += ` ${errorCount} failed.`; + } + if (duplicateCount > 0) { + message += ` ${duplicateCount} duplicates skipped.`; + } + + const notificationType = errorCount > 0 ? 'warning' : (successCount > 0 ? 'success' : 'info'); + this.showNotification(message, notificationType); // Refresh the protocol signals display if (typeof window.loadAllSignals === 'function') { window.loadAllSignals(); } } + + // Get existing signals to check for duplicates + async getExistingSignals() { + try { + const response = await fetch('/api/v1/dashboard/protocol-signals'); + const data = await response.json(); + + if (data.success) { + return data.signals || []; + } else { + console.error('Failed to get existing signals:', data.detail); + return []; + } + } catch (error) { + console.error('Error getting existing signals:', error); + return []; + } + } // Tag-based signal search async searchSignalsByTags(tags) { @@ -363,6 +440,47 @@ class SimplifiedProtocolDiscovery { } } + // Clear all existing signals (for testing) + async clearAllSignals() { + if (!confirm('Are you sure you want to delete ALL protocol signals? This action cannot be undone.')) { + return; + } + + try { + const existingSignals = await this.getExistingSignals(); + let deletedCount = 0; + + for (const signal of existingSignals) { + try { + const response = await fetch(`/api/v1/dashboard/protocol-signals/${signal.signal_id}`, { + method: 'DELETE' + }); + + const data = await response.json(); + + if (data.success) { + deletedCount++; + console.log(`✓ Deleted signal: ${signal.signal_name}`); + } else { + console.error(`✗ Failed to delete signal: ${signal.signal_name}`, data.detail); + } + } catch (error) { + console.error(`✗ Error deleting signal: ${signal.signal_name}`, error); + } + } + + this.showNotification(`Deleted ${deletedCount} signals successfully.`, 'success'); + + // Refresh the protocol signals display + if (typeof window.loadAllSignals === 'function') { + window.loadAllSignals(); + } + } catch (error) { + console.error('Error clearing signals:', error); + this.showNotification('Error clearing signals', 'error'); + } + } + // Signal name suggestions based on device type generateSignalNameSuggestions(deviceName, dataPoint) { const baseName = `${deviceName} ${dataPoint}`; @@ -462,9 +580,26 @@ class SimplifiedProtocolDiscovery { } // Global instance +// Expose to window for global access +window.SimplifiedProtocolDiscovery = SimplifiedProtocolDiscovery; + const simplifiedDiscovery = new SimplifiedProtocolDiscovery(); +window.simplifiedDiscovery = simplifiedDiscovery; // Initialize when DOM is loaded -document.addEventListener('DOMContentLoaded', function() { - simplifiedDiscovery.init(); -}); \ No newline at end of file +console.log('Discovery.js loaded - setting up DOMContentLoaded listener'); + +// Check if DOM is already loaded +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', function() { + console.log('DOMContentLoaded event fired - Initializing SimplifiedProtocolDiscovery...'); + window.simplifiedDiscovery.init(); + console.log('SimplifiedProtocolDiscovery initialized successfully'); + }); +} else { + console.log('DOM already loaded - Initializing SimplifiedProtocolDiscovery immediately...'); + window.simplifiedDiscovery.init(); + console.log('SimplifiedProtocolDiscovery initialized successfully'); +} + +console.log('=== DISCOVERY.JS FILE LOADED - END ==='); \ No newline at end of file diff --git a/templates/simplified_protocol_signals.html b/templates/simplified_protocol_signals.html index 3b3c217..d99132c 100644 --- a/templates/simplified_protocol_signals.html +++ b/templates/simplified_protocol_signals.html @@ -42,6 +42,23 @@ + +
+

Discovery Results

+

Use discovered signals to quickly add them to your protocol mapping:

+
+ + +
+
+ +
+
+

Popular Tags

@@ -136,7 +153,7 @@
- - + + \ No newline at end of file