Authentication: - Add App.vue login gate (v-if auth.loading / v-else-if !auth.user / router-view) - Fix auth.checkSession with try/finally to always reset loading - Fix generate_keys method name for Frappe v16 (generate_keys, not generate_keys_for_api_user) - Auto-generate API token on cookie-based auth (Authentik SSO support) - Remove duplicate checkSession from DispatchV2Page (was causing infinite mount/unmount loop) GPS Tracking — Hybrid REST + WebSocket: - Initial REST fetch per-device in parallel (Traccar API only supports one deviceId per request) - WebSocket real-time updates via wss://dispatch.gigafibre.ca/traccar/api/socket - Auto-fallback to 30s polling if WebSocket fails, with exponential backoff reconnect - Module-level guards (__gpsStarted, __gpsPolling) to prevent loops on component remount - Only update tech.gpsCoords when value actually changes (prevents unnecessary reactive triggers) Tech Management (GPS Modal): - Add/delete technicians directly from GPS modal → persists to ERPNext - Inline edit: double-click name to rename, phone field, status select - Auto-generate technician_id (TECH-N+1) - Unlink jobs before delete to avoid ERPNext LinkExistsError - Added phone/email custom fields to Dispatch Technician doctype Infrastructure: - Nginx proxy: /api/ → ERPNext (same-origin, eliminates all CORS issues) - Nginx proxy: /traccar/ WebSocket support (Upgrade headers, 86400s timeout) - No-cache headers on index.html and sw.js for instant PWA updates - BASE_URL switched to empty string in production (same-origin via proxy) Bug fixes: - ERPNext Number Card PostgreSQL fix (ORDER BY on aggregate queries) - Traccar fetchPositions: parallel per-device calls (API ignores multiple deviceId params) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
76 lines
2.0 KiB
JavaScript
76 lines
2.0 KiB
JavaScript
/* eslint-env node */
|
|
const { configure } = require('quasar/wrappers')
|
|
|
|
module.exports = configure(function (ctx) {
|
|
return {
|
|
boot: ['pinia'],
|
|
|
|
css: ['app.scss'],
|
|
|
|
extras: ['roboto-font', 'material-icons'],
|
|
|
|
build: {
|
|
target: {
|
|
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
|
|
node: 'node20',
|
|
},
|
|
vueRouterMode: 'hash',
|
|
// Base path = where the app is deployed under ERPNext
|
|
// Change this if you move the app to a different path
|
|
extendViteConf (viteConf) {
|
|
viteConf.base = process.env.DEPLOY_BASE || '/assets/dispatch-app/'
|
|
},
|
|
},
|
|
|
|
devServer: {
|
|
open: false,
|
|
// Listen on all interfaces so the container port is reachable from the host
|
|
host: '0.0.0.0',
|
|
port: 9000,
|
|
proxy: {
|
|
// Proxy ERPNext API calls to the frontend container
|
|
// host.docker.internal resolves to the Docker host on Mac / Windows
|
|
'/api': {
|
|
target: 'http://host.docker.internal:8080',
|
|
changeOrigin: true,
|
|
cookieDomainRewrite: 'localhost',
|
|
},
|
|
'/assets': {
|
|
target: 'http://host.docker.internal:8080',
|
|
changeOrigin: true,
|
|
},
|
|
},
|
|
},
|
|
|
|
framework: {
|
|
config: {},
|
|
// Only load what we actually use — add more as needed
|
|
plugins: ['Notify', 'Loading', 'LocalStorage'],
|
|
},
|
|
|
|
animations: [],
|
|
|
|
pwa: {
|
|
workboxMode: 'generateSW',
|
|
injectPwaMetaTags: true,
|
|
swFilename: 'sw.js',
|
|
manifestFilename: 'manifest.json',
|
|
useCredentialForManifestTag: false,
|
|
workboxOptions: {
|
|
skipWaiting: true,
|
|
clientsClaim: true,
|
|
},
|
|
extendManifestJson (json) {
|
|
json.name = 'Dispatch'
|
|
json.short_name = 'Dispatch'
|
|
json.description = 'Dispatch & Field Service'
|
|
json.display = 'standalone'
|
|
json.orientation = 'portrait'
|
|
json.background_color = '#ffffff'
|
|
json.theme_color = '#6366f1'
|
|
json.start_url = '.'
|
|
},
|
|
},
|
|
}
|
|
})
|