// Simplified Protocol Mapping Functions // Uses human-readable signal names and tags instead of complex IDs (function() { 'use strict'; // Check if global variables already exist before declaring if (typeof window.currentProtocolFilter === 'undefined') { window.currentProtocolFilter = 'all'; } if (typeof window.editingSignalId === 'undefined') { window.editingSignalId = null; } if (typeof window.allTags === 'undefined') { window.allTags = new Set(); } // Use window object variables directly to avoid redeclaration conflicts // Simplified Signal Management Functions async function loadAllSignals() { try { const response = await fetch('/api/v1/dashboard/protocol-signals'); const data = await response.json(); if (data.success) { displaySignals(data.signals); updateTagCloud(data.signals); } else { showSimplifiedAlert('Failed to load signals', 'error'); } } catch (error) { console.error('Error loading signals:', error); showSimplifiedAlert('Error loading signals', 'error'); } } function displaySignals(signals) { const tbody = document.getElementById('protocol-signals-body'); tbody.innerHTML = ''; if (signals.length === 0) { tbody.innerHTML = 'No protocol signals found'; return; } signals.forEach(signal => { const row = document.createElement('tr'); row.innerHTML = ` ${signal.signal_name} ${signal.protocol_type} ${signal.tags.map(tag => `${tag}`).join('')} ${signal.protocol_address} ${signal.db_source} ${signal.enabled ? 'Enabled' : 'Disabled'} `; tbody.appendChild(row); }); } function updateTagCloud(signals) { const tagCloud = document.getElementById('tag-cloud'); if (!tagCloud) return; // Collect all tags const tagCounts = {}; signals.forEach(signal => { signal.tags.forEach(tag => { tagCounts[tag] = (tagCounts[tag] || 0) + 1; }); }); // Create tag cloud tagCloud.innerHTML = ''; Object.entries(tagCounts).forEach(([tag, count]) => { const tagElement = document.createElement('span'); tagElement.className = 'tag-cloud-item'; tagElement.textContent = tag; tagElement.title = `${count} signal(s)`; tagElement.onclick = () => filterByTag(tag); tagCloud.appendChild(tagElement); }); } function filterByTag(tag) { const filterInput = document.getElementById('tag-filter'); if (filterInput) { filterInput.value = tag; applyFilters(); } } async function applyFilters() { const tagFilter = document.getElementById('tag-filter')?.value || ''; const protocolFilter = document.getElementById('protocol-filter')?.value || 'all'; const nameFilter = document.getElementById('name-filter')?.value || ''; const params = new URLSearchParams(); if (tagFilter) params.append('tags', tagFilter); if (protocolFilter !== 'all') params.append('protocol_type', protocolFilter); if (nameFilter) params.append('signal_name_contains', nameFilter); try { const response = await fetch(`/api/v1/dashboard/protocol-signals?${params}`); const data = await response.json(); if (data.success) { displaySignals(data.signals); } } catch (error) { console.error('Error applying filters:', error); } } // Modal Functions function showAddSignalModal() { window.editingSignalId = null; // Safely update modal elements if they exist const modalTitle = document.getElementById('modal-title'); if (modalTitle) { modalTitle.textContent = 'Add Protocol Signal'; } const signalForm = document.getElementById('signal-form'); if (signalForm) { signalForm.reset(); } const protocolAddressHelp = document.getElementById('protocol-address-help'); if (protocolAddressHelp) { protocolAddressHelp.textContent = ''; } const signalModal = document.getElementById('signal-modal'); if (signalModal) { signalModal.style.display = 'block'; } } function showEditSignalModal(signal) { window.editingSignalId = signal.signal_id; document.getElementById('modal-title').textContent = 'Edit Protocol Signal'; // Populate form document.getElementById('signal_name').value = signal.signal_name; document.getElementById('tags').value = signal.tags.join(', '); document.getElementById('protocol_type').value = signal.protocol_type; document.getElementById('protocol_address').value = signal.protocol_address; document.getElementById('db_source').value = signal.db_source; document.getElementById('preprocessing_enabled').checked = signal.preprocessing_enabled || false; updateProtocolFields(); document.getElementById('signal-modal').style.display = 'block'; } function closeSignalModal() { document.getElementById('signal-modal').style.display = 'none'; window.editingSignalId = null; } function updateProtocolFields() { const protocolType = document.getElementById('protocol_type').value; const helpText = document.getElementById('protocol-address-help'); switch (protocolType) { case 'modbus_tcp': case 'modbus_rtu': helpText.textContent = 'Modbus address format: 40001 (holding register), 30001 (input register), 10001 (coil), 00001 (discrete input)'; break; case 'opcua': helpText.textContent = 'OPC UA NodeId format: ns=2;s=MyVariable or ns=2;i=1234'; break; case 'rest_api': helpText.textContent = 'REST API endpoint format: /api/v1/data/endpoint'; break; default: helpText.textContent = ''; } } // Form Submission async function saveSignal(event) { event.preventDefault(); const formData = getSignalFormData(); try { let response; if (window.editingSignalId) { response = await fetch(`/api/v1/dashboard/protocol-signals/${window.editingSignalId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }); } else { response = await fetch('/api/v1/dashboard/protocol-signals', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }); } const data = await response.json(); if (data.success) { showSimplifiedAlert(`Protocol signal ${window.editingSignalId ? 'updated' : 'created'} successfully!`, 'success'); closeSignalModal(); loadAllSignals(); } else { showSimplifiedAlert(`Failed to save signal: ${data.detail || 'Unknown error'}`, 'error'); } } catch (error) { console.error('Error saving signal:', error); showSimplifiedAlert('Error saving signal', 'error'); } } function getSignalFormData() { const tagsInput = document.getElementById('tags').value; const tags = tagsInput.split(',').map(tag => tag.trim()).filter(tag => tag); return { signal_name: document.getElementById('signal_name').value, tags: tags, protocol_type: document.getElementById('protocol_type').value, protocol_address: document.getElementById('protocol_address').value, db_source: document.getElementById('db_source').value, preprocessing_enabled: document.getElementById('preprocessing_enabled').checked }; } // Signal Management async function editSignal(signalId) { try { const response = await fetch(`/api/v1/dashboard/protocol-signals/${signalId}`); const data = await response.json(); if (data.success) { showEditSignalModal(data.signal); } else { showSimplifiedAlert('Signal not found', 'error'); } } catch (error) { console.error('Error loading signal:', error); showSimplifiedAlert('Error loading signal', 'error'); } } async function deleteSignal(signalId) { if (!confirm('Are you sure you want to delete this signal?')) { return; } try { const response = await fetch(`/api/v1/dashboard/protocol-signals/${signalId}`, { method: 'DELETE' }); const data = await response.json(); if (data.success) { showSimplifiedAlert('Signal deleted successfully!', 'success'); loadAllSignals(); } else { showSimplifiedAlert(`Failed to delete signal: ${data.detail || 'Unknown error'}`, 'error'); } } catch (error) { console.error('Error deleting signal:', error); showSimplifiedAlert('Error deleting signal', 'error'); } } // Discovery Integration function autoPopulateSignalForm(discoveryData) { console.log('Auto-populating signal form with:', discoveryData); // First, open the "Add New Signal" modal showAddSignalModal(); // Use a simpler approach - just populate after a short delay // This avoids complex timeout logic that can be unreliable setTimeout(() => { const modal = document.getElementById('signal-modal'); if (modal && modal.style.display !== 'none') { console.log('Modal is visible, populating fields...'); populateModalFields(discoveryData); } else { console.log('Modal not immediately visible, trying again...'); // Try one more time after another short delay setTimeout(() => { populateModalFields(discoveryData); }, 100); } }, 100); } function populateModalFields(discoveryData) { console.log('Populating modal fields with:', discoveryData); // Populate signal name const signalNameField = document.getElementById('signal_name'); if (signalNameField && discoveryData.signal_name) { signalNameField.value = discoveryData.signal_name; console.log('✓ Set signal_name to:', discoveryData.signal_name); } // Populate tags const tagsField = document.getElementById('tags'); if (tagsField && discoveryData.tags) { tagsField.value = discoveryData.tags.join(', '); console.log('✓ Set tags to:', discoveryData.tags); } // Populate protocol type const protocolTypeField = document.getElementById('protocol_type'); if (protocolTypeField && discoveryData.protocol_type) { protocolTypeField.value = discoveryData.protocol_type; console.log('✓ Set protocol_type to:', discoveryData.protocol_type); // Trigger protocol field updates protocolTypeField.dispatchEvent(new Event('change')); } // Populate protocol address const protocolAddressField = document.getElementById('protocol_address'); if (protocolAddressField && discoveryData.protocol_address) { protocolAddressField.value = discoveryData.protocol_address; console.log('✓ Set protocol_address to:', discoveryData.protocol_address); } // Populate database source const dbSourceField = document.getElementById('db_source'); if (dbSourceField && discoveryData.db_source) { dbSourceField.value = discoveryData.db_source; console.log('✓ Set db_source to:', discoveryData.db_source); } // Show success message showSimplifiedAlert(`Signal form populated with discovery data. Please review and save.`, 'success'); } // Utility Functions function showSimplifiedAlert(message, type = 'info') { const alertsDiv = document.getElementById('simplified-alerts'); // Only proceed if the alerts container exists if (!alertsDiv) { console.log(`Alert (${type}): ${message}`); return; } const alertDiv = document.createElement('div'); alertDiv.className = `alert ${type === 'error' ? 'error' : 'success'}`; alertDiv.textContent = message; alertsDiv.innerHTML = ''; alertsDiv.appendChild(alertDiv); // Auto-remove after 5 seconds setTimeout(() => { if (alertDiv.parentNode) { alertDiv.remove(); } }, 5000); } // Initialize document.addEventListener('DOMContentLoaded', function() { const signalForm = document.getElementById('signal-form'); if (signalForm) { signalForm.addEventListener('submit', saveSignal); } // Load initial data loadAllSignals(); }); // Expose functions to window for discovery integration window.autoPopulateSignalForm = autoPopulateSignalForm; window.showAddSignalModal = showAddSignalModal; window.applyFilters = applyFilters; window.closeSignalModal = closeSignalModal; })();