From 9ae0f271ea3e41f62753e555f6f1525f83be5fa8 Mon Sep 17 00:00:00 2001 From: Shawn Date: Fri, 29 May 2026 23:17:48 -0400 Subject: [PATCH] chore: remove accidentally committed gps backup file --- static/index.html | 408 +++++++++++++++++++++++++++++++------ static/sw.js | 2 +- tests/test_map_frontend.py | 4 +- 3 files changed, 354 insertions(+), 60 deletions(-) diff --git a/static/index.html b/static/index.html index 76b5fce..882f96c 100644 --- a/static/index.html +++ b/static/index.html @@ -827,16 +827,6 @@ .map-search-row input { flex: 1; min-width: 0; } - .map-filter-chips { - display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 6px; - } - .map-filter-chip { - font-size: 10px; font-weight: 600; padding: 3px 8px; - border-radius: 12px; border: 1px solid var(--border); - background: var(--card2); color: var(--text2); cursor: pointer; - transition: all 0.12s; - } - .map-filter-chip.active { background: var(--accent); border-color: var(--accent); color: #fff; } /* Asset list below map */ .map-asset-list { @@ -1281,6 +1271,22 @@
+ + + + + + - -
+ +
+ +
+
+
+
+
Category
+ +
+
+
Make
+ +
+
+
+
+
Location Type
+ +
+
+
Disney Park
+ +
+
+
+
+
Customer
+ +
+
+
Location
+ +
+
+
+
+
Branch
+ +
+
+
Assigned To
+ +
+
+
+ + +
+
+
@@ -3831,6 +3915,18 @@ df('Created', formatDate(a.created_at)) + df('Updated', formatDate(a.updated_at)); + // Photo + const photoCard = document.getElementById('detailPhotoCard'); + const photoImg = document.getElementById('detailPhotoImg'); + if (a.photo_path) { + photoCard.style.display = 'block'; + photoImg.src = a.photo_path; + photoImg.onload = () => { photoImg.style.display = 'inline'; }; + photoImg.onerror = () => { photoCard.style.display = 'none'; }; + } else { + photoCard.style.display = 'none'; + } + // Location / Directions const hasDir = a.address || a.building_name || a.building_number || a.floor || a.room || a.trailer_number || a.walking_directions || a.map_link || a.parking_location; const dirCard = document.getElementById('detailDirections'); @@ -4016,6 +4112,34 @@ }).catch(() => {}); } + // ── Photo viewer ────────────────────────────────────────────────── + function openPhotoModal() { + const img = document.getElementById('detailPhotoImg'); + const modal = document.getElementById('photoModal'); + const modalImg = document.getElementById('photoModalImg'); + if (!img || !modal || !modalImg) return; + modalImg.src = img.src; + modal.style.display = 'flex'; + document.body.style.overflow = 'hidden'; + } + function closePhotoModal(event) { + if (event && event.target && event.target.id !== 'photoModal' && event.target.id !== 'photoModalImg' && event.target.tagName !== 'SPAN') return; + const modal = document.getElementById('photoModal'); + if (modal) { + modal.style.display = 'none'; + document.body.style.overflow = ''; + } + } + document.addEventListener('keydown', function(e) { + if (e.key === 'Escape') { + const modal = document.getElementById('photoModal'); + if (modal && modal.style.display === 'flex') { + modal.style.display = 'none'; + document.body.style.overflow = ''; + } + } + }); + async function navigateToAsset(mode) { mode = mode || 'driving'; if (!AppState.currentAssetId) { @@ -4497,81 +4621,252 @@ } + // ── Map filter state ────────────────────────────────────────────────── + let mapFilters = { category: null, status: null, make: null, disney_park: null, disney_filter: null, q: '', + customer_id: null, location_id: null, assigned_to: null, branch: null }; + let mapFilterDropdownsLoaded = false; + + function toggleMapFilterPanel() { + const panel = document.getElementById('mapFilterPanel'); + const toggle = document.getElementById('mapFilterToggle'); + panel.classList.toggle('open'); + toggle.classList.toggle('active', panel.classList.contains('open')); + if (panel.classList.contains('open') && !mapFilterDropdownsLoaded) { + loadMapFilterDropdowns(); + } + } + + async function loadMapFilterDropdowns() { + if (mapFilterDropdownsLoaded) return; + mapFilterDropdownsLoaded = true; + var panel = document.getElementById('mapFilterPanel'); + var loadingMsg = document.createElement('div'); + loadingMsg.className = 'loading-spinner'; + loadingMsg.innerHTML = ' Loading filters...'; + panel.appendChild(loadingMsg); + try { + var cats = await api('/api/categories'); + document.getElementById('mapFilterCategory').innerHTML = '' + + cats.map(function(c) { return ''; }).join(''); + + var makes = await api('/api/makes'); + document.getElementById('mapFilterMake').innerHTML = '' + + makes.map(function(m) { return ''; }).join(''); + + var customers = await api('/api/customers'); + document.getElementById('mapFilterCustomer').innerHTML = '' + + customers.map(function(c) { return ''; }).join(''); + + var users = await api('/api/users'); + document.getElementById('mapFilterAssignedTo').innerHTML = '' + + users.filter(function(u) { return u.role === 'technician' || u.role === 'admin'; }) + .map(function(u) { return ''; }).join(''); + + var branches = await api('/api/branches'); + document.getElementById('mapFilterBranch').innerHTML = '' + + branches.branches.map(function(b) { return ''; }).join(''); + } catch (e) { + showToast('Failed to load filter options', true); + } finally { + if (loadingMsg && loadingMsg.parentNode) loadingMsg.parentNode.removeChild(loadingMsg); + } + } + + function onMapFilterChange() { + mapFilters.category = document.getElementById('mapFilterCategory').value || null; + mapFilters.make = document.getElementById('mapFilterMake').value || null; + + var disneyFilterVal = document.getElementById('mapFilterDisneyFilter').value; + if (disneyFilterVal) { + mapFilters.disney_filter = disneyFilterVal; + mapFilters.disney_park = null; + } else { + var parkVal = document.getElementById('mapFilterDisneyPark').value; + mapFilters.disney_park = parkVal || null; + mapFilters.disney_filter = null; + } + mapFilters.customer_id = document.getElementById('mapFilterCustomer').value || null; + + var locEl = document.getElementById('mapFilterLocation'); + var prevCust = locEl.dataset.customerId; + var custEl = document.getElementById('mapFilterCustomer'); + if (custEl.value !== prevCust) { + locEl.innerHTML = ''; + locEl.disabled = true; + mapFilters.location_id = null; + if (custEl.value) { + loadMapLocationsForCustomer(custEl.value); + } + } else { + mapFilters.location_id = locEl.value || null; + } + locEl.dataset.customerId = custEl.value; + + mapFilters.assigned_to = document.getElementById('mapFilterAssignedTo').value || null; + mapFilters.branch = document.getElementById('mapFilterBranch').value || null; + + renderMapActiveFilterTags(); + applyMapFilter(); + } + + async function loadMapLocationsForCustomer(customerId) { + try { + var locations = await api('/api/locations?customer_id=' + customerId); + var locEl = document.getElementById('mapFilterLocation'); + locEl.innerHTML = '' + + locations.map(function(l) { return ''; }).join(''); + locEl.disabled = false; + } catch (e) { showToast('Failed to load locations', true); } + } + + function getMapActiveFilterCount() { + var count = 0; + if (mapFilters.category) count++; + if (mapFilters.make) count++; + if (mapFilters.disney_park) count++; + if (mapFilters.disney_filter) count++; + if (mapFilters.customer_id) count++; + if (mapFilters.location_id) count++; + if (mapFilters.assigned_to) count++; + if (mapFilters.branch) count++; + if (mapFilters.q) count++; + return count; + } + + function renderMapActiveFilterTags() { + var el = document.getElementById('mapActiveFilters'); + var countEl = document.getElementById('mapFilterCount'); + var toggle = document.getElementById('mapFilterToggle'); + var count = getMapActiveFilterCount(); + + countEl.textContent = count; + countEl.style.display = count > 0 ? 'inline' : 'none'; + if (toggle) toggle.classList.toggle('active', count > 0); + + var tags = []; + if (mapFilters.q) tags.push({key:'q', label:'🔍 "' + mapFilters.q + '"'}); + if (mapFilters.category) tags.push({key:'category', label:'📂 ' + mapFilters.category}); + if (mapFilters.make) tags.push({key:'make', label:'🏭 ' + mapFilters.make}); + if (mapFilters.disney_park) tags.push({key:'disney_park', label: parkIcon(mapFilters.disney_park) + ' ' + parkName(mapFilters.disney_park)}); + if (mapFilters.disney_filter === 'disney') tags.push({key:'disney_filter', label:'🏰 Disney only'}); + if (mapFilters.disney_filter === 'non_disney') tags.push({key:'disney_filter', label:'🏢 Non-Disney'}); + if (mapFilters.customer_id) { + var custSel = document.getElementById('mapFilterCustomer'); + var txt = custSel.options[custSel.selectedIndex] ? custSel.options[custSel.selectedIndex].text : 'Customer'; + tags.push({key:'customer_id', label:'🟢 ' + txt}); + } + if (mapFilters.location_id) { + var locSel = document.getElementById('mapFilterLocation'); + var txt = locSel.options[locSel.selectedIndex] ? locSel.options[locSel.selectedIndex].text : 'Location'; + tags.push({key:'location_id', label:'📍 ' + txt}); + } + if (mapFilters.assigned_to) tags.push({key:'assigned_to', label:'👤 ' + mapFilters.assigned_to}); + if (mapFilters.branch) tags.push({key:'branch', label:'🏢 ' + mapFilters.branch}); + + el.innerHTML = tags.map(function(t) { + return '' + esc(t.label) + ' '; + }).join(''); + } + + function removeMapFilter(key) { + if (key === 'q') { + document.getElementById('mapSearchInput').value = ''; + mapFilters.q = ''; + } else if (key === 'category') { + document.getElementById('mapFilterCategory').value = ''; + mapFilters.category = null; + } else if (key === 'make') { + document.getElementById('mapFilterMake').value = ''; + mapFilters.make = null; + } else if (key === 'disney_park') { + document.getElementById('mapFilterDisneyPark').value = ''; + mapFilters.disney_park = null; + } else if (key === 'disney_filter') { + document.getElementById('mapFilterDisneyFilter').value = ''; + mapFilters.disney_filter = null; + } else if (key === 'customer_id') { + document.getElementById('mapFilterCustomer').value = ''; + document.getElementById('mapFilterLocation').innerHTML = ''; + document.getElementById('mapFilterLocation').disabled = true; + mapFilters.customer_id = null; + mapFilters.location_id = null; + } else if (key === 'location_id') { + document.getElementById('mapFilterLocation').value = ''; + mapFilters.location_id = null; + } else if (key === 'assigned_to') { + document.getElementById('mapFilterAssignedTo').value = ''; + mapFilters.assigned_to = null; + } else if (key === 'branch') { + document.getElementById('mapFilterBranch').value = ''; + mapFilters.branch = null; + } + renderMapActiveFilterTags(); + applyMapFilter(); + } + + function clearMapFilters() { + mapFilters = { category: null, status: null, make: null, disney_park: null, disney_filter: null, q: '', + customer_id: null, location_id: null, assigned_to: null, branch: null }; + document.getElementById('mapSearchInput').value = ''; + document.getElementById('mapFilterCategory').value = ''; + document.getElementById('mapFilterMake').value = ''; + document.getElementById('mapFilterDisneyPark').value = ''; + document.getElementById('mapFilterDisneyFilter').value = ''; + document.getElementById('mapFilterCustomer').value = ''; + document.getElementById('mapFilterLocation').innerHTML = ''; + document.getElementById('mapFilterLocation').disabled = true; + document.getElementById('mapFilterAssignedTo').value = ''; + document.getElementById('mapFilterBranch').value = ''; + renderMapActiveFilterTags(); + applyMapFilter(); + } + async function loadAssetPins() { - // Store markers on a namespace so we can clear them if (!window._assetPins) window._assetPins = []; - // Clear existing markers window._assetPins.forEach(function(m) { if (map) map.removeLayer(m); }); window._assetPins = []; try { const assets = await api('/api/assets?has_gps=true&limit=2000'); _mapAllAssets = assets; - buildMapFilterChips(assets); - // Apply current filter applyMapFilter(); } catch (e) { console.error('Failed to load asset pins:', e); + showToast('Failed to load map assets — ' + (e.message || 'connection error'), true); } } - function buildMapFilterChips(assets) { - var cats = {}; var statuses = {}; - assets.forEach(function(a) { - if (a.category) cats[a.category] = (cats[a.category] || 0) + 1; - if (a.status) statuses[a.status] = (statuses[a.status] || 0) + 1; - }); - var catKeys = Object.keys(cats).sort(); - var statusKeys = Object.keys(statuses).sort(); - var html = ''; - html += 'All'; - catKeys.forEach(function(c) { - html += '' + esc(c) + ' (' + cats[c] + ')'; - }); - html += 'All Status'; - statusKeys.forEach(function(s) { - html += '' + esc(s) + ''; - }); - document.getElementById('mapFilterChips').innerHTML = html; - } - - function mapSetCategory(cat) { - _mapActiveCategory = _mapActiveCategory === cat ? '' : cat; - _mapActiveStatus = ''; - applyMapFilter(); - buildMapFilterChips(_mapAllAssets); - } - - function mapSetStatus(status) { - _mapActiveStatus = _mapActiveStatus === status ? '' : status; - _mapActiveCategory = ''; - applyMapFilter(); - buildMapFilterChips(_mapAllAssets); - } - function mapDebounceFilter() { if (_mapFilterTimer) clearTimeout(_mapFilterTimer); + mapFilters.q = (document.getElementById('mapSearchInput').value || '').toLowerCase().trim(); + renderMapActiveFilterTags(); _mapFilterTimer = setTimeout(applyMapFilter, 200); } function applyMapFilter() { if (_mapFilterTimer) { clearTimeout(_mapFilterTimer); _mapFilterTimer = null; } - var q = (document.getElementById('mapSearchInput').value || '').toLowerCase().trim(); + var q = mapFilters.q; // Clear existing pins window._assetPins.forEach(function(m) { if (map) map.removeLayer(m); }); window._assetPins = []; var matched = []; - _mapAllAssets.forEach(function(a) { + var allAssets = _mapAllAssets || []; + allAssets.forEach(function(a) { // Category filter - if (_mapActiveCategory && a.category !== _mapActiveCategory) return; - // Status filter - if (_mapActiveStatus && a.status !== _mapActiveStatus) return; + if (mapFilters.category && a.category !== mapFilters.category) return; + // Make filter + if (mapFilters.make && a.make !== mapFilters.make) return; + // Disney/non-disney filter + if (mapFilters.disney_filter === 'disney' && !a.is_disney) return; + if (mapFilters.disney_filter === 'non_disney' && a.is_disney) return; + // Disney park filter + if (mapFilters.disney_park && a.disney_park !== mapFilters.disney_park) return; // Text search if (q) { - var haystack = ((a.name || '') + ' ' + (a.machine_id || '') + ' ' + (a.category || '') + ' ' + (a.description || '')).toLowerCase(); + var haystack = ((a.name || '') + ' ' + (a.machine_id || '') + ' ' + (a.category || '') + ' ' + (a.company || '') + ' ' + (a.description || '')).toLowerCase(); if (haystack.indexOf(q) === -1) return; } matched.push(a); @@ -4619,7 +4914,6 @@ el.innerHTML = '
📦 No assets match your search
'; return; } - // Sort by name var sorted = assets.slice().sort(function(a, b) { return (a.name || '').localeCompare(b.name || ''); }); var html = ''; sorted.forEach(function(a) { diff --git a/static/sw.js b/static/sw.js index e2caaf5..b10e404 100644 --- a/static/sw.js +++ b/static/sw.js @@ -3,7 +3,7 @@ // Caches app shell + CDN deps. Network-first for API, cache fallback for static. // ═══════════════════════════════════════════════════════════════════════════ -const CACHE_NAME = 'canteen-v6'; +const CACHE_NAME = 'canteen-v7'; // App shell — core resources needed to boot the PWA const APP_SHELL = [ diff --git a/tests/test_map_frontend.py b/tests/test_map_frontend.py index 994c9ea..09e02cb 100644 --- a/tests/test_map_frontend.py +++ b/tests/test_map_frontend.py @@ -142,8 +142,8 @@ class TestGPSControls: assert "GPS location not available" in body() def test_pins_chip_ui(self): - """Pin toggle chip exists.""" - assert "chipPins" in body() + """🎯 Filters toggle button exists in map tab.""" + assert "mapFilterToggle" in body() class TestHeatmap: