Commit Graph

187 Commits

Author SHA1 Message Date
shawn 6322786fd2 fix: stop keyboard-loop on mobile camera failure + guard drawer behind login
- handleCameraError() now sets scanningActive=false and resets codeReader
  so ZXing can't fire more callbacks that re-create the manual input and
  re-focus it — mobile keyboard was popping repeatedly
- openDrawer() now checked loginOverlay.hidden before opening, so drawer
  can't appear behind the login screen
2026-06-01 22:46:38 -04:00
shawn 0f0aa1021a Fix UX-015: ZXing async callback silently swallows camera errors - add handleCameraError(), 5s cameraFailTimer, error branch in decodeFromVideoDevice callback 2026-06-01 22:11:12 -04:00
shawn d092abd91a UX fixes: admin link gating, GPS pulse timeout, ? shortcut overlay, offline queue, native confirm→modal 2026-06-01 22:01:23 -04:00
shawn a7b1887274 chore: Remove stale bak files from index 2026-06-01 21:23:07 -04:00
shawn b020665088 fix: Default to OCR mode on initial page load
- Fixed HTML initial state: OCR toggle button has 'active', OCR panel has 'active', barcode does not
- switchTab calls setAddAssetMode() which syncs visual panels AND starts the right camera
- Previously the JS variable was 'ocr' but HTML hardcoded barcode as active — visual mismatch
2026-06-01 21:22:25 -04:00
shawn 5ae9763f9a chore: Ignore .bak files, remove from tracking 2026-06-01 19:17:14 -04:00
shawn 50ba02e79e fix: Make work order detail modal scrollable
- Added max-height: 85vh to modal container
- Made modal-body scrollable (overflow-y: auto, flex shrink)
- Title and action buttons stay fixed while body scrolls
- Fixes 'too tall and not scrollable' when WO details have many items
2026-06-01 19:17:10 -04:00
shawn 4e4632ab3d chore: Remove accidentally committed DB backups 2026-06-01 19:12:24 -04:00
shawn 86975e2e2b feat: Default to OCR scanner, auto-start camera, hide viewport after capture
- Default add-asset mode changed from barcode to OCR
- Auto-start OCR camera when switching to OCR mode or Add Asset tab
- Camera viewport hidden entirely after photo capture (no placeholder showing)
- Retake button added to all OCR result states (found, not-found, error)
- 'Retake' resets UI and re-starts camera for a new photo
2026-06-01 19:12:01 -04:00
shawn 03cf4b9281 feat: Route tab overhaul + work order filters + Next Stop + Google Maps
- Added work order filter bar to Route tab matching the Work Orders tab UX:
  status, priority, work type dropdowns + date range selector
- Filter params passed to /api/workorders/today endpoint (backend updated
  with new query params: status, priority, work_type, date_range)
- Added Google Maps Navigate button on every route stop
- Added Mark Done & Next Stop button — tracks current stop index,
  marks completed stops with green check, advances to next with
  auto-prompt to open Google Maps navigation
- Animated stop progress: done stops dimmed with green ✓, current
  stop highlighted with accent border
- Updated /api/workorders/today to support date_range (week/month/all)
  and additional filter WHERE clauses
2026-06-01 13:10:37 -04:00
shawn 2d232941da Fix single checkin GET to include username via JOIN 2026-06-01 00:27:29 -04:00
shawn e325981b17 Fix check-in user tracking
- Backend: create_checkin now auto-resolves user_id from auth token
  when not provided in the request body
- Backend: list_checkins now JOINs users table to return username
  alongside each check-in
- Frontend: all 4 check-in functions now pass user_id from
  AppState.currentUser
- Frontend: check-in history shows 👤 username next to each entry
- Also made work order count clickable: shows WO detail modal
- Added work_orders list to MSFS asset response

Closes #62
2026-05-31 23:54:13 -04:00
shawn 07539b683e feat: add script to import machines from Cantaloupe Excel export
Adds scripts/import_from_excel.py that reads Cantaloupe .xlsx exports
and imports missing machines into the canteen-asset-tracker DB.
- Dry-run by default, --write to commit, --prod for production DB
- Maps all 62 spreadsheet columns to assets table schema
- Stores full raw row as JSON in seed_data table
- Backs up DB before import
2026-05-31 11:09:27 -04:00
shawn 8713169e84 feat: add My GPS button to asset detail GPS editor
Adds a '📍 My GPS' button to the GPS Map Editor card in the asset
detail screen that:
- Grabs device GPS via navigator.geolocation.getCurrentPosition
- Places map marker at current device position
- Auto-unlocks the GPS editor if locked, shows Save button
- Displays accuracy in status text
- Provides clear error messages for denied/timed-out/unavailable

Includes enableHighAccuracy: true, 15s timeout, 60s cache.
2026-05-31 09:53:23 -04:00
shawn 2a92c4e71b Swap all UI icons to game-icons SVGs via sprite
- Created SVG sprite with 49 game-icons symbols (58KB)
- Added .gi CSS class for icon sizing/fill
- Replaced 77 emoji in static HTML with <use href='#gi-{name}'>
- Skip <option> elements (can't render SVG there)
- Added JS gi() helper for 33 dynamic icon assignments
- Replaced 📍🔒🔓📷📋↕️⚠ in JS-driven content
- Zero network requests, zero console errors
- Pairs with existing CATEGORY_MAP game-icons SVGs
2026-05-31 02:40:52 -04:00
shawn cc4f3b7dcf Swap all category icons to game-icons
All 8 categories now use Game Icons from game-icons.net:
- Bev:     game-icons:soda-bottle (glass soda bottle)
- Snack:   game-icons:chips-bag (crinkly chip bag)
- Food:    game-icons:hamburger (stacked burger)
- Equip:   game-icons:wrench (adjustable wrench)
- Appl:    game-icons:cooler (ice chest)
- Markets: game-icons:shop (storefront with awning)
- Coffee:  game-icons:coffee-cup (paper cup with steam)
- Other:   game-icons:cargo-crate (industrial crate)

Zero external deps — inline SVGs from Iconify CDN
2026-05-31 02:26:01 -04:00
shawn dc11ac75d2 Swap Bev and Snack icons to game-icons
- Bev: hugeicons:soda-can → game-icons:soda-bottle
- Snack: mdi:chips → game-icons:chips-bag
- Other categories unchanged
2026-05-31 02:24:21 -04:00
shawn b444009593 Replace emoji icons with Iconify SVG icons
- Bev: hugeicons:soda-can (soda can with pull tab, outline style)
- Snack: mdi:chips (bag of chips)
- Food: mdi:hamburger
- Equipment: mdi:wrench
- Appliances: mdi:fridge-outline
- Markets: mdi:store
- Coffee: mdi:coffee
- Other: mdi:package-variant
- Removed stale <img guard in map sidebar rendering
- Added SVG sizing CSS for asset list icons
- Zero external deps — inline SVGs from Iconify CDN
2026-05-31 02:15:49 -04:00
shawn 18743ffdde Add GPS Map Editor to asset detail view
Add a GPS map editor card at the top of asset details, allowing users to
manually set an asset's GPS coordinates via an interactive Leaflet map.

- GPS card with Leaflet map and draggable marker
- 🔒 Lock/unlock toggle (locked by default when GPS exists)
- 💾 Save GPS button (visible only when unlocked)
- Saves via PUT /api/assets/{id} with lat/lng
- Click on map or drag marker to set position
- Fallback to Orlando coords (28.5383, -81.3792) when no GPS
- Auto-refresh detail view after save

Closes #61
2026-05-31 01:47:54 -04:00
shawn 064fc43fe3 fix: remove all address-geocoded GPS, keep only original check-ins
All GPS from MSFS account addresses and Cantaloupe seed data removed.
Only 5 authentic app check-in GPS entries remain.
Reverts the bulk restore from earlier commit (gps restore was address-based).
2026-05-31 01:45:53 -04:00
shawn 616769e805 feat: restore GPS data from pre-MSFS backup + MSFS account data
- 221 GPS entries restored via serial_number match from pre-MSFS backup
- 5,730 GPS entries restored via MSFS account address data
- Coverage improved from 1.6% (124) to 80.4% (6,075) of 7,560 assets
- Remaining 1,485 have no GPS in MSFS account records
2026-05-31 01:40:03 -04:00
shawn 55a21e981f Recategorize: Markets (🏪) replaces Kiosk; 106 coffee machines Bev→Coffee
- Renamed Kiosk category → Markets (includes 365 Retail Markets,
  Intuitivo, Panoptyc, Smart Market, Micro-Market-Ave C)
- Moved 106 coffee brands from Bev to Coffee: Nespresso (36),
  Curtis (23), Krea (14), EVERSYS (12), Bloomfield (6),
  Segafredo (4), Bravilor (4), Simonelli (2), Starbucks (2),
  Marco (2), Cafection Digi-cup (1)
- Updated CATEGORY_MAP
2026-05-31 01:09:40 -04:00
shawn fff2b6a52a feat: add Coffee category () — move 63 De Jong Duke / Impressions vending machines from Equipment
- New Coffee category with amber (#a16207) branding
- 63 coffee vending machines recategorized from Equipment
- CATEGORY_MAP updated in main app
2026-05-31 00:52:02 -04:00
shawn 955e489977 Add Kiosk category, re-categorize 207 assets, fix .gitignore
- New Kiosk category (🏪, purple) for 365 Retail Markets, Panoptyc, Intuitivo,
  Smart Market, Micro-Market — 1,100 assets moved from Equipment/Other
- CRANE (114) → Equipment (was wrongly 'Other')
- Vendo, Royal, DN, DIXIE NARCO (52) → Bev (beverage vending machines)
- USI (2) → Snack
- Cafection Digi-cup, Echostream, Purelogix, Avalon (4) → Bev
- CoolServ, Cold Snap, KoolTek (3) → Appliances (cooling/refrigeration)
- De Jong Duke, AC, Impressions, Lektro-Vend (11) → Equipment
- Remaining 'Other' reduced from 221 to 14 genuine unknowns
- Zero unmapped categories — Category Health clean
2026-05-31 00:40:21 -04:00
shawn f1a3bb9f00 feat: revised category icons + unknown type detection
- Cleaned CATEGORY_MAP: removed dead entries (Furniture, GF Bev,
  Snack/bev, Snack/food), fixed duplicate 'Food' key, proper
  distinct icons for all 6 real categories
- Added categoryInfo() helper: 🥤/🍿/🍔/🔧/🔌/📦 for known cats,
   (red) for unmapped categories, 📦 for null
- Updated all render sites (list, map pins, map list, detail view,
  scan result, OCR result) to use categoryInfo()
- Added category icons to detail view and scan/OCR result headers
- Synced categories DB table: added Equipment/Appliances with icons,
  removed unused Unknown
- Updated seed data in both server.py and admin_server.py to match
  real asset categories
- Added category_health to /api/stats with unmapped category detection
- Added Category Health card to admin dashboard (shown only when
  unmapped categories exist)
- Updated CSS backgrounds for all real categories + .cat-unmapped
2026-05-31 00:28:03 -04:00
shawn 5c2e15e28b ux: persist help overlay dismissed state via localStorage 2026-05-30 21:20:50 -04:00
shawn 474a618f79 UX fixes: fix Map tab crash, remove Edit/Delete buttons, update Help dialog and menu labels 2026-05-30 20:56:28 -04:00
shawn 9ae0f271ea chore: remove accidentally committed gps backup file 2026-05-29 23:17:53 -04:00
shawn 17b870e4cc feat: wire vision/OCR results back into asset records
- Auto-save photo_path to matched assets when photo uploaded via /api/ocr
- Auto-extract and save serial_number from OCR text to blank-serial matched assets
- Add _extract_serial_from_text helper for serial number pattern matching
- Create scripts/backfill_vision_photos.py for batch-processing unlinked photos
- Add docs/OCR_PIPELINE.md documenting the full OCR/vision pipeline
- Fix test DB schema: add connect_id, equipment_id, barcode, customer_name
- Fix OCR test assertions to match actual endpoint behavior
2026-05-29 10:03:51 -04:00
shawn 99cef94153 Cross-reference photos against assets DB
- Scanned all 15 photos in uploads/photos/ via vision + Tesseract OCR
- Matched keurig_label.jpg → Asset #5144 (machine_id 636671)
- Updated Asset #5144 photo_path in assets.db
- Created scripts/crossref_photos.py for reusable batch matching
- Reported unmatched IDs for coca_cola_label.jpg and telemetry_device.jpg
- Generated crossref_report.md with full findings
2026-05-29 09:56:49 -04:00
shawn e2db719fd7 docs: update OCR description to reflect Ollama vision primary 2026-05-29 09:00:27 -04:00
shawn b80ed4b483 feat: Ollama vision OCR via Windows PC for label photo matching
- Add persistent SSH tunnel (systemd service) to Windows PC Ollama
- Add _HAS_OLLAMA check at server startup (qwen2.5vl:3b)
- Replace Tesseract-only OCR with Ollama-first strategy
- Ollama (qwen2.5vl:3b) handles dark/complex labels Tesseract can't read
- Keurig serial 2500.0100.0025534 now correctly matched as Asset #5144
- Add ocr_source field to /api/ocr response ('ollama' or 'tesseract')
- Fix match_label_photo.py argparse bug (image_paths -> images)
- Update match_label_photo.py CLI to read vision key from Hermes config
2026-05-29 08:59:53 -04:00
shawn 8022c77b70 feat: add normalized matching for label photos → asset DB lookup
- normalize_identifier() strips dots/dashes/prefixes, keeps alphanumeric
- find_asset_by_normalized_id() searches serial_number, connect_id,
  equipment_id, barcode with normalized comparison
- /api/ocr now returns matched_assets in addition to legacy machine_id
- New /api/match-text endpoint for client-side text matching
- scripts/match_label_photo.py CLI tool for OCR + DB matching
- Vision model fixed (mimo-v2-omni at opencode.ai, was using
  truncated placeholder key)
2026-05-29 08:37:06 -04:00
shawn e10e226743 Add serial_number to barcode search
- /api/assets/search now also matches serial_number column
  so scanning a sticker with just the serial number works
2026-05-29 07:59:37 -04:00
shawn 8c8f8a261c Add 2D barcode scanning + connect_id search
- Add QR_CODE, DATA_MATRIX, PDF_417, AZTEC to barcode scanner hints
  so serial number stickers with 2D barcodes can be scanned
- Update /api/assets/search to also match connect_id so full
  Connect IDs (e.g. VM-05912-0000068454) work when scanned
- Bump SW cache v5→v6, footer v3.2→v3.3
2026-05-29 07:55:44 -04:00
shawn 2bdcfe0bae feat: branch fallback for assets without account linkage
- 1,606 more assets now get company from branch/territory name
  (e.g. 'Canteen Corp/Orlando, FL') when the connect_id exists
  in extraction DB but has no linked account name
- Coverage: 7,349/7,488 (98.1%) have company + customer_name
- Only 139 remain empty (4 prefixes not in branch cache)
- Updated AGENTS.md with data population docs
2026-05-29 07:51:02 -04:00
shawn 4f9c0d0b75 feat: populate company/place/customer_name from MSFS extraction DB
- New script: scripts/populate_asset_company_place.py maps connect_id →
  account name (company/customer_name) + city (place) + address via
  extraction DB (msdyn_customerasset + account join)
- 5,743/7,488 assets now have company + customer_name populated
- 5,647/7,488 assets now have place (city) populated
- Fix: SELECT COALESCE(c.name, a.customer_name) so stored customer_name
  isn't overridden to NULL when customer_id FK is missing
- Bump SW v4→v5, version v3.1→v3.2 to force cache refresh
2026-05-29 07:45:01 -04:00
shawn 5180d811a8 fix: add place/building/floor fields to main detail view
The detail view's Asset Details card was missing location fields
(place, building_name, building_number, floor, room, trailer_number)
that were visible in the list cards. Added them alongside Model
so building/floor info appears in the main card rather than only
in the collapsed Directions & Access section below.
2026-05-29 00:25:10 -04:00
shawn f1eb453a19 fix: keep GUEST/CAST visible in asset names
- clean_customer_name() no longer strips GUEST/CAST suffixes
- Re-ran migration: 967 asset names updated with GUEST/CAST preserved
- Format: '95301 - Animal Kingdom CAST / address / building'
  vs previous: '95301 - Animal Kingdom / address / building'
2026-05-29 00:13:08 -04:00
shawn 9ee8de8578 fix: add/find tab now lookup-only, nav fix, route techs fix
- Add/Find tab: removed check-in card and add-asset form, now pure lookup
- OCR: stop camera after capture, added GPS capture at photo time
- OCR: increased timeout from 8s to 15s to reduce 500 errors
- Nav tab: added GPS prompt + asset search when navigating directly
- Route: include all 26 techs from bookableresource table (not just Shawn)
2026-05-29 00:10:30 -04:00
shawn 1db6475f83 feat: asset naming, location extraction, and location display
- New asset naming: {MID} - {Customer} / {Address} / {Building details}
- Extracted 660 building_names from customer data (Disney resorts, hotels)
- 1,704 assets now have location data (building_name, floor, etc.)
- Location section in detail view now shows building, floor, trailer, room
- Added has_gps filter to API for map loading
- Added location_source column to track GPS origin
2026-05-28 23:58:56 -04:00
shawn ae3b114ebc feat: import Seed (mycantaloupe.com) data — 1,655 assets enriched
- Added import_seed.py — reads Machine List(8).xlsx, matches by Asset ID → machine_id
- 51 new columns on assets table (route, barcode, sales, contact info, etc.)
- seed_data table with full 62-field JSON per asset for detail enrichment
- Seed data card in frontend asset detail view
- GET /api/assets/{id} now returns result.seed and result.seed_imported_at
- GPS columns from Seed ignored per request
- 1,654 matched, 199 unmatched (Seed-only assets not in MSFS)

Refs #47
2026-05-28 23:28:08 -04:00
shawn 908c67a26c docs: update msfs-data-import.md after clean-slate reset
- Cleared all MSFS-derived (address-geocoded) GPS
- Only real field GPS (28 assets from photo EXIF) remains
- Documented backup locations and clean-slate process

Refs #46
2026-05-28 23:01:17 -04:00
shawn a8158566ac feat: OCR auto-saves GPS to asset + MSFS enrichment in detail view
OCR endpoint (/api/ocr) now auto-saves EXIF GPS from the photo
to the asset's latitude/longitude fields when they are blank,
so the first photo scan at a machine permanently records its location.

GET /api/assets/{id} now includes an 'msfs' block enriched from
the merged Dynamics 365 Field Service data (merged-assets.json)
loaded at server start (1,834 matched assets). Fields shown:
equipment_id, connect_id, compass_asset_number, manufacturer,
model_text, dex_model, install_date, software_version, etc.

Frontend updates:
- New 'Field Service Data' card in asset detail view when MSFS
  data is available (manufacturer, Connect ID, install date, etc.)
- '📍 GPS saved to asset' confirmation shown after OCR auto-save
- AppState.ocrGpsSaved flag to track the auto-save event
2026-05-28 22:28:34 -04:00
shawn 3a8f89432a fix: stray closing brace broke entire JS script + remove login gate for guest mode 2026-05-28 22:16:43 -04:00
shawn b07c30da5e docs: MSFS data import pipeline — extraction → merge → assets.db 2026-05-28 22:07:14 -04:00
shawn 77ffb0ab2a Remove unused exifr CDN from index.html 2026-05-28 22:04:27 -04:00
shawn 7c1ceafc6b Remove auth: fall back to default admin user when no token provided (field tool mode) 2026-05-28 22:03:58 -04:00
shawn f3d176116a Major app overhaul: MSFS data import, lookup-only Find tab, OSRM nav, cleanup 2026-05-28 21:57:58 -04:00
shawn a9f2f88604 ux: Increase map max-height from 60vh to 70vh for better square ratio 2026-05-27 19:51:45 -04:00