Refactor: Adding a form for gateway values

This commit is contained in:
Halcy0nic
2024-10-28 10:02:53 -06:00
parent 00e2f670fe
commit 789f801102
+204 -67
View File
@@ -202,7 +202,7 @@
})
.catch(error => {
console.error('Error:', error);
Swal.fire('Oops!', 'Something went wrong. The port might already be in use.', 'error');
Swal.fire('Oops!', 'Something went wrong.', 'error');
});
}
});
@@ -398,7 +398,7 @@
})
.catch(error => {
console.error('Error:', error);
Swal.fire('Oops!', 'Something went wrong. The port might already be in use.', 'error');
Swal.fire('Oops!', 'Something went wrong.', 'error');
});
}
});
@@ -594,7 +594,7 @@
})
.catch(error => {
console.error('Error:', error);
Swal.fire('Oops!', 'Something went wrong. The port might already be in use.', 'error');
Swal.fire('Oops!', 'Something went wrong.', 'error');
});
}
});
@@ -682,75 +682,212 @@
<br>
<br>
<div class="config-section">
<section class="config-section">
<h4>Configure LoRaWAN Gateways</h4>
<p>
The <strong>'Configure LoRaWAN Gateway'</strong> section allows you to set up to ten Dragino LPS8N LoRaWAN gateways.
</p>
<ul>
<li>Click the "Configure Gateway" button to start configuring each gateway's IP address.</li>
<li>Skip configuring a gateway or disconnect an existing one by leaving the input field empty.</li>
<li>All entered IP addresses are validated for correct formatting.</li>
<li>Once configured, the application automatically retrieves and stores LoRaWAN traffic from each active gateway.</li>
<li>Access and analyze stored traffic in 'survey mode'.</li>
</ul>
</div>
<br>
<button class="btn btn-primary" id="configureGatewayBtn">Configure LoRaWAN Gateway</button>
<div class="description">
<p>
The <strong>Configure LoRaWAN Gateway</strong> section allows you to set up to ten Dragino LPS8N LoRaWAN gateways.
</p>
<ul>
<li>Enter the IP address for each gateway you want to configure.</li>
<li>Leave the input field empty to keep the current IP or disconnect an existing one.</li>
<li>All entered IP addresses are validated for correct formatting.</li>
<li>Once configured, the application automatically retrieves and stores LoRaWAN traffic from each active gateway.</li>
<li>Access and analyze stored traffic in 'survey mode'.</li>
</ul>
<p class="note"><em>Empty values will be ignored, and the Gateway IP address will remain unchanged</em></p>
</div>
<form id="gatewayForm" class="mt-3">
<div id="gatewayInputs"></div>
<button type="button" class="btn btn-primary mt-3" onclick="submitGatewayForm()">Update Gateways</button>
</form>
</section>
<style>
.gateway-container {
position: relative;
}
.status-indicator {
transition: background-color 0.3s ease;
box-shadow: 0 0 5px rgba(0,0,0,0.2);
}
.status-indicator[title] {
cursor: pointer;
}
.note {
font-style: italic;
color: #666;
margin-top: 1rem;
}
.config-section {
padding: 20px;
background-color: #f8f9fa;
border-radius: 5px;
margin-bottom: 20px;
}
.form-control {
margin-bottom: 0 !important;
}
</style>
<script>
document.getElementById('configureGatewayBtn').addEventListener('click', function() {
let gatewayIPs = {};
const ipPrompt = (title) => {
return Swal.fire({
title: title,
input: 'text',
inputPlaceholder: 'Leave empty to keep current IP',
inputValidator: (value) => {
if (value && !value.match(/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/)) {
return 'Please enter a valid IP address or leave it empty';
}
class GatewayManager {
constructor() {
this.gatewayIPs = Object.fromEntries(
Array.from({length: 10}, (_, i) => [`gateway${i + 1}`, ''])
);
this.init();
}
createGatewayInputs() {
const container = document.getElementById('gatewayInputs');
container.innerHTML = Object.keys(this.gatewayIPs)
.map((key, index) => `
<div class="gateway-container d-flex align-items-center mb-2">
<input type="text"
id="${key}"
class="form-control"
placeholder="Gateway ${index + 1} IP Address"
value="${this.gatewayIPs[key]}">
<div id="${key}-status" class="status-indicator ml-2"
style="width: 12px; height: 12px; border-radius: 50%; margin-left: 10px;">
</div>
</div>
`).join('');
}
async checkGatewayStatus(gatewayIP) {
if (!gatewayIP) return false;
try {
const response = await fetch(`http://${gatewayIP}:8000/cgi-bin/log-traffic.has`, {
method: 'HEAD',
mode: 'no-cors',
timeout: 5000
});
return true;
} catch (error) {
return false;
}
}
updateStatusIndicator(gatewayKey, isOnline) {
const statusElement = document.getElementById(`${gatewayKey}-status`);
if (statusElement) {
statusElement.style.backgroundColor = isOnline ? '#4BD28F' : '#FF4D4D';
statusElement.title = isOnline ? 'Gateway Online' : 'Gateway Offline';
}
}
async checkAllGateways() {
for (const [key, ip] of Object.entries(this.gatewayIPs)) {
if (ip) {
const isOnline = await this.checkGatewayStatus(ip);
this.updateStatusIndicator(key, isOnline);
} else {
this.updateStatusIndicator(key, false);
}
}
}
validateIPAddress(ip) {
if (!ip) return true;
const regex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
if (!regex.test(ip)) return false;
return ip.split('.').every(octet => {
const num = parseInt(octet);
return num >= 0 && num <= 255;
});
}
async submitGatewayForm() {
const updatedIPs = {};
let hasValidationError = false;
Object.keys(this.gatewayIPs).forEach(key => {
const input = document.getElementById(key);
const value = input.value.trim();
if (value && !this.validateIPAddress(value)) {
hasValidationError = true;
input.classList.add('is-invalid');
Swal.fire('Error', `Invalid IP address for ${key}`, 'error');
return;
}
if (value) {
updatedIPs[key] = value;
input.classList.remove('is-invalid');
}
});
if (hasValidationError) return;
if (Object.keys(updatedIPs).length === 0) {
Swal.fire('No Changes', 'No IP addresses were changed.', 'info');
return;
}
try {
const response = await fetch('/set_gateways', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams(updatedIPs)
});
if (!response.ok) throw new Error('Network response was not ok');
await response.json();
Swal.fire('Success', 'Gateway IPs updated successfully', 'success');
this.gatewayIPs = {...this.gatewayIPs, ...updatedIPs};
// Check status of all gateways after successful update
await this.checkAllGateways();
} catch (error) {
console.error('Error:', error);
Swal.fire('Error', 'There was an issue updating the Gateway IPs', 'error');
}
}
init() {
this.createGatewayInputs();
document.querySelector('#gatewayForm button')
.addEventListener('click', () => this.submitGatewayForm());
// Add input event listeners for real-time status checking
Object.keys(this.gatewayIPs).forEach(key => {
const input = document.getElementById(key);
input.addEventListener('change', async () => {
const ip = input.value.trim();
if (ip) {
const isOnline = await this.checkGatewayStatus(ip);
this.updateStatusIndicator(key, isOnline);
} else {
this.updateStatusIndicator(key, false);
}
});
};
const promptGateways = async () => {
for (let i = 1; i <= 10; i++) {
const result = await ipPrompt(`Enter Gateway ${i} IP Address`);
if (result.value) gatewayIPs[`gateway${i}`] = result.value;
}
// Now send the IPs to the server only if they are not undefined
let queryString = Object.keys(gatewayIPs).reduce((acc, key) => {
if (gatewayIPs[key] !== undefined) {
acc.push(`${key}=${encodeURIComponent(gatewayIPs[key])}`);
}
return acc;
}, []).join('&');
if (queryString) {
fetch('/set_gateways', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: queryString
})
.then(response => response.json())
.then(data => Swal.fire('Success', 'Gateway IPs updated successfully', 'success'))
.catch(error => Swal.fire('Error', 'There was an issue updating the Gateway IPs', 'error'));
} else {
Swal.fire('No Changes', 'No IP addresses were changed.', 'info');
}
};
promptGateways();
});
</script>
});
// Initial status check
this.checkAllGateways();
}
}
// Initialize the gateway manager
document.addEventListener('DOMContentLoaded', () => {
new GatewayManager();
});
</script>
</div>
</section>
</section>
</div>