205 lines
8.7 KiB
HTML
205 lines
8.7 KiB
HTML
<!-- One-Off Recording Schedule Editor -->
|
|
<!-- Used for single start/stop recordings with a specific date+time range -->
|
|
|
|
<div id="schedule-oneoff-editor" class="space-y-4">
|
|
<div class="mb-4">
|
|
<h4 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">One-Off Recording</h4>
|
|
<p class="text-xs text-gray-500 dark:text-gray-400">
|
|
Schedule a single recording session with a specific start and end time.
|
|
Duration can be between 15 minutes and 24 hours.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Info box -->
|
|
<div class="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg p-4">
|
|
<div class="flex gap-3">
|
|
<svg class="w-5 h-5 text-amber-500 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<div class="text-sm text-amber-700 dark:text-amber-300">
|
|
<p class="font-medium mb-1">How it works:</p>
|
|
<ol class="list-decimal list-inside space-y-1 text-xs">
|
|
<li>At the start time, the measurement will <strong>start</strong></li>
|
|
<li>At the end time, the measurement will <strong>stop</strong></li>
|
|
<li>If enabled, data will be <strong>downloaded</strong> via FTP after stop</li>
|
|
<li>The schedule will be <strong>auto-disabled</strong> after completion</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Start date/time -->
|
|
<div class="bg-gray-50 dark:bg-gray-700/50 rounded-lg p-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
Start Date & Time
|
|
</label>
|
|
<input type="datetime-local"
|
|
name="start_datetime"
|
|
id="oneoff_start_datetime"
|
|
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 focus:ring-seismo-orange focus:border-seismo-orange">
|
|
<p class="text-xs text-gray-400 dark:text-gray-500 mt-2">
|
|
Must be in the future
|
|
</p>
|
|
</div>
|
|
|
|
<!-- End date/time -->
|
|
<div class="bg-gray-50 dark:bg-gray-700/50 rounded-lg p-4">
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
End Date & Time
|
|
</label>
|
|
<input type="datetime-local"
|
|
name="end_datetime"
|
|
id="oneoff_end_datetime"
|
|
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 focus:ring-seismo-orange focus:border-seismo-orange">
|
|
</div>
|
|
|
|
<!-- Duration preview -->
|
|
<div id="oneoff-duration-preview" class="hidden bg-gray-50 dark:bg-gray-700/50 rounded-lg p-4">
|
|
<div class="flex items-center gap-3">
|
|
<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="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
</svg>
|
|
<div>
|
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Duration: </span>
|
|
<span id="oneoff-duration-text" class="text-sm text-gray-600 dark:text-gray-400"></span>
|
|
</div>
|
|
</div>
|
|
<p id="oneoff-duration-error" class="hidden text-xs text-red-500 mt-2"></p>
|
|
</div>
|
|
|
|
<!-- Download option -->
|
|
<div class="bg-gray-50 dark:bg-gray-700/50 rounded-lg p-4">
|
|
<label class="flex items-start gap-3 cursor-pointer">
|
|
<input type="checkbox"
|
|
name="include_download"
|
|
id="include_download_oneoff"
|
|
class="rounded text-seismo-orange focus:ring-seismo-orange mt-0.5"
|
|
checked>
|
|
<div>
|
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
Download data after recording ends
|
|
</span>
|
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
|
When enabled, measurement data will be downloaded via FTP after the recording stops.
|
|
</p>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Auto-increment index option -->
|
|
<div class="bg-gray-50 dark:bg-gray-700/50 rounded-lg p-4">
|
|
<label class="flex items-start gap-3 cursor-pointer">
|
|
<input type="checkbox"
|
|
name="auto_increment_index"
|
|
id="auto_increment_index_oneoff"
|
|
class="rounded text-seismo-orange focus:ring-seismo-orange mt-0.5"
|
|
checked>
|
|
<div>
|
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
Auto-increment store index before start
|
|
</span>
|
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
|
When enabled, the store/index number is incremented before starting.
|
|
This prevents "overwrite existing data?" prompts on the device.
|
|
</p>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Set min datetime to now (prevent past selections)
|
|
function setMinDatetime() {
|
|
const now = new Date();
|
|
now.setMinutes(Math.ceil(now.getMinutes() / 15) * 15);
|
|
now.setSeconds(0);
|
|
now.setMilliseconds(0);
|
|
const minStr = now.toISOString().slice(0, 16);
|
|
document.getElementById('oneoff_start_datetime').min = minStr;
|
|
document.getElementById('oneoff_end_datetime').min = minStr;
|
|
}
|
|
|
|
setMinDatetime();
|
|
|
|
// Update duration preview when dates change
|
|
function updateDurationPreview() {
|
|
const startInput = document.getElementById('oneoff_start_datetime');
|
|
const endInput = document.getElementById('oneoff_end_datetime');
|
|
const preview = document.getElementById('oneoff-duration-preview');
|
|
const durationText = document.getElementById('oneoff-duration-text');
|
|
const errorText = document.getElementById('oneoff-duration-error');
|
|
|
|
if (!startInput.value || !endInput.value) {
|
|
preview.classList.add('hidden');
|
|
return;
|
|
}
|
|
|
|
const start = new Date(startInput.value);
|
|
const end = new Date(endInput.value);
|
|
const diffMs = end - start;
|
|
const diffMinutes = diffMs / (1000 * 60);
|
|
|
|
preview.classList.remove('hidden');
|
|
errorText.classList.add('hidden');
|
|
|
|
if (diffMinutes <= 0) {
|
|
durationText.textContent = 'Invalid';
|
|
errorText.textContent = 'End time must be after start time.';
|
|
errorText.classList.remove('hidden');
|
|
return;
|
|
}
|
|
|
|
if (diffMinutes < 15) {
|
|
const mins = Math.round(diffMinutes);
|
|
durationText.textContent = `${mins} minute${mins !== 1 ? 's' : ''}`;
|
|
errorText.textContent = 'Minimum duration is 15 minutes.';
|
|
errorText.classList.remove('hidden');
|
|
return;
|
|
}
|
|
|
|
if (diffMinutes > 1440) {
|
|
const hours = Math.round(diffMinutes / 60 * 10) / 10;
|
|
durationText.textContent = `${hours} hours`;
|
|
errorText.textContent = 'Maximum duration is 24 hours.';
|
|
errorText.classList.remove('hidden');
|
|
return;
|
|
}
|
|
|
|
// Valid duration
|
|
if (diffMinutes < 60) {
|
|
durationText.textContent = `${Math.round(diffMinutes)} minutes`;
|
|
} else {
|
|
const hours = Math.floor(diffMinutes / 60);
|
|
const mins = Math.round(diffMinutes % 60);
|
|
durationText.textContent = mins > 0
|
|
? `${hours} hour${hours !== 1 ? 's' : ''} ${mins} min`
|
|
: `${hours} hour${hours !== 1 ? 's' : ''}`;
|
|
}
|
|
}
|
|
|
|
document.getElementById('oneoff_start_datetime').addEventListener('change', function() {
|
|
// Auto-set end to start + 1 hour if end is empty
|
|
const endInput = document.getElementById('oneoff_end_datetime');
|
|
if (!endInput.value) {
|
|
const start = new Date(this.value);
|
|
start.setHours(start.getHours() + 1);
|
|
endInput.value = start.toISOString().slice(0, 16);
|
|
}
|
|
// Update min of end input
|
|
endInput.min = this.value;
|
|
updateDurationPreview();
|
|
});
|
|
|
|
document.getElementById('oneoff_end_datetime').addEventListener('change', updateDurationPreview);
|
|
|
|
// Function to get one-off data as object (called by parent form)
|
|
function getOneOffData() {
|
|
return {
|
|
start_datetime: document.getElementById('oneoff_start_datetime').value,
|
|
end_datetime: document.getElementById('oneoff_end_datetime').value,
|
|
include_download: document.getElementById('include_download_oneoff').checked,
|
|
auto_increment_index: document.getElementById('auto_increment_index_oneoff').checked,
|
|
};
|
|
}
|
|
</script>
|