Compare commits
4 Commits
d78bafb76e
...
f296806fd1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f296806fd1 | ||
|
|
24da5ab79f | ||
|
|
305540f564 | ||
|
|
639b485c28 |
@@ -604,8 +604,9 @@ function updateFleetMapFiltered(allUnits) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fit bounds if we have markers
|
// Only fit bounds on initial load, not on subsequent updates
|
||||||
if (bounds.length > 0) {
|
// This preserves the user's current map view when auto-refreshing
|
||||||
|
if (bounds.length > 0 && !fleetMapInitialized) {
|
||||||
const padding = window.innerWidth < 768 ? [20, 20] : [50, 50];
|
const padding = window.innerWidth < 768 ? [20, 20] : [50, 50];
|
||||||
fleetMap.fitBounds(bounds, { padding: padding });
|
fleetMap.fitBounds(bounds, { padding: padding });
|
||||||
fleetMapInitialized = true;
|
fleetMapInitialized = true;
|
||||||
|
|||||||
@@ -60,7 +60,9 @@
|
|||||||
data-note="{{ unit.note if unit.note else '' }}">
|
data-note="{{ unit.note if unit.note else '' }}">
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
{% if unit.status == 'OK' %}
|
{% if not unit.deployed %}
|
||||||
|
<span class="w-3 h-3 rounded-full bg-gray-400 dark:bg-gray-500" title="Benched"></span>
|
||||||
|
{% elif unit.status == 'OK' %}
|
||||||
<span class="w-3 h-3 rounded-full bg-green-500" title="OK"></span>
|
<span class="w-3 h-3 rounded-full bg-green-500" title="OK"></span>
|
||||||
{% elif unit.status == 'Pending' %}
|
{% elif unit.status == 'Pending' %}
|
||||||
<span class="w-3 h-3 rounded-full bg-yellow-500" title="Pending"></span>
|
<span class="w-3 h-3 rounded-full bg-yellow-500" title="Pending"></span>
|
||||||
@@ -208,7 +210,9 @@
|
|||||||
<!-- Header: Status Dot + Unit ID + Status Badge -->
|
<!-- Header: Status Dot + Unit ID + Status Badge -->
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
{% if unit.status == 'OK' %}
|
{% if not unit.deployed %}
|
||||||
|
<span class="w-4 h-4 rounded-full bg-gray-400 dark:bg-gray-500" title="Benched"></span>
|
||||||
|
{% elif unit.status == 'OK' %}
|
||||||
<span class="w-4 h-4 rounded-full bg-green-500" title="OK"></span>
|
<span class="w-4 h-4 rounded-full bg-green-500" title="OK"></span>
|
||||||
{% elif unit.status == 'Pending' %}
|
{% elif unit.status == 'Pending' %}
|
||||||
<span class="w-4 h-4 rounded-full bg-yellow-500" title="Pending"></span>
|
<span class="w-4 h-4 rounded-full bg-yellow-500" title="Pending"></span>
|
||||||
@@ -235,6 +239,10 @@
|
|||||||
<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">
|
<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
|
Modem
|
||||||
</span>
|
</span>
|
||||||
|
{% elif unit.device_type == 'slm' %}
|
||||||
|
<span class="px-2 py-1 rounded-full bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-300 text-xs font-medium">
|
||||||
|
SLM
|
||||||
|
</span>
|
||||||
{% else %}
|
{% 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">
|
<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
|
Seismograph
|
||||||
|
|||||||
188
templates/partials/projects/file_list.html
Normal file
188
templates/partials/projects/file_list.html
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
<!-- File List for NRL - Simple flat list of files with session info -->
|
||||||
|
{% if files %}
|
||||||
|
<div class="divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
|
{% for file_data in files %}
|
||||||
|
{% set file = file_data.file %}
|
||||||
|
{% set session = file_data.session %}
|
||||||
|
|
||||||
|
<div class="flex items-center gap-3 px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors group">
|
||||||
|
<!-- File Icon -->
|
||||||
|
{% if file.file_type == 'audio' %}
|
||||||
|
<svg class="w-6 h-6 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"></path>
|
||||||
|
</svg>
|
||||||
|
{% elif file.file_type == 'archive' %}
|
||||||
|
<svg class="w-6 h-6 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"></path>
|
||||||
|
</svg>
|
||||||
|
{% elif file.file_type == 'log' %}
|
||||||
|
<svg class="w-6 h-6 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||||
|
</svg>
|
||||||
|
{% elif file.file_type == 'image' %}
|
||||||
|
<svg class="w-6 h-6 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||||
|
</svg>
|
||||||
|
{% elif file.file_type == 'measurement' %}
|
||||||
|
<svg class="w-6 h-6 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
||||||
|
</svg>
|
||||||
|
{% else %}
|
||||||
|
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||||
|
</svg>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- File Info -->
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="font-medium text-gray-900 dark:text-white truncate">
|
||||||
|
{{ file.file_path.split('/')[-1] if file.file_path else 'Unknown' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
||||||
|
<!-- File Type Badge -->
|
||||||
|
<span class="px-1.5 py-0.5 rounded font-medium
|
||||||
|
{% if file.file_type == 'audio' %}bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300
|
||||||
|
{% elif file.file_type == 'data' %}bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300
|
||||||
|
{% elif file.file_type == 'measurement' %}bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300
|
||||||
|
{% elif file.file_type == 'log' %}bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300
|
||||||
|
{% elif file.file_type == 'archive' %}bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300
|
||||||
|
{% elif file.file_type == 'image' %}bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-300
|
||||||
|
{% else %}bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300{% endif %}">
|
||||||
|
{{ file.file_type or 'unknown' }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{# Leq vs Lp badge for RND files #}
|
||||||
|
{% if file.file_path and '_Leq_' in file.file_path %}
|
||||||
|
<span class="px-1.5 py-0.5 rounded font-medium bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300">
|
||||||
|
Leq (15-min avg)
|
||||||
|
</span>
|
||||||
|
{% elif file.file_path and '_Lp' in file.file_path and file.file_path.endswith('.rnd') %}
|
||||||
|
<span class="px-1.5 py-0.5 rounded font-medium bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300">
|
||||||
|
Lp (instant)
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- File Size -->
|
||||||
|
<span class="mx-1">•</span>
|
||||||
|
{% if file.file_size_bytes %}
|
||||||
|
{% if file.file_size_bytes < 1024 %}
|
||||||
|
{{ file.file_size_bytes }} B
|
||||||
|
{% elif file.file_size_bytes < 1048576 %}
|
||||||
|
{{ "%.1f"|format(file.file_size_bytes / 1024) }} KB
|
||||||
|
{% elif file.file_size_bytes < 1073741824 %}
|
||||||
|
{{ "%.1f"|format(file.file_size_bytes / 1048576) }} MB
|
||||||
|
{% else %}
|
||||||
|
{{ "%.2f"|format(file.file_size_bytes / 1073741824) }} GB
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
Unknown size
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Session Info -->
|
||||||
|
{% if session %}
|
||||||
|
<span class="mx-1">•</span>
|
||||||
|
<span class="text-gray-400">Session: {{ session.started_at|local_datetime if session.started_at else 'Unknown' }}</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Download Time -->
|
||||||
|
{% if file.downloaded_at %}
|
||||||
|
<span class="mx-1">•</span>
|
||||||
|
{{ file.downloaded_at|local_datetime }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Checksum Indicator -->
|
||||||
|
{% if file.checksum %}
|
||||||
|
<span class="mx-1" title="SHA256: {{ file.checksum[:16] }}...">
|
||||||
|
<svg class="w-3 h-3 inline text-green-600" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fill-rule="evenodd" d="M2.166 4.999A11.954 11.954 0 0010 1.944 11.954 11.954 0 0017.834 5c.11.65.166 1.32.166 2.001 0 5.225-3.34 9.67-8 11.317C5.34 16.67 2 12.225 2 7c0-.682.057-1.35.166-2.001zm11.541 3.708a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="opacity-0 group-hover:opacity-100 transition-opacity flex items-center gap-2">
|
||||||
|
{% if file.file_type == 'measurement' or (file.file_path and file.file_path.endswith('.rnd')) %}
|
||||||
|
<a href="/api/projects/{{ project_id }}/files/{{ file.id }}/view-rnd"
|
||||||
|
onclick="event.stopPropagation();"
|
||||||
|
class="px-3 py-1 text-xs bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 transition-colors flex items-center">
|
||||||
|
<svg class="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
||||||
|
</svg>
|
||||||
|
View
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{# Only show Report button for Leq files #}
|
||||||
|
{% if file.file_path and '_Leq_' in file.file_path %}
|
||||||
|
<a href="/api/projects/{{ project_id }}/files/{{ file.id }}/generate-report"
|
||||||
|
onclick="event.stopPropagation();"
|
||||||
|
class="px-3 py-1 text-xs bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors flex items-center"
|
||||||
|
title="Generate Excel Report">
|
||||||
|
<svg class="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||||
|
</svg>
|
||||||
|
Report
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<button onclick="event.stopPropagation(); downloadFile('{{ file.id }}')"
|
||||||
|
class="px-3 py-1 text-xs bg-seismo-orange text-white rounded-lg hover:bg-seismo-navy transition-colors">
|
||||||
|
<svg class="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
|
||||||
|
</svg>
|
||||||
|
Download
|
||||||
|
</button>
|
||||||
|
<button onclick="event.stopPropagation(); confirmDeleteFile('{{ file.id }}', '{{ file.file_path.split('/')[-1] if file.file_path else 'Unknown' }}')"
|
||||||
|
class="px-3 py-1 text-xs bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
|
||||||
|
title="Delete this file">
|
||||||
|
<svg class="w-4 h-4 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<!-- Empty State -->
|
||||||
|
<div class="px-6 py-12 text-center">
|
||||||
|
<svg class="w-16 h-16 mx-auto mb-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
|
||||||
|
</svg>
|
||||||
|
<p class="text-gray-500 dark:text-gray-400 mb-2">No files downloaded yet</p>
|
||||||
|
<p class="text-sm text-gray-400 dark:text-gray-500">
|
||||||
|
Files will appear here once they are downloaded from the sound level meter
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function downloadFile(fileId) {
|
||||||
|
window.location.href = `/api/projects/{{ project_id }}/files/${fileId}/download`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmDeleteFile(fileId, fileName) {
|
||||||
|
if (confirm(`Are you sure you want to delete "${fileName}"?\n\nThis action cannot be undone.`)) {
|
||||||
|
deleteFile(fileId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteFile(fileId) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/projects/{{ project_id }}/files/${fileId}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
const data = await response.json();
|
||||||
|
alert(`Failed to delete file: ${data.detail || 'Unknown error'}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert(`Error deleting file: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -58,7 +58,9 @@
|
|||||||
data-note="{{ unit.note if unit.note else '' }}">
|
data-note="{{ unit.note if unit.note else '' }}">
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
{% if unit.status == 'OK' %}
|
{% if not unit.deployed %}
|
||||||
|
<span class="w-3 h-3 rounded-full bg-gray-400 dark:bg-gray-500" title="Benched"></span>
|
||||||
|
{% elif unit.status == 'OK' %}
|
||||||
<span class="w-3 h-3 rounded-full bg-green-500" title="OK"></span>
|
<span class="w-3 h-3 rounded-full bg-green-500" title="OK"></span>
|
||||||
{% elif unit.status == 'Pending' %}
|
{% elif unit.status == 'Pending' %}
|
||||||
<span class="w-3 h-3 rounded-full bg-yellow-500" title="Pending"></span>
|
<span class="w-3 h-3 rounded-full bg-yellow-500" title="Pending"></span>
|
||||||
@@ -83,6 +85,10 @@
|
|||||||
<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">
|
<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
|
Modem
|
||||||
</span>
|
</span>
|
||||||
|
{% elif unit.device_type == 'slm' %}
|
||||||
|
<span class="px-2 py-1 rounded-full bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-300 text-xs font-medium">
|
||||||
|
SLM
|
||||||
|
</span>
|
||||||
{% else %}
|
{% 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">
|
<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
|
Seismograph
|
||||||
@@ -195,7 +201,9 @@
|
|||||||
<!-- Header: Status Dot + Unit ID + Status Badge -->
|
<!-- Header: Status Dot + Unit ID + Status Badge -->
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
{% if unit.status == 'OK' %}
|
{% if not unit.deployed %}
|
||||||
|
<span class="w-4 h-4 rounded-full bg-gray-400 dark:bg-gray-500" title="Benched"></span>
|
||||||
|
{% elif unit.status == 'OK' %}
|
||||||
<span class="w-4 h-4 rounded-full bg-green-500" title="OK"></span>
|
<span class="w-4 h-4 rounded-full bg-green-500" title="OK"></span>
|
||||||
{% elif unit.status == 'Pending' %}
|
{% elif unit.status == 'Pending' %}
|
||||||
<span class="w-4 h-4 rounded-full bg-yellow-500" title="Pending"></span>
|
<span class="w-4 h-4 rounded-full bg-yellow-500" title="Pending"></span>
|
||||||
@@ -222,6 +230,10 @@
|
|||||||
<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">
|
<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
|
Modem
|
||||||
</span>
|
</span>
|
||||||
|
{% elif unit.device_type == 'slm' %}
|
||||||
|
<span class="px-2 py-1 rounded-full bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-300 text-xs font-medium">
|
||||||
|
SLM
|
||||||
|
</span>
|
||||||
{% else %}
|
{% 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">
|
<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
|
Seismograph
|
||||||
|
|||||||
@@ -122,7 +122,7 @@
|
|||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
||||||
<option value="seismograph">Seismograph</option>
|
<option value="seismograph">Seismograph</option>
|
||||||
<option value="modem">Modem</option>
|
<option value="modem">Modem</option>
|
||||||
<option value="sound_level_meter">Sound Level Meter</option>
|
<option value="slm">Sound Level Meter</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -178,8 +178,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Hardware Model</label>
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Hardware Model</label>
|
||||||
<input type="text" name="hardware_model" placeholder="e.g., Raven XTV"
|
<select name="hardware_model"
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
||||||
|
<option value="">Select model...</option>
|
||||||
|
<option value="RV50">RV50</option>
|
||||||
|
<option value="RV55">RV55</option>
|
||||||
|
<option value="RX55">RX55</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Deployment Type</label>
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Deployment Type</label>
|
||||||
@@ -206,21 +211,6 @@
|
|||||||
<input type="text" name="slm_model" placeholder="NL-43"
|
<input type="text" name="slm_model" placeholder="NL-43"
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Host/IP Address</label>
|
|
||||||
<input type="text" name="slm_host" placeholder="192.168.1.100"
|
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">TCP Port</label>
|
|
||||||
<input type="number" name="slm_tcp_port" placeholder="2255"
|
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">FTP Port</label>
|
|
||||||
<input type="number" name="slm_ftp_port" placeholder="21"
|
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Serial Number</label>
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Serial Number</label>
|
||||||
<input type="text" name="slm_serial_number" placeholder="SN123456"
|
<input type="text" name="slm_serial_number" placeholder="SN123456"
|
||||||
@@ -244,6 +234,12 @@
|
|||||||
<option value="I">I (Impulse)</option>
|
<option value="I">I (Impulse)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="slmModemPairingField" class="hidden">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Deployed With Modem</label>
|
||||||
|
{% set picker_id = "-add-slm" %}
|
||||||
|
{% include "partials/modem_picker.html" with context %}
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">SLM connects via modem's IP address</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
@@ -301,7 +297,7 @@
|
|||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
||||||
<option value="seismograph">Seismograph</option>
|
<option value="seismograph">Seismograph</option>
|
||||||
<option value="modem">Modem</option>
|
<option value="modem">Modem</option>
|
||||||
<option value="sound_level_meter">Sound Level Meter</option>
|
<option value="slm">Sound Level Meter</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -360,8 +356,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Hardware Model</label>
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Hardware Model</label>
|
||||||
<input type="text" name="hardware_model" id="editHardwareModel" placeholder="e.g., Raven XTV"
|
<select name="hardware_model" id="editHardwareModel"
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
||||||
|
<option value="">Select model...</option>
|
||||||
|
<option value="RV50">RV50</option>
|
||||||
|
<option value="RV55">RV55</option>
|
||||||
|
<option value="RX55">RX55</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Deployment Type</label>
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Deployment Type</label>
|
||||||
@@ -388,21 +389,6 @@
|
|||||||
<input type="text" name="slm_model" id="editSlmModel" placeholder="NL-43"
|
<input type="text" name="slm_model" id="editSlmModel" placeholder="NL-43"
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Host/IP Address</label>
|
|
||||||
<input type="text" name="slm_host" id="editSlmHost" placeholder="192.168.1.100"
|
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">TCP Port</label>
|
|
||||||
<input type="number" name="slm_tcp_port" id="editSlmTcpPort" placeholder="2255"
|
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">FTP Port</label>
|
|
||||||
<input type="number" name="slm_ftp_port" id="editSlmFtpPort" placeholder="21"
|
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Serial Number</label>
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Serial Number</label>
|
||||||
<input type="text" name="slm_serial_number" id="editSlmSerialNumber" placeholder="SN123456"
|
<input type="text" name="slm_serial_number" id="editSlmSerialNumber" placeholder="SN123456"
|
||||||
@@ -428,6 +414,12 @@
|
|||||||
<option value="I">I (Impulse)</option>
|
<option value="I">I (Impulse)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="editSlmModemPairingField" class="hidden">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Deployed With Modem</label>
|
||||||
|
{% set picker_id = "-edit-slm" %}
|
||||||
|
{% include "partials/modem_picker.html" with context %}
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">SLM connects via modem's IP address</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
@@ -641,7 +633,7 @@
|
|||||||
setFieldsDisabled(seismoFields, true);
|
setFieldsDisabled(seismoFields, true);
|
||||||
setFieldsDisabled(modemFields, false);
|
setFieldsDisabled(modemFields, false);
|
||||||
setFieldsDisabled(slmFields, true);
|
setFieldsDisabled(slmFields, true);
|
||||||
} else if (deviceType === 'sound_level_meter') {
|
} else if (deviceType === 'slm') {
|
||||||
seismoFields.classList.add('hidden');
|
seismoFields.classList.add('hidden');
|
||||||
modemFields.classList.add('hidden');
|
modemFields.classList.add('hidden');
|
||||||
slmFields.classList.remove('hidden');
|
slmFields.classList.remove('hidden');
|
||||||
@@ -649,6 +641,7 @@
|
|||||||
setFieldsDisabled(seismoFields, true);
|
setFieldsDisabled(seismoFields, true);
|
||||||
setFieldsDisabled(modemFields, true);
|
setFieldsDisabled(modemFields, true);
|
||||||
setFieldsDisabled(slmFields, false);
|
setFieldsDisabled(slmFields, false);
|
||||||
|
toggleModemPairing(); // Check if modem pairing should be shown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,17 +654,26 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle modem pairing field visibility (only for deployed seismographs)
|
// Toggle modem pairing field visibility (only for deployed seismographs and SLMs)
|
||||||
function toggleModemPairing() {
|
function toggleModemPairing() {
|
||||||
const deviceType = document.getElementById('deviceTypeSelect').value;
|
const deviceType = document.getElementById('deviceTypeSelect').value;
|
||||||
const deployedCheckbox = document.getElementById('deployedCheckbox');
|
const deployedCheckbox = document.getElementById('deployedCheckbox');
|
||||||
const modemPairingField = document.getElementById('modemPairingField');
|
const modemPairingField = document.getElementById('modemPairingField');
|
||||||
|
const slmModemPairingField = document.getElementById('slmModemPairingField');
|
||||||
|
|
||||||
|
// Seismograph modem pairing
|
||||||
if (deviceType === 'seismograph' && deployedCheckbox.checked) {
|
if (deviceType === 'seismograph' && deployedCheckbox.checked) {
|
||||||
modemPairingField.classList.remove('hidden');
|
modemPairingField.classList.remove('hidden');
|
||||||
} else {
|
} else {
|
||||||
modemPairingField.classList.add('hidden');
|
modemPairingField.classList.add('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SLM modem pairing
|
||||||
|
if (deviceType === 'slm' && deployedCheckbox.checked) {
|
||||||
|
slmModemPairingField.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
slmModemPairingField.classList.add('hidden');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add unknown unit to roster
|
// Add unknown unit to roster
|
||||||
@@ -816,13 +818,14 @@
|
|||||||
setFieldsDisabled(seismoFields, true);
|
setFieldsDisabled(seismoFields, true);
|
||||||
setFieldsDisabled(modemFields, false);
|
setFieldsDisabled(modemFields, false);
|
||||||
setFieldsDisabled(slmFields, true);
|
setFieldsDisabled(slmFields, true);
|
||||||
} else if (deviceType === 'sound_level_meter') {
|
} else if (deviceType === 'slm') {
|
||||||
seismoFields.classList.add('hidden');
|
seismoFields.classList.add('hidden');
|
||||||
modemFields.classList.add('hidden');
|
modemFields.classList.add('hidden');
|
||||||
slmFields.classList.remove('hidden');
|
slmFields.classList.remove('hidden');
|
||||||
setFieldsDisabled(seismoFields, true);
|
setFieldsDisabled(seismoFields, true);
|
||||||
setFieldsDisabled(modemFields, true);
|
setFieldsDisabled(modemFields, true);
|
||||||
setFieldsDisabled(slmFields, false);
|
setFieldsDisabled(slmFields, false);
|
||||||
|
toggleEditModemPairing(); // Check if modem pairing should be shown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -831,12 +834,21 @@
|
|||||||
const deviceType = document.getElementById('editDeviceTypeSelect').value;
|
const deviceType = document.getElementById('editDeviceTypeSelect').value;
|
||||||
const deployedCheckbox = document.getElementById('editDeployedCheckbox');
|
const deployedCheckbox = document.getElementById('editDeployedCheckbox');
|
||||||
const modemPairingField = document.getElementById('editModemPairingField');
|
const modemPairingField = document.getElementById('editModemPairingField');
|
||||||
|
const slmModemPairingField = document.getElementById('editSlmModemPairingField');
|
||||||
|
|
||||||
|
// Seismograph modem pairing
|
||||||
if (deviceType === 'seismograph' && deployedCheckbox.checked) {
|
if (deviceType === 'seismograph' && deployedCheckbox.checked) {
|
||||||
modemPairingField.classList.remove('hidden');
|
modemPairingField.classList.remove('hidden');
|
||||||
} else {
|
} else {
|
||||||
modemPairingField.classList.add('hidden');
|
modemPairingField.classList.add('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SLM modem pairing
|
||||||
|
if (deviceType === 'slm' && deployedCheckbox.checked) {
|
||||||
|
slmModemPairingField.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
slmModemPairingField.classList.add('hidden');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edit Unit - Fetch data and populate form
|
// Edit Unit - Fetch data and populate form
|
||||||
@@ -911,7 +923,7 @@
|
|||||||
// Modem fields
|
// Modem fields
|
||||||
document.getElementById('editIpAddress').value = unit.ip_address;
|
document.getElementById('editIpAddress').value = unit.ip_address;
|
||||||
document.getElementById('editPhoneNumber').value = unit.phone_number;
|
document.getElementById('editPhoneNumber').value = unit.phone_number;
|
||||||
document.getElementById('editHardwareModel').value = unit.hardware_model;
|
document.getElementById('editHardwareModel').value = unit.hardware_model || '';
|
||||||
document.getElementById('editDeploymentType').value = unit.deployment_type || '';
|
document.getElementById('editDeploymentType').value = unit.deployment_type || '';
|
||||||
|
|
||||||
// Populate unit picker for modem (uses -edit-modem suffix)
|
// Populate unit picker for modem (uses -edit-modem suffix)
|
||||||
@@ -940,13 +952,36 @@
|
|||||||
|
|
||||||
// SLM fields
|
// SLM fields
|
||||||
document.getElementById('editSlmModel').value = unit.slm_model || '';
|
document.getElementById('editSlmModel').value = unit.slm_model || '';
|
||||||
document.getElementById('editSlmHost').value = unit.slm_host || '';
|
|
||||||
document.getElementById('editSlmTcpPort').value = unit.slm_tcp_port || '';
|
|
||||||
document.getElementById('editSlmFtpPort').value = unit.slm_ftp_port || '';
|
|
||||||
document.getElementById('editSlmSerialNumber').value = unit.slm_serial_number || '';
|
document.getElementById('editSlmSerialNumber').value = unit.slm_serial_number || '';
|
||||||
document.getElementById('editSlmFrequencyWeighting').value = unit.slm_frequency_weighting || '';
|
document.getElementById('editSlmFrequencyWeighting').value = unit.slm_frequency_weighting || '';
|
||||||
document.getElementById('editSlmTimeWeighting').value = unit.slm_time_weighting || '';
|
document.getElementById('editSlmTimeWeighting').value = unit.slm_time_weighting || '';
|
||||||
|
|
||||||
|
// Populate SLM modem picker (uses -edit-slm suffix)
|
||||||
|
const slmModemPickerValue = document.getElementById('modem-picker-value-edit-slm');
|
||||||
|
const slmModemPickerSearch = document.getElementById('modem-picker-search-edit-slm');
|
||||||
|
const slmModemPickerClear = document.getElementById('modem-picker-clear-edit-slm');
|
||||||
|
if (slmModemPickerValue) slmModemPickerValue.value = unit.deployed_with_modem_id || '';
|
||||||
|
if (unit.deployed_with_modem_id && unit.device_type === 'slm') {
|
||||||
|
// Fetch modem display (ID + IP + note)
|
||||||
|
fetch(`/api/roster/${unit.deployed_with_modem_id}`)
|
||||||
|
.then(r => r.ok ? r.json() : null)
|
||||||
|
.then(modem => {
|
||||||
|
if (modem && slmModemPickerSearch) {
|
||||||
|
let display = modem.id;
|
||||||
|
if (modem.ip_address) display += ` - ${modem.ip_address}`;
|
||||||
|
if (modem.note) display += ` - ${modem.note}`;
|
||||||
|
slmModemPickerSearch.value = display;
|
||||||
|
if (slmModemPickerClear) slmModemPickerClear.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (slmModemPickerSearch) slmModemPickerSearch.value = unit.deployed_with_modem_id;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (slmModemPickerSearch) slmModemPickerSearch.value = '';
|
||||||
|
if (slmModemPickerClear) slmModemPickerClear.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
// Cascade section - show if there's a paired device
|
// Cascade section - show if there's a paired device
|
||||||
const cascadeSection = document.getElementById('editCascadeSection');
|
const cascadeSection = document.getElementById('editCascadeSection');
|
||||||
const cascadeToUnitId = document.getElementById('editCascadeToUnitId');
|
const cascadeToUnitId = document.getElementById('editCascadeToUnitId');
|
||||||
|
|||||||
@@ -179,6 +179,54 @@
|
|||||||
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Hardware Model</label>
|
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Hardware Model</label>
|
||||||
<p id="viewHardwareModel" class="mt-1 text-gray-900 dark:text-white font-medium">--</p>
|
<p id="viewHardwareModel" class="mt-1 text-gray-900 dark:text-white font-medium">--</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="viewModemLoginSection" class="hidden">
|
||||||
|
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Management Interface</label>
|
||||||
|
<p class="mt-1">
|
||||||
|
<a id="viewModemLoginLink" href="#" target="_blank"
|
||||||
|
class="inline-flex items-center gap-2 text-seismo-orange hover:text-orange-600 font-medium">
|
||||||
|
<span id="viewModemLoginText">--</span>
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sound Level Meter Info -->
|
||||||
|
<div id="viewSlmFields" class="hidden border-t border-gray-200 dark:border-gray-700 pt-6">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Sound Level Meter Information</h3>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Model</label>
|
||||||
|
<p id="viewSlmModel" class="mt-1 text-gray-900 dark:text-white font-medium">--</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Serial Number</label>
|
||||||
|
<p id="viewSlmSerialNumber" class="mt-1 text-gray-900 dark:text-white font-medium">--</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Frequency Weighting</label>
|
||||||
|
<p id="viewSlmFrequencyWeighting" class="mt-1 text-gray-900 dark:text-white font-medium">--</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Time Weighting</label>
|
||||||
|
<p id="viewSlmTimeWeighting" class="mt-1 text-gray-900 dark:text-white font-medium">--</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Measurement Range</label>
|
||||||
|
<p id="viewSlmMeasurementRange" class="mt-1 text-gray-900 dark:text-white font-medium">--</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Deployed With Modem</label>
|
||||||
|
<p id="viewSlmDeployedWithModemContainer" class="mt-1">
|
||||||
|
<a id="viewSlmDeployedWithModemLink" href="#" class="text-seismo-orange hover:text-orange-600 font-medium hover:underline hidden">
|
||||||
|
<span id="viewSlmDeployedWithModemText">--</span>
|
||||||
|
</a>
|
||||||
|
<span id="viewSlmDeployedWithModemNoLink" class="text-gray-900 dark:text-white font-medium">--</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -292,7 +340,7 @@
|
|||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
||||||
<option value="seismograph">Seismograph</option>
|
<option value="seismograph">Seismograph</option>
|
||||||
<option value="modem">Modem</option>
|
<option value="modem">Modem</option>
|
||||||
<option value="sound_level_meter">Sound Level Meter</option>
|
<option value="slm">Sound Level Meter</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -375,8 +423,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Hardware Model</label>
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Hardware Model</label>
|
||||||
<input type="text" name="hardware_model" id="hardwareModel" placeholder="e.g., Raven XTV"
|
<select name="hardware_model" id="hardwareModel"
|
||||||
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
|
||||||
|
<option value="">Select model...</option>
|
||||||
|
<option value="RV50">RV50</option>
|
||||||
|
<option value="RV55">RV55</option>
|
||||||
|
<option value="RX55">RX55</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -434,7 +487,7 @@
|
|||||||
{% set input_name = "deployed_with_modem_id" %}
|
{% set input_name = "deployed_with_modem_id" %}
|
||||||
{% include "partials/modem_picker.html" with context %}
|
{% include "partials/modem_picker.html" with context %}
|
||||||
</div>
|
</div>
|
||||||
<button type="button" onclick="openPairDeviceModal('sound_level_meter')"
|
<button type="button" onclick="openPairDeviceModal('slm')"
|
||||||
class="px-3 py-2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-300 rounded-lg transition-colors flex items-center gap-1"
|
class="px-3 py-2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-300 rounded-lg transition-colors flex items-center gap-1"
|
||||||
title="Pair with modem">
|
title="Pair with modem">
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -594,6 +647,19 @@ async function fetchModemDisplay(modemIdOrIp) {
|
|||||||
return { display: modemIdOrIp, modemId: modemIdOrIp };
|
return { display: modemIdOrIp, modemId: modemIdOrIp };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format weighting values for display
|
||||||
|
function formatWeighting(value, type) {
|
||||||
|
if (!value) return null;
|
||||||
|
if (type === 'frequency') {
|
||||||
|
const labels = { 'A': 'A-weighting', 'C': 'C-weighting', 'Z': 'Z-weighting (Flat)' };
|
||||||
|
return labels[value] || value;
|
||||||
|
} else if (type === 'time') {
|
||||||
|
const labels = { 'F': 'Fast (125ms)', 'S': 'Slow (1s)', 'I': 'Impulse (35ms)' };
|
||||||
|
return labels[value] || value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
// Load unit data on page load
|
// Load unit data on page load
|
||||||
async function loadUnitData() {
|
async function loadUnitData() {
|
||||||
try {
|
try {
|
||||||
@@ -689,9 +755,16 @@ function populateViewMode() {
|
|||||||
'Missing': 'text-red-600 dark:text-red-400'
|
'Missing': 'text-red-600 dark:text-red-400'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If unit is not deployed (benched), show gray "Benched" status instead of health status
|
||||||
|
if (!currentUnit.deployed) {
|
||||||
|
document.getElementById('statusIndicator').className = 'w-3 h-3 rounded-full bg-gray-400 dark:bg-gray-500';
|
||||||
|
document.getElementById('statusText').className = 'font-semibold text-gray-600 dark:text-gray-400';
|
||||||
|
document.getElementById('statusText').textContent = 'Benched';
|
||||||
|
} else {
|
||||||
document.getElementById('statusIndicator').className = `w-3 h-3 rounded-full ${statusColors[unitStatus.status] || 'bg-gray-400'}`;
|
document.getElementById('statusIndicator').className = `w-3 h-3 rounded-full ${statusColors[unitStatus.status] || 'bg-gray-400'}`;
|
||||||
document.getElementById('statusText').className = `font-semibold ${statusTextColors[unitStatus.status] || 'text-gray-600'}`;
|
document.getElementById('statusText').className = `font-semibold ${statusTextColors[unitStatus.status] || 'text-gray-600'}`;
|
||||||
document.getElementById('statusText').textContent = unitStatus.status || 'Unknown';
|
document.getElementById('statusText').textContent = unitStatus.status || 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
// Format "Last Seen" with timezone-aware formatting
|
// Format "Last Seen" with timezone-aware formatting
|
||||||
if (unitStatus.last && typeof formatFullTimestamp === 'function') {
|
if (unitStatus.last && typeof formatFullTimestamp === 'function') {
|
||||||
@@ -704,7 +777,8 @@ function populateViewMode() {
|
|||||||
} else {
|
} else {
|
||||||
document.getElementById('statusIndicator').className = 'w-3 h-3 rounded-full bg-gray-400';
|
document.getElementById('statusIndicator').className = 'w-3 h-3 rounded-full bg-gray-400';
|
||||||
document.getElementById('statusText').className = 'font-semibold text-gray-600 dark:text-gray-400';
|
document.getElementById('statusText').className = 'font-semibold text-gray-600 dark:text-gray-400';
|
||||||
document.getElementById('statusText').textContent = 'No status data';
|
// Show "Benched" if not deployed, otherwise "No status data"
|
||||||
|
document.getElementById('statusText').textContent = !currentUnit.deployed ? 'Benched' : 'No status data';
|
||||||
document.getElementById('lastSeen').textContent = '--';
|
document.getElementById('lastSeen').textContent = '--';
|
||||||
document.getElementById('age').textContent = '--';
|
document.getElementById('age').textContent = '--';
|
||||||
}
|
}
|
||||||
@@ -775,22 +849,86 @@ function populateViewMode() {
|
|||||||
document.getElementById('viewPhoneNumber').textContent = currentUnit.phone_number || '--';
|
document.getElementById('viewPhoneNumber').textContent = currentUnit.phone_number || '--';
|
||||||
document.getElementById('viewHardwareModel').textContent = currentUnit.hardware_model || '--';
|
document.getElementById('viewHardwareModel').textContent = currentUnit.hardware_model || '--';
|
||||||
|
|
||||||
|
// Modem management interface link
|
||||||
|
const modemLoginSection = document.getElementById('viewModemLoginSection');
|
||||||
|
const modemLoginLink = document.getElementById('viewModemLoginLink');
|
||||||
|
const modemLoginText = document.getElementById('viewModemLoginText');
|
||||||
|
|
||||||
|
if (currentUnit.ip_address && currentUnit.hardware_model) {
|
||||||
|
let loginUrl = '';
|
||||||
|
let loginLabel = '';
|
||||||
|
|
||||||
|
if (currentUnit.hardware_model === 'RV50' || currentUnit.hardware_model === 'RV55') {
|
||||||
|
// ACEmanager uses port 9191
|
||||||
|
loginUrl = `http://${currentUnit.ip_address}:9191`;
|
||||||
|
loginLabel = 'ACEmanager';
|
||||||
|
} else if (currentUnit.hardware_model === 'RX55') {
|
||||||
|
// AirLink uses HTTPS on port 443
|
||||||
|
loginUrl = `https://${currentUnit.ip_address}:443`;
|
||||||
|
loginLabel = 'AirLink';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loginUrl) {
|
||||||
|
modemLoginLink.href = loginUrl;
|
||||||
|
modemLoginText.textContent = loginLabel;
|
||||||
|
modemLoginSection.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
modemLoginSection.classList.add('hidden');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
modemLoginSection.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
// Notes
|
// Notes
|
||||||
document.getElementById('viewNote').textContent = currentUnit.note || '--';
|
document.getElementById('viewNote').textContent = currentUnit.note || '--';
|
||||||
|
|
||||||
// Show/hide fields based on device type
|
// Show/hide fields based on device type
|
||||||
if (currentUnit.device_type === 'modem') {
|
// Hide all device-specific sections first
|
||||||
document.getElementById('viewSeismographFields').classList.add('hidden');
|
document.getElementById('viewSeismographFields').classList.add('hidden');
|
||||||
|
document.getElementById('viewModemFields').classList.add('hidden');
|
||||||
|
document.getElementById('viewSlmFields').classList.add('hidden');
|
||||||
|
document.getElementById('viewPairedDeviceSection').classList.add('hidden');
|
||||||
|
document.getElementById('viewConnectivitySection').classList.add('hidden');
|
||||||
|
|
||||||
|
if (currentUnit.device_type === 'modem') {
|
||||||
document.getElementById('viewModemFields').classList.remove('hidden');
|
document.getElementById('viewModemFields').classList.remove('hidden');
|
||||||
document.getElementById('viewPairedDeviceSection').classList.remove('hidden');
|
document.getElementById('viewPairedDeviceSection').classList.remove('hidden');
|
||||||
document.getElementById('viewConnectivitySection').classList.remove('hidden');
|
document.getElementById('viewConnectivitySection').classList.remove('hidden');
|
||||||
// Load paired device info
|
// Load paired device info
|
||||||
loadPairedDevice();
|
loadPairedDevice();
|
||||||
|
} else if (currentUnit.device_type === 'slm') {
|
||||||
|
document.getElementById('viewSlmFields').classList.remove('hidden');
|
||||||
|
// Populate SLM view fields
|
||||||
|
document.getElementById('viewSlmModel').textContent = currentUnit.slm_model || '--';
|
||||||
|
document.getElementById('viewSlmSerialNumber').textContent = currentUnit.slm_serial_number || '--';
|
||||||
|
document.getElementById('viewSlmFrequencyWeighting').textContent = formatWeighting(currentUnit.slm_frequency_weighting, 'frequency') || '--';
|
||||||
|
document.getElementById('viewSlmTimeWeighting').textContent = formatWeighting(currentUnit.slm_time_weighting, 'time') || '--';
|
||||||
|
document.getElementById('viewSlmMeasurementRange').textContent = currentUnit.slm_measurement_range || '--';
|
||||||
|
|
||||||
|
// Handle SLM modem link
|
||||||
|
const slmModemLink = document.getElementById('viewSlmDeployedWithModemLink');
|
||||||
|
const slmModemNoLink = document.getElementById('viewSlmDeployedWithModemNoLink');
|
||||||
|
const slmModemText = document.getElementById('viewSlmDeployedWithModemText');
|
||||||
|
|
||||||
|
if (currentUnit.deployed_with_modem_id) {
|
||||||
|
fetchModemDisplay(currentUnit.deployed_with_modem_id).then(result => {
|
||||||
|
if (slmModemText) slmModemText.textContent = result.display;
|
||||||
|
if (slmModemLink) {
|
||||||
|
slmModemLink.href = `/unit/${encodeURIComponent(result.modemId)}`;
|
||||||
|
slmModemLink.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
if (slmModemNoLink) slmModemNoLink.classList.add('hidden');
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
|
if (slmModemNoLink) {
|
||||||
|
slmModemNoLink.textContent = '--';
|
||||||
|
slmModemNoLink.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
if (slmModemLink) slmModemLink.classList.add('hidden');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Seismograph (default)
|
||||||
document.getElementById('viewSeismographFields').classList.remove('hidden');
|
document.getElementById('viewSeismographFields').classList.remove('hidden');
|
||||||
document.getElementById('viewModemFields').classList.add('hidden');
|
|
||||||
document.getElementById('viewPairedDeviceSection').classList.add('hidden');
|
|
||||||
document.getElementById('viewConnectivitySection').classList.add('hidden');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -906,7 +1044,7 @@ async function checkAndShowCascadeSection() {
|
|||||||
if (currentUnit.device_type === 'modem' && currentUnit.deployed_with_unit_id) {
|
if (currentUnit.device_type === 'modem' && currentUnit.deployed_with_unit_id) {
|
||||||
// Modem is paired with a seismograph or SLM
|
// Modem is paired with a seismograph or SLM
|
||||||
pairedUnitId = currentUnit.deployed_with_unit_id;
|
pairedUnitId = currentUnit.deployed_with_unit_id;
|
||||||
} else if ((currentUnit.device_type === 'seismograph' || currentUnit.device_type === 'sound_level_meter') && currentUnit.deployed_with_modem_id) {
|
} else if ((currentUnit.device_type === 'seismograph' || currentUnit.device_type === 'slm') && currentUnit.deployed_with_modem_id) {
|
||||||
// Seismograph or SLM is paired with a modem
|
// Seismograph or SLM is paired with a modem
|
||||||
pairedUnitId = currentUnit.deployed_with_modem_id;
|
pairedUnitId = currentUnit.deployed_with_modem_id;
|
||||||
}
|
}
|
||||||
@@ -936,7 +1074,7 @@ function toggleDetailFields() {
|
|||||||
seismoFields.classList.remove('hidden');
|
seismoFields.classList.remove('hidden');
|
||||||
} else if (deviceType === 'modem') {
|
} else if (deviceType === 'modem') {
|
||||||
modemFields.classList.remove('hidden');
|
modemFields.classList.remove('hidden');
|
||||||
} else if (deviceType === 'sound_level_meter') {
|
} else if (deviceType === 'slm') {
|
||||||
slmFields.classList.remove('hidden');
|
slmFields.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -999,7 +1137,7 @@ function getCorrectModemPickerValue(deviceType) {
|
|||||||
if (deviceType === 'seismograph') {
|
if (deviceType === 'seismograph') {
|
||||||
const picker = document.getElementById('modem-picker-value-detail-seismo');
|
const picker = document.getElementById('modem-picker-value-detail-seismo');
|
||||||
return picker ? picker.value : '';
|
return picker ? picker.value : '';
|
||||||
} else if (deviceType === 'sound_level_meter') {
|
} else if (deviceType === 'slm') {
|
||||||
const picker = document.getElementById('modem-picker-value-detail-slm');
|
const picker = document.getElementById('modem-picker-value-detail-slm');
|
||||||
return picker ? picker.value : '';
|
return picker ? picker.value : '';
|
||||||
}
|
}
|
||||||
@@ -1536,7 +1674,7 @@ function selectModemForPairing(modemId, displayText) {
|
|||||||
let pickerId = '';
|
let pickerId = '';
|
||||||
if (pairModalDeviceType === 'seismograph') {
|
if (pairModalDeviceType === 'seismograph') {
|
||||||
pickerId = '-detail-seismo';
|
pickerId = '-detail-seismo';
|
||||||
} else if (pairModalDeviceType === 'sound_level_meter') {
|
} else if (pairModalDeviceType === 'slm') {
|
||||||
pickerId = '-detail-slm';
|
pickerId = '-detail-slm';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1557,7 +1695,7 @@ function clearPairing(deviceType) {
|
|||||||
let pickerId = '';
|
let pickerId = '';
|
||||||
if (deviceType === 'seismograph') {
|
if (deviceType === 'seismograph') {
|
||||||
pickerId = '-detail-seismo';
|
pickerId = '-detail-seismo';
|
||||||
} else if (deviceType === 'sound_level_meter') {
|
} else if (deviceType === 'slm') {
|
||||||
pickerId = '-detail-slm';
|
pickerId = '-detail-slm';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1653,7 +1791,7 @@ function renderModemPairDeviceList() {
|
|||||||
let filteredDevices = modemPairDevices.filter(device => {
|
let filteredDevices = modemPairDevices.filter(device => {
|
||||||
// Filter by device type
|
// Filter by device type
|
||||||
if (device.device_type === 'seismograph' && !showSeismo) return false;
|
if (device.device_type === 'seismograph' && !showSeismo) return false;
|
||||||
if (device.device_type === 'sound_level_meter' && !showSLM) return false;
|
if (device.device_type === 'slm' && !showSLM) return false;
|
||||||
|
|
||||||
// Hide devices paired to OTHER modems (but show unpaired and paired-to-this)
|
// Hide devices paired to OTHER modems (but show unpaired and paired-to-this)
|
||||||
if (hidePaired && device.is_paired_to_other) return false;
|
if (hidePaired && device.is_paired_to_other) return false;
|
||||||
@@ -1680,8 +1818,8 @@ function renderModemPairDeviceList() {
|
|||||||
// Build device list HTML
|
// Build device list HTML
|
||||||
let html = '<div class="divide-y divide-gray-200 dark:divide-gray-700">';
|
let html = '<div class="divide-y divide-gray-200 dark:divide-gray-700">';
|
||||||
for (const device of filteredDevices) {
|
for (const device of filteredDevices) {
|
||||||
const deviceTypeLabel = device.device_type === 'sound_level_meter' ? 'SLM' : 'Seismograph';
|
const deviceTypeLabel = device.device_type === 'slm' ? 'SLM' : 'Seismograph';
|
||||||
const deviceTypeClass = device.device_type === 'sound_level_meter'
|
const deviceTypeClass = device.device_type === 'slm'
|
||||||
? 'bg-purple-100 dark:bg-purple-900/30 text-purple-800 dark:text-purple-300'
|
? 'bg-purple-100 dark:bg-purple-900/30 text-purple-800 dark:text-purple-300'
|
||||||
: 'bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300';
|
: 'bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user