410 lines
14 KiB
JavaScript
410 lines
14 KiB
JavaScript
// 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 = '<tr><td colspan="7" style="text-align: center; padding: 20px;">No protocol signals found</td></tr>';
|
|
return;
|
|
}
|
|
|
|
signals.forEach(signal => {
|
|
const row = document.createElement('tr');
|
|
row.innerHTML = `
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${signal.signal_name}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${signal.protocol_type}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">
|
|
${signal.tags.map(tag => `<span class="tag-badge">${tag}</span>`).join('')}
|
|
</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${signal.protocol_address}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${signal.db_source}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">
|
|
<span class="status-badge ${signal.enabled ? 'enabled' : 'disabled'}">
|
|
${signal.enabled ? 'Enabled' : 'Disabled'}
|
|
</span>
|
|
</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">
|
|
<button onclick="editSignal('${signal.signal_id}')" class="btn-edit">Edit</button>
|
|
<button onclick="deleteSignal('${signal.signal_id}')" class="btn-delete">Delete</button>
|
|
</td>
|
|
`;
|
|
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() {
|
|
console.log('showAddSignalModal called');
|
|
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');
|
|
console.log('Modal element found:', signalModal);
|
|
if (signalModal) {
|
|
console.log('Setting modal display to block');
|
|
signalModal.style.display = 'block';
|
|
console.log('Modal display after setting:', signalModal.style.display);
|
|
} else {
|
|
console.error('signal-modal element not found!');
|
|
}
|
|
}
|
|
|
|
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();
|
|
|
|
// Wait for modal to be fully loaded and visible
|
|
const waitForModal = setInterval(() => {
|
|
const modal = document.getElementById('signal-modal');
|
|
const isModalVisible = modal && modal.style.display !== 'none';
|
|
|
|
if (isModalVisible) {
|
|
clearInterval(waitForModal);
|
|
console.log('Modal is visible, populating fields...');
|
|
populateModalFields(discoveryData);
|
|
}
|
|
}, 50);
|
|
|
|
// Timeout after 3 seconds (increased from 2)
|
|
setTimeout(() => {
|
|
clearInterval(waitForModal);
|
|
const modal = document.getElementById('signal-modal');
|
|
if (modal && modal.style.display !== 'none') {
|
|
console.log('Modal opened within timeout, populating fields...');
|
|
populateModalFields(discoveryData);
|
|
} else {
|
|
console.error('Modal did not open within timeout period');
|
|
console.log('Modal element:', modal);
|
|
console.log('Modal display style:', modal ? modal.style.display : 'no modal found');
|
|
showSimplifiedAlert('Could not open signal form. Please try opening it manually.', 'error');
|
|
}
|
|
}, 3000);
|
|
}
|
|
|
|
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;
|
|
})(); |