Files
terra-view/templates/partials/modem_picker.html
serversdwn 6492fdff82 BIG update: Update to 0.5.1. Added:
-Project management
-Modem Managerment
-Modem/unit pairing

and more
2026-01-28 03:27:50 +00:00

129 lines
5.8 KiB
HTML

{#
Modem Picker Component
A reusable HTMX-based autocomplete for selecting modems.
Usage: include "partials/modem_picker.html" with context
Variables available in context:
- selected_modem_id: Pre-selected modem ID (optional)
- selected_modem_display: Display text for pre-selected modem (optional)
- input_name: Name attribute for the hidden input (default: "deployed_with_modem_id")
- picker_id: Unique ID suffix for multiple pickers on same page (default: "")
#}
{% set picker_id = picker_id|default("") %}
{% set input_name = input_name|default("deployed_with_modem_id") %}
{% set selected_modem_id = selected_modem_id|default("") %}
{% set selected_modem_display = selected_modem_display|default("") %}
<div class="modem-picker relative" id="modem-picker-container{{ picker_id }}">
<!-- Hidden input for form submission (stores modem ID) -->
<input type="hidden"
name="{{ input_name }}"
id="modem-picker-value{{ picker_id }}"
value="{{ selected_modem_id }}">
<!-- Search Input -->
<div class="relative">
<input type="text"
id="modem-picker-search{{ picker_id }}"
placeholder="Search by modem ID, IP, or note..."
class="w-full px-4 py-2 pr-10 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 focus:border-seismo-orange"
autocomplete="off"
value="{{ selected_modem_display }}"
hx-get="/api/roster/search/modems"
hx-trigger="keyup changed delay:300ms, focus"
hx-target="#modem-picker-dropdown{{ picker_id }}"
hx-vals='{"picker_id": "{{ picker_id }}"}'
name="q"
onfocus="showModemDropdown('{{ picker_id }}')"
oninput="handleModemSearchInput('{{ picker_id }}', this.value)">
<!-- Search icon -->
<div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
<svg class="w-5 h-5 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>
<!-- Clear button (shown when modem is selected) -->
<button type="button"
id="modem-picker-clear{{ picker_id }}"
class="absolute inset-y-0 right-8 flex items-center pr-1 {{ 'hidden' if not selected_modem_id else '' }}"
onclick="clearModemSelection('{{ picker_id }}')"
title="Clear selection">
<svg class="w-4 h-4 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" 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>
<!-- Dropdown Results Container -->
<div id="modem-picker-dropdown{{ picker_id }}"
class="hidden absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-300 dark:border-gray-600 rounded-lg shadow-lg max-h-60 overflow-y-auto">
<!-- Results loaded via HTMX -->
</div>
</div>
<script>
{# Modem picker functions - defined once, work for any picker_id #}
if (typeof selectModem === 'undefined') {
function selectModem(modemId, displayText, pickerId = '') {
const valueInput = document.getElementById('modem-picker-value' + pickerId);
const searchInput = document.getElementById('modem-picker-search' + pickerId);
const dropdown = document.getElementById('modem-picker-dropdown' + pickerId);
const clearBtn = document.getElementById('modem-picker-clear' + pickerId);
if (valueInput) valueInput.value = modemId;
if (searchInput) searchInput.value = displayText;
if (dropdown) dropdown.classList.add('hidden');
if (clearBtn) clearBtn.classList.remove('hidden');
}
function clearModemSelection(pickerId = '') {
const valueInput = document.getElementById('modem-picker-value' + pickerId);
const searchInput = document.getElementById('modem-picker-search' + pickerId);
const clearBtn = document.getElementById('modem-picker-clear' + pickerId);
if (valueInput) valueInput.value = '';
if (searchInput) {
searchInput.value = '';
searchInput.focus();
}
if (clearBtn) clearBtn.classList.add('hidden');
}
function showModemDropdown(pickerId = '') {
const dropdown = document.getElementById('modem-picker-dropdown' + pickerId);
if (dropdown) dropdown.classList.remove('hidden');
}
function hideModemDropdown(pickerId = '') {
const dropdown = document.getElementById('modem-picker-dropdown' + pickerId);
if (dropdown) dropdown.classList.add('hidden');
}
function handleModemSearchInput(pickerId, value) {
const valueInput = document.getElementById('modem-picker-value' + pickerId);
const clearBtn = document.getElementById('modem-picker-clear' + pickerId);
// If user clears the search box, also clear the hidden value
if (!value.trim()) {
if (valueInput) valueInput.value = '';
if (clearBtn) clearBtn.classList.add('hidden');
}
}
// Close dropdown when clicking outside
document.addEventListener('click', function(event) {
const pickers = document.querySelectorAll('.modem-picker');
pickers.forEach(picker => {
if (!picker.contains(event.target)) {
const dropdown = picker.querySelector('[id^="modem-picker-dropdown"]');
if (dropdown) dropdown.classList.add('hidden');
}
});
});
}
</script>