Full PWA mobile version added, bug fixes on deployment status, navigation links added

This commit is contained in:
serversdwn
2025-12-11 04:03:23 +00:00
parent 195df967e4
commit 274e390c3e
26 changed files with 2393 additions and 34 deletions

View File

@@ -1,4 +1,5 @@
<div class="rounded-xl shadow-lg bg-white dark:bg-slate-800 overflow-hidden">
<!-- Desktop Table View -->
<div class="hidden md:block rounded-xl shadow-lg bg-white dark:bg-slate-800 overflow-hidden">
<table id="roster-table" class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-700">
<tr>
@@ -183,6 +184,160 @@
</div>
</div>
<!-- Mobile Card View -->
<div class="md:hidden space-y-3">
{% for unit in units %}
<div class="unit-card"
onclick="openUnitModal('{{ unit.id }}', '{{ unit.status }}', '{{ unit.age }}')"
data-unit-id="{{ unit.id }}"
data-status="{{ unit.status }}"
data-age="{{ unit.age }}">
<!-- Header: Status Dot + Unit ID + Status Badge -->
<div class="flex items-center justify-between mb-2">
<div class="flex items-center gap-2">
{% if unit.status == 'OK' %}
<span class="w-4 h-4 rounded-full bg-green-500" title="OK"></span>
{% elif unit.status == 'Pending' %}
<span class="w-4 h-4 rounded-full bg-yellow-500" title="Pending"></span>
{% elif unit.status == 'Missing' %}
<span class="w-4 h-4 rounded-full bg-red-500" title="Missing"></span>
{% else %}
<span class="w-4 h-4 rounded-full bg-gray-400" title="No Data"></span>
{% endif %}
<span class="font-bold text-lg text-seismo-orange dark:text-seismo-orange">{{ unit.id }}</span>
</div>
<span class="px-3 py-1 rounded-full text-xs font-medium
{% if unit.status == 'OK' %}bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300
{% elif unit.status == 'Pending' %}bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-300
{% elif unit.status == 'Missing' %}bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-300
{% else %}bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400
{% endif %}">
{% if unit.status in ['N/A', 'Unknown'] %}Benched{% else %}{{ unit.status }}{% endif %}
</span>
</div>
<!-- Type Badge -->
<div class="mb-2">
{% if unit.device_type == 'modem' %}
<span class="px-2 py-1 rounded-full bg-purple-100 dark:bg-purple-900/30 text-purple-800 dark:text-purple-300 text-xs font-medium">
Modem
</span>
{% else %}
<span class="px-2 py-1 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300 text-xs font-medium">
Seismograph
</span>
{% endif %}
</div>
<!-- Location (Tap to Navigate) -->
{% if unit.address %}
<div class="text-sm mb-1">
<a href="https://www.google.com/maps/search/?api=1&query={{ unit.address | urlencode }}"
target="_blank"
onclick="event.stopPropagation()"
class="flex items-center gap-1 text-seismo-orange hover:text-orange-600 dark:text-seismo-orange dark:hover:text-orange-400">
<svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
<span class="underline">{{ unit.address }}</span>
</a>
</div>
{% elif unit.coordinates %}
<div class="text-sm mb-1">
<a href="https://www.google.com/maps/search/?api=1&query={{ unit.coordinates | urlencode }}"
target="_blank"
onclick="event.stopPropagation()"
class="flex items-center gap-1 text-seismo-orange hover:text-orange-600 dark:text-seismo-orange dark:hover:text-orange-400">
<svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
<span class="font-mono underline">{{ unit.coordinates }}</span>
</a>
</div>
{% endif %}
<!-- Project ID -->
{% if unit.project_id %}
<div class="text-sm text-gray-600 dark:text-gray-400 mb-1">
🏗️ {{ unit.project_id }}
</div>
{% endif %}
<!-- Last Seen -->
<div class="text-sm text-gray-500 dark:text-gray-500 mt-2">
🕐 {{ unit.age }}
</div>
<!-- Deployed/Benched Indicator -->
<div class="mt-2">
{% if unit.deployed %}
<span class="text-xs text-blue-600 dark:text-blue-400">
⚡ Deployed
</span>
{% else %}
<span class="text-xs text-gray-500 dark:text-gray-500">
📦 Benched
</span>
{% endif %}
</div>
<!-- Tap Hint -->
<div class="text-xs text-gray-400 mt-2 text-center border-t border-gray-200 dark:border-gray-700 pt-2">
Tap for details
</div>
</div>
{% endfor %}
<!-- Mobile Last Updated -->
<div class="text-xs text-gray-500 dark:text-gray-400 text-center py-2">
Last updated: <span id="last-updated-mobile">{{ timestamp }}</span>
</div>
</div>
<!-- Unit Detail Modal -->
<div id="unitModal" class="unit-modal">
<!-- Backdrop -->
<div class="unit-modal-backdrop" onclick="closeUnitModal(event)"></div>
<!-- Modal Content -->
<div class="unit-modal-content">
<!-- Handle Bar (Mobile Only) -->
<div class="modal-handle"></div>
<!-- Header -->
<div class="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<h3 id="modalUnitId" class="text-xl font-bold text-gray-900 dark:text-white"></h3>
<button onclick="closeUnitModal(event)" data-close-modal class="w-10 h-10 flex items-center justify-center text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<!-- Content -->
<div id="modalContent" class="p-6">
<!-- Content will be populated by JavaScript -->
</div>
<!-- Actions -->
<div class="p-6 border-t border-gray-200 dark:border-gray-700 space-y-3">
<button id="modalEditBtn" class="w-full h-12 bg-seismo-orange hover:bg-orange-600 text-white rounded-lg font-medium transition-colors">
Edit Unit
</button>
<div class="grid grid-cols-2 gap-3">
<button id="modalDeployBtn" class="h-12 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
Deploy/Bench
</button>
<button id="modalDeleteBtn" class="h-12 border border-red-300 dark:border-red-600 text-red-600 dark:text-red-400 rounded-lg hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors">
Delete
</button>
</div>
</div>
</div>
</div>
<style>
.sort-indicator::after {
content: '⇅';
@@ -201,7 +356,14 @@
<script>
// Update timestamp
document.getElementById('last-updated').textContent = new Date().toLocaleTimeString();
const timestampElement = document.getElementById('last-updated');
if (timestampElement) {
timestampElement.textContent = new Date().toLocaleTimeString();
}
const timestampMobileElement = document.getElementById('last-updated-mobile');
if (timestampMobileElement) {
timestampMobileElement.textContent = new Date().toLocaleTimeString();
}
// Sorting state
let currentSort = { column: null, direction: 'asc' };