Files
terra-view/templates/modems.html
serversdwn 05482bd903 Add:
- pair_devices.html template for device pairing interface
- SLMM device control lock prevents flooding nl43.
Fix:
- Polling intervals for SLMM.
- modem view now list
- device pairing much improved.
- various other tweaks through out UI.
- SLMM Scheduled downloads fixed.
2026-01-29 07:50:13 +00:00

103 lines
4.4 KiB
HTML

{% extends "base.html" %}
{% block title %}Field Modems - Terra-View{% endblock %}
{% block content %}
<div class="mb-8">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white flex items-center">
<svg class="w-8 h-8 mr-3 text-seismo-orange" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0"></path>
</svg>
Field Modems
</h1>
<p class="text-gray-600 dark:text-gray-400 mt-1">Manage network connectivity devices for field equipment</p>
</div>
<!-- Summary Stats -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8"
hx-get="/api/modem-dashboard/stats"
hx-trigger="load, every 30s"
hx-swap="innerHTML">
<!-- Stats will be loaded here -->
<div class="animate-pulse bg-gray-200 dark:bg-gray-700 h-24 rounded-xl"></div>
<div class="animate-pulse bg-gray-200 dark:bg-gray-700 h-24 rounded-xl"></div>
<div class="animate-pulse bg-gray-200 dark:bg-gray-700 h-24 rounded-xl"></div>
<div class="animate-pulse bg-gray-200 dark:bg-gray-700 h-24 rounded-xl"></div>
</div>
<!-- Modem List -->
<div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-6">
<div class="flex items-center justify-between mb-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">All Modems</h2>
<div class="flex items-center gap-4">
<!-- Search -->
<div class="relative">
<input type="text"
id="modem-search"
placeholder="Search modems..."
class="pl-9 pr-4 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange focus:border-transparent"
hx-get="/api/modem-dashboard/units"
hx-trigger="keyup changed delay:300ms"
hx-target="#modem-list"
hx-include="[name='search']"
name="search">
<svg class="w-4 h-4 absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</div>
<a href="/roster?device_type=modem" class="text-sm text-seismo-orange hover:underline">
Add modem in roster
</a>
</div>
</div>
<div id="modem-list"
hx-get="/api/modem-dashboard/units"
hx-trigger="load, every 30s"
hx-swap="innerHTML">
<p class="text-gray-500 dark:text-gray-400">Loading modems...</p>
</div>
</div>
<script>
// Ping a modem and show result
async function pingModem(modemId) {
const btn = document.getElementById(`ping-btn-${modemId}`);
const resultDiv = document.getElementById(`ping-result-${modemId}`);
// Show loading state
const originalText = btn.textContent;
btn.textContent = 'Pinging...';
btn.disabled = true;
resultDiv.classList.remove('hidden');
resultDiv.className = 'mt-2 text-xs text-gray-500';
resultDiv.textContent = 'Testing connection...';
try {
const response = await fetch(`/api/modem-dashboard/${modemId}/ping`);
const data = await response.json();
if (data.status === 'success') {
resultDiv.className = 'mt-2 text-xs text-green-600 dark:text-green-400';
resultDiv.innerHTML = `<span class="inline-block w-2 h-2 bg-green-500 rounded-full mr-1"></span>Online (${data.response_time_ms}ms)`;
} else {
resultDiv.className = 'mt-2 text-xs text-red-600 dark:text-red-400';
resultDiv.innerHTML = `<span class="inline-block w-2 h-2 bg-red-500 rounded-full mr-1"></span>${data.detail || 'Offline'}`;
}
} catch (error) {
resultDiv.className = 'mt-2 text-xs text-red-600 dark:text-red-400';
resultDiv.textContent = 'Error: ' + error.message;
}
// Restore button
btn.textContent = originalText;
btn.disabled = false;
// Hide result after 10 seconds
setTimeout(() => {
resultDiv.classList.add('hidden');
}, 10000);
}
</script>
{% endblock %}