feat: add allocated status and project allocation to unit management

- Updated dashboard to display allocated units alongside deployed and benched units.
- Introduced a quick-info modal for units, showing detailed information including calibration status, project allocation, and upcoming jobs.
- Enhanced fleet calendar with a new quick-info modal for units, allowing users to view unit details without navigating away.
- Modified devices table to include allocated status and visual indicators for allocated units.
- Added allocated filter option in the roster view for better unit management.
- Implemented backend migration to add 'allocated' and 'allocated_to_project_id' columns to the roster table.
- Updated unit detail view to reflect allocated status and allow for project allocation input.
This commit is contained in:
2026-03-26 05:05:34 +00:00
parent 4f71d528ce
commit 64d4423308
11 changed files with 501 additions and 90 deletions

View File

@@ -562,7 +562,7 @@
<!-- Status Checkboxes -->
<div class="border-t border-gray-200 dark:border-gray-700 pt-4 space-y-3">
<div class="flex items-center gap-6">
<div class="flex items-center gap-6 flex-wrap">
<label class="flex items-center gap-2 cursor-pointer">
<input type="checkbox" name="deployed" id="deployed" value="true"
class="w-4 h-4 text-seismo-orange focus:ring-seismo-orange rounded">
@@ -573,6 +573,18 @@
class="w-4 h-4 text-purple-600 focus:ring-purple-500 rounded">
<span class="text-sm text-gray-700 dark:text-gray-300">Out for Calibration</span>
</label>
<label class="flex items-center gap-2 cursor-pointer">
<input type="checkbox" name="allocated" id="allocated" value="true"
onchange="document.getElementById('allocatedProjectRow').style.display = this.checked ? '' : 'none'"
class="w-4 h-4 text-orange-500 focus:ring-orange-400 rounded">
<span class="text-sm text-gray-700 dark:text-gray-300">Allocated</span>
</label>
</div>
<div id="allocatedProjectRow" style="display:none">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Allocated to Project</label>
<input type="text" name="allocated_to_project_id" id="allocatedToProjectId"
placeholder="Project name or ID"
class="w-full px-3 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-orange-400 text-sm">
</div>
<!-- Hidden field for retired — controlled by the Retire button below -->
<input type="hidden" name="retired" id="retired" value="">
@@ -881,10 +893,14 @@ function populateViewMode() {
document.getElementById('age').textContent = unitStatus.age || '--';
} else {
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';
// Show "Benched" if not deployed, otherwise "No status data"
document.getElementById('statusText').textContent = !currentUnit.deployed ? 'Benched' : 'No status data';
const isAllocated = currentUnit.allocated && !currentUnit.deployed;
document.getElementById('statusIndicator').className = isAllocated
? 'w-3 h-3 rounded-full bg-orange-400'
: 'w-3 h-3 rounded-full bg-gray-400';
document.getElementById('statusText').className = isAllocated
? 'font-semibold text-orange-500 dark:text-orange-400'
: 'font-semibold text-gray-600 dark:text-gray-400';
document.getElementById('statusText').textContent = isAllocated ? 'Allocated' : (!currentUnit.deployed ? 'Benched' : 'No status data');
document.getElementById('lastSeen').textContent = '--';
document.getElementById('age').textContent = '--';
}
@@ -896,6 +912,11 @@ function populateViewMode() {
} else if (currentUnit.out_for_calibration) {
document.getElementById('retiredStatus').textContent = 'Out for Calibration';
document.getElementById('retiredStatus').className = 'font-medium text-purple-600 dark:text-purple-400';
} else if (currentUnit.allocated && !currentUnit.deployed) {
document.getElementById('retiredStatus').textContent = currentUnit.allocated_to_project_id
? `Allocated — ${currentUnit.allocated_to_project_id}`
: 'Allocated';
document.getElementById('retiredStatus').className = 'font-medium text-orange-500 dark:text-orange-400';
} else {
document.getElementById('retiredStatus').textContent = 'Active';
document.getElementById('retiredStatus').className = 'font-medium text-gray-900 dark:text-white';
@@ -1095,6 +1116,10 @@ function populateEditForm() {
document.getElementById('retired').value = currentUnit.retired ? 'true' : '';
updateRetireButton(currentUnit.retired);
document.getElementById('note').value = currentUnit.note || '';
const allocatedChecked = currentUnit.allocated || false;
document.getElementById('allocated').checked = allocatedChecked;
document.getElementById('allocatedToProjectId').value = currentUnit.allocated_to_project_id || '';
document.getElementById('allocatedProjectRow').style.display = allocatedChecked ? '' : 'none';
// Seismograph fields
document.getElementById('lastCalibrated').value = currentUnit.last_calibrated || '';