216 lines
10 KiB
HTML
216 lines
10 KiB
HTML
<form id="slm-config-form"
|
|
hx-post="/api/slm-dashboard/config/{{ unit.id }}"
|
|
hx-swap="none"
|
|
hx-on::after-request="handleConfigSave(event)">
|
|
|
|
<div class="mb-6">
|
|
<h4 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Unit: {{ unit.id }}</h4>
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">Configure measurement parameters for this sound level meter</p>
|
|
</div>
|
|
|
|
<!-- Model & Serial -->
|
|
<div class="grid grid-cols-2 gap-4 mb-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Model</label>
|
|
<select name="slm_model" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
|
|
<option value="">Select model...</option>
|
|
<option value="NL-43" {% if unit.slm_model == 'NL-43' %}selected{% endif %}>NL-43</option>
|
|
<option value="NL-53" {% if unit.slm_model == 'NL-53' %}selected{% endif %}>NL-53</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<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" value="{{ unit.slm_serial_number or '' }}"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
placeholder="e.g., SN123456">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Frequency & Time Weighting -->
|
|
<div class="grid grid-cols-2 gap-4 mb-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Frequency Weighting</label>
|
|
<select name="slm_frequency_weighting" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
|
|
<option value="">Select...</option>
|
|
<option value="A" {% if unit.slm_frequency_weighting == 'A' %}selected{% endif %}>A-weighting</option>
|
|
<option value="C" {% if unit.slm_frequency_weighting == 'C' %}selected{% endif %}>C-weighting</option>
|
|
<option value="Z" {% if unit.slm_frequency_weighting == 'Z' %}selected{% endif %}>Z-weighting (Linear)</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Time Weighting</label>
|
|
<select name="slm_time_weighting" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
|
|
<option value="">Select...</option>
|
|
<option value="Fast" {% if unit.slm_time_weighting == 'Fast' %}selected{% endif %}>Fast (125ms)</option>
|
|
<option value="Slow" {% if unit.slm_time_weighting == 'Slow' %}selected{% endif %}>Slow (1s)</option>
|
|
<option value="Impulse" {% if unit.slm_time_weighting == 'Impulse' %}selected{% endif %}>Impulse</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Measurement Range -->
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Measurement Range</label>
|
|
<select name="slm_measurement_range" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
|
|
<option value="">Select range...</option>
|
|
<option value="30-130" {% if unit.slm_measurement_range == '30-130' %}selected{% endif %}>30-130 dB</option>
|
|
<option value="40-140" {% if unit.slm_measurement_range == '40-140' %}selected{% endif %}>40-140 dB</option>
|
|
<option value="50-140" {% if unit.slm_measurement_range == '50-140' %}selected{% endif %}>50-140 dB</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Network Configuration -->
|
|
<div class="border-t border-gray-200 dark:border-gray-700 pt-4 mt-6 mb-4">
|
|
<h5 class="text-md font-semibold text-gray-900 dark:text-white mb-3">Network Configuration</h5>
|
|
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Assigned Modem</label>
|
|
<select name="deployed_with_modem_id" id="config-modem-select" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
|
|
<option value="">No modem (direct connection)</option>
|
|
<!-- Options loaded via JavaScript -->
|
|
</select>
|
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Select a modem for network access, or leave blank for direct IP connection</p>
|
|
</div>
|
|
|
|
<!-- Legacy direct connection (shown only if no modem selected) -->
|
|
<div id="direct-connection-fields" class="{% if unit.deployed_with_modem_id %}hidden{% endif %}">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Direct IP Address</label>
|
|
<input type="text" name="slm_host" value="{{ unit.slm_host or '' }}"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white font-mono text-sm"
|
|
placeholder="192.168.1.100">
|
|
</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" value="{{ unit.slm_tcp_port or '' }}"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white font-mono text-sm"
|
|
placeholder="502">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="flex justify-end gap-3 mt-6">
|
|
<button type="button" onclick="closeConfigModal()"
|
|
class="px-4 py-2 text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-lg transition-colors">
|
|
Cancel
|
|
</button>
|
|
<button type="button" onclick="testConnection('{{ unit.id }}')"
|
|
class="px-4 py-2 text-blue-700 dark:text-blue-300 bg-blue-100 dark:bg-blue-900 hover:bg-blue-200 dark:hover:bg-blue-800 rounded-lg transition-colors">
|
|
Test Connection
|
|
</button>
|
|
<button type="submit"
|
|
class="px-4 py-2 text-white bg-seismo-orange hover:bg-seismo-burgundy rounded-lg transition-colors">
|
|
Save Configuration
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<script>
|
|
// Load modems list for dropdown
|
|
async function loadModemsForConfig() {
|
|
try {
|
|
const response = await fetch('/api/roster/modems');
|
|
const modems = await response.json();
|
|
|
|
const select = document.getElementById('config-modem-select');
|
|
const currentValue = '{{ unit.deployed_with_modem_id or "" }}';
|
|
|
|
// Keep the "No modem" option
|
|
modems.forEach(modem => {
|
|
const option = document.createElement('option');
|
|
option.value = modem.id;
|
|
option.textContent = `${modem.id}${modem.ip_address ? ' (' + modem.ip_address + ')' : ''}`;
|
|
if (modem.id === currentValue) {
|
|
option.selected = true;
|
|
}
|
|
select.appendChild(option);
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to load modems:', error);
|
|
}
|
|
}
|
|
|
|
// Toggle direct connection fields based on modem selection
|
|
document.getElementById('config-modem-select')?.addEventListener('change', function() {
|
|
const directFields = document.getElementById('direct-connection-fields');
|
|
if (this.value === '') {
|
|
directFields.classList.remove('hidden');
|
|
} else {
|
|
directFields.classList.add('hidden');
|
|
}
|
|
});
|
|
|
|
// Handle save response
|
|
function handleConfigSave(event) {
|
|
if (event.detail.successful) {
|
|
// Show success message
|
|
const toast = document.createElement('div');
|
|
toast.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50';
|
|
toast.textContent = 'Configuration saved successfully!';
|
|
document.body.appendChild(toast);
|
|
|
|
setTimeout(() => {
|
|
toast.remove();
|
|
closeConfigModal();
|
|
// Refresh the unit list
|
|
htmx.trigger('#slm-list', 'load');
|
|
}, 2000);
|
|
} else {
|
|
// Show error message
|
|
const toast = document.createElement('div');
|
|
toast.className = 'fixed bottom-4 right-4 bg-red-500 text-white px-6 py-3 rounded-lg shadow-lg z-50';
|
|
toast.textContent = 'Failed to save configuration';
|
|
document.body.appendChild(toast);
|
|
|
|
setTimeout(() => {
|
|
toast.remove();
|
|
}, 3000);
|
|
}
|
|
}
|
|
|
|
// Test connection to SLM
|
|
async function testConnection(unitId) {
|
|
const toast = document.createElement('div');
|
|
toast.className = 'fixed bottom-4 right-4 bg-blue-500 text-white px-6 py-3 rounded-lg shadow-lg z-50';
|
|
toast.textContent = 'Testing connection...';
|
|
document.body.appendChild(toast);
|
|
|
|
try {
|
|
const response = await fetch(`/api/slmm/${unitId}/status`);
|
|
const data = await response.json();
|
|
|
|
toast.remove();
|
|
|
|
const resultToast = document.createElement('div');
|
|
if (response.ok && data.status === 'online') {
|
|
resultToast.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50';
|
|
resultToast.textContent = `✓ Connection successful! ${data.model || 'SLM'} responding`;
|
|
} else {
|
|
resultToast.className = 'fixed bottom-4 right-4 bg-yellow-500 text-white px-6 py-3 rounded-lg shadow-lg z-50';
|
|
resultToast.textContent = `Connection failed or device offline`;
|
|
}
|
|
document.body.appendChild(resultToast);
|
|
|
|
setTimeout(() => {
|
|
resultToast.remove();
|
|
}, 3000);
|
|
} catch (error) {
|
|
toast.remove();
|
|
const errorToast = document.createElement('div');
|
|
errorToast.className = 'fixed bottom-4 right-4 bg-red-500 text-white px-6 py-3 rounded-lg shadow-lg z-50';
|
|
errorToast.textContent = '✗ Connection test failed';
|
|
document.body.appendChild(errorToast);
|
|
|
|
setTimeout(() => {
|
|
errorToast.remove();
|
|
}, 3000);
|
|
}
|
|
}
|
|
|
|
// Load modems on page load
|
|
loadModemsForConfig();
|
|
</script>
|