298 lines
11 KiB
JavaScript
298 lines
11 KiB
JavaScript
// Protocol Mapping Functions
|
|
let currentProtocolFilter = 'all';
|
|
let editingMappingId = null;
|
|
|
|
function selectProtocol(protocol) {
|
|
currentProtocolFilter = protocol;
|
|
|
|
// Update active button
|
|
document.querySelectorAll('.protocol-btn').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
});
|
|
event.target.classList.add('active');
|
|
|
|
// Reload mappings with filter
|
|
loadProtocolMappings();
|
|
}
|
|
|
|
async function loadProtocolMappings() {
|
|
try {
|
|
const params = new URLSearchParams();
|
|
if (currentProtocolFilter !== 'all') {
|
|
params.append('protocol_type', currentProtocolFilter);
|
|
}
|
|
|
|
const response = await fetch(`/api/v1/dashboard/protocol-mappings?${params}`);
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
displayProtocolMappings(data.mappings);
|
|
} else {
|
|
showProtocolMappingAlert('Failed to load protocol mappings', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading protocol mappings:', error);
|
|
showProtocolMappingAlert('Error loading protocol mappings', 'error');
|
|
}
|
|
}
|
|
|
|
function displayProtocolMappings(mappings) {
|
|
const tbody = document.getElementById('protocol-mappings-body');
|
|
tbody.innerHTML = '';
|
|
|
|
if (mappings.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="8" style="text-align: center; padding: 20px;">No protocol mappings found</td></tr>';
|
|
return;
|
|
}
|
|
|
|
mappings.forEach(mapping => {
|
|
const row = document.createElement('tr');
|
|
row.innerHTML = `
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${mapping.id}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${mapping.protocol_type}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${mapping.station_id || '-'}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${mapping.pump_id || '-'}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${mapping.data_type}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${mapping.protocol_address}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">${mapping.db_source}</td>
|
|
<td style="padding: 10px; border: 1px solid #ddd;">
|
|
<button onclick="editMapping('${mapping.id}')" style="background: #007acc; margin-right: 5px;">Edit</button>
|
|
<button onclick="deleteMapping('${mapping.id}')" style="background: #dc3545;">Delete</button>
|
|
</td>
|
|
`;
|
|
tbody.appendChild(row);
|
|
});
|
|
}
|
|
|
|
function showAddMappingModal() {
|
|
editingMappingId = null;
|
|
document.getElementById('modal-title').textContent = 'Add Protocol Mapping';
|
|
document.getElementById('mapping-form').reset();
|
|
document.getElementById('protocol_address_help').textContent = '';
|
|
document.getElementById('mapping-modal').style.display = 'block';
|
|
}
|
|
|
|
function showEditMappingModal(mapping) {
|
|
editingMappingId = mapping.id;
|
|
document.getElementById('modal-title').textContent = 'Edit Protocol Mapping';
|
|
document.getElementById('mapping_id').value = mapping.id;
|
|
document.getElementById('protocol_type').value = mapping.protocol_type;
|
|
document.getElementById('station_id').value = mapping.station_id || '';
|
|
document.getElementById('pump_id').value = mapping.pump_id || '';
|
|
document.getElementById('data_type').value = mapping.data_type;
|
|
document.getElementById('protocol_address').value = mapping.protocol_address;
|
|
document.getElementById('db_source').value = mapping.db_source;
|
|
|
|
updateProtocolFields();
|
|
document.getElementById('mapping-modal').style.display = 'block';
|
|
}
|
|
|
|
function closeMappingModal() {
|
|
document.getElementById('mapping-modal').style.display = 'none';
|
|
editingMappingId = null;
|
|
}
|
|
|
|
function updateProtocolFields() {
|
|
const protocolType = document.getElementById('protocol_type').value;
|
|
const helpText = document.getElementById('protocol_address_help');
|
|
|
|
switch (protocolType) {
|
|
case 'modbus_tcp':
|
|
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 'modbus_rtu':
|
|
helpText.textContent = 'Modbus RTU address format: 40001 (holding register), 30001 (input register), 10001 (coil), 00001 (discrete input)';
|
|
break;
|
|
case 'rest_api':
|
|
helpText.textContent = 'REST API endpoint format: /api/v1/data/endpoint';
|
|
break;
|
|
default:
|
|
helpText.textContent = '';
|
|
}
|
|
}
|
|
|
|
async function validateMapping() {
|
|
const formData = getMappingFormData();
|
|
|
|
try {
|
|
const response = await fetch(`/api/v1/dashboard/protocol-mappings/${editingMappingId || 'new'}/validate`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(formData)
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
if (data.valid) {
|
|
showProtocolMappingAlert('Mapping validation successful!', 'success');
|
|
} else {
|
|
showProtocolMappingAlert(`Validation failed: ${data.errors.join(', ')}`, 'error');
|
|
}
|
|
} else {
|
|
showProtocolMappingAlert('Validation error', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error validating mapping:', error);
|
|
showProtocolMappingAlert('Error validating mapping', 'error');
|
|
}
|
|
}
|
|
|
|
async function saveMapping(event) {
|
|
event.preventDefault();
|
|
|
|
const formData = getMappingFormData();
|
|
|
|
try {
|
|
let response;
|
|
if (editingMappingId) {
|
|
response = await fetch(`/api/v1/dashboard/protocol-mappings/${editingMappingId}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(formData)
|
|
});
|
|
} else {
|
|
response = await fetch('/api/v1/dashboard/protocol-mappings', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(formData)
|
|
});
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showProtocolMappingAlert(`Protocol mapping ${editingMappingId ? 'updated' : 'created'} successfully!`, 'success');
|
|
closeMappingModal();
|
|
loadProtocolMappings();
|
|
} else {
|
|
showProtocolMappingAlert(`Failed to save mapping: ${data.detail || 'Unknown error'}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error saving mapping:', error);
|
|
showProtocolMappingAlert('Error saving mapping', 'error');
|
|
}
|
|
}
|
|
|
|
function getMappingFormData() {
|
|
return {
|
|
protocol_type: document.getElementById('protocol_type').value,
|
|
station_id: document.getElementById('station_id').value,
|
|
pump_id: document.getElementById('pump_id').value,
|
|
data_type: document.getElementById('data_type').value,
|
|
protocol_address: document.getElementById('protocol_address').value,
|
|
db_source: document.getElementById('db_source').value
|
|
};
|
|
}
|
|
|
|
async function editMapping(mappingId) {
|
|
try {
|
|
const response = await fetch(`/api/v1/dashboard/protocol-mappings?protocol_type=all`);
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
const mapping = data.mappings.find(m => m.id === mappingId);
|
|
if (mapping) {
|
|
showEditMappingModal(mapping);
|
|
} else {
|
|
showProtocolMappingAlert('Mapping not found', 'error');
|
|
}
|
|
} else {
|
|
showProtocolMappingAlert('Failed to load mapping', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading mapping:', error);
|
|
showProtocolMappingAlert('Error loading mapping', 'error');
|
|
}
|
|
}
|
|
|
|
async function deleteMapping(mappingId) {
|
|
if (!confirm(`Are you sure you want to delete mapping ${mappingId}?`)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/api/v1/dashboard/protocol-mappings/${mappingId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showProtocolMappingAlert('Mapping deleted successfully!', 'success');
|
|
loadProtocolMappings();
|
|
} else {
|
|
showProtocolMappingAlert(`Failed to delete mapping: ${data.detail || 'Unknown error'}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error deleting mapping:', error);
|
|
showProtocolMappingAlert('Error deleting mapping', 'error');
|
|
}
|
|
}
|
|
|
|
function showProtocolMappingAlert(message, type) {
|
|
const alertsDiv = document.getElementById('protocol-mapping-alerts');
|
|
const alertDiv = document.createElement('div');
|
|
alertDiv.className = `alert ${type === 'error' ? 'error' : 'success'}`;
|
|
alertDiv.textContent = message;
|
|
|
|
alertsDiv.innerHTML = '';
|
|
alertsDiv.appendChild(alertDiv);
|
|
|
|
setTimeout(() => {
|
|
alertDiv.remove();
|
|
}, 5000);
|
|
}
|
|
|
|
async function exportProtocolMappings() {
|
|
try {
|
|
const response = await fetch('/api/v1/dashboard/protocol-mappings?protocol_type=all');
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
const csvContent = convertToCSV(data.mappings);
|
|
downloadCSV(csvContent, 'protocol_mappings.csv');
|
|
} else {
|
|
showProtocolMappingAlert('Failed to export mappings', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error exporting mappings:', error);
|
|
showProtocolMappingAlert('Error exporting mappings', 'error');
|
|
}
|
|
}
|
|
|
|
function convertToCSV(mappings) {
|
|
const headers = ['ID', 'Protocol', 'Station', 'Pump', 'Data Type', 'Protocol Address', 'Database Source'];
|
|
const rows = mappings.map(mapping => [
|
|
mapping.id,
|
|
mapping.protocol_type,
|
|
mapping.station_id || '',
|
|
mapping.pump_id || '',
|
|
mapping.data_type,
|
|
mapping.protocol_address,
|
|
mapping.db_source
|
|
]);
|
|
|
|
return [headers, ...rows].map(row => row.map(field => `"${field}"`).join(',')).join('\n');
|
|
}
|
|
|
|
function downloadCSV(content, filename) {
|
|
const blob = new Blob([content], { type: 'text/csv' });
|
|
const url = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename;
|
|
a.click();
|
|
window.URL.revokeObjectURL(url);
|
|
}
|
|
|
|
// Initialize form submission handler
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const mappingForm = document.getElementById('mapping-form');
|
|
if (mappingForm) {
|
|
mappingForm.addEventListener('submit', saveMapping);
|
|
}
|
|
}); |