@fleetbase/fleetops-engine 0.6.70 → 0.6.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RELEASE.md +18 -47
- package/addon/components/admin/tracking-page-settings.hbs +56 -0
- package/addon/components/admin/tracking-page-settings.js +67 -0
- package/addon/components/device/form.hbs +2 -2
- package/addon/components/driver/details.hbs +1 -1
- package/addon/components/driver/form.hbs +1 -1
- package/addon/components/equipment/form.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +11 -3
- package/addon/components/maintenance/form.hbs +3 -3
- package/addon/components/map/google-live-map.js +2 -2
- package/addon/components/map/leaflet-live-map.js +45 -32
- package/addon/components/orchestrator/phase-builder.js +2 -1
- package/addon/components/orchestrator-workbench.hbs +7 -1
- package/addon/components/orchestrator-workbench.js +16 -2
- package/addon/components/order/details/activity.hbs +8 -6
- package/addon/components/order/details/activity.js +9 -0
- package/addon/components/order/details.hbs +29 -0
- package/addon/components/order/details.js +26 -0
- package/addon/components/order/form/details.hbs +30 -4
- package/addon/components/order/form/details.js +46 -0
- package/addon/components/order/form/route.hbs +5 -3
- package/addon/components/order/form/route.js +24 -1
- package/addon/components/order/form.hbs +12 -0
- package/addon/components/order/form.js +21 -1
- package/addon/components/order/kanban.js +72 -0
- package/addon/components/order-config-manager/activity-flow.js +45 -10
- package/addon/components/order-config-manager/lifecycle.hbs +250 -0
- package/addon/components/order-config-manager/lifecycle.js +358 -0
- package/addon/components/order-config-manager.js +5 -1
- package/addon/components/service-rate/details.hbs +1 -1
- package/addon/components/service-rate/form.hbs +1 -1
- package/addon/components/tracking-page/full-view.hbs +276 -0
- package/addon/components/tracking-page/full-view.js +474 -0
- package/addon/components/tracking-page/locale-selector.js +30 -0
- package/addon/components/tracking-page/map.hbs +44 -0
- package/addon/components/tracking-page/map.js +328 -0
- package/addon/components/tracking-page/order-list.hbs +35 -0
- package/addon/components/tracking-page/public-view.hbs +60 -0
- package/addon/components/tracking-page/settings-preview.hbs +21 -0
- package/addon/components/tracking-page/settings-preview.js +23 -0
- package/addon/components/tracking-page/verify-panel.hbs +109 -0
- package/addon/components/tracking-page.hbs +142 -0
- package/addon/components/tracking-page.js +564 -0
- package/addon/components/trailer/form.hbs +2 -2
- package/addon/components/vehicle/form.hbs +3 -3
- package/addon/components/warranty/form.hbs +2 -2
- package/addon/components/widget/live-fleet.js +54 -6
- package/addon/components/widget/proof-of-delivery.hbs +49 -0
- package/addon/components/widget/proof-of-delivery.js +62 -0
- package/addon/components/work-order/form.hbs +3 -3
- package/addon/controllers/analytics/reports/index.js +10 -1
- package/addon/controllers/connectivity/devices/index/details.js +1 -0
- package/addon/controllers/connectivity/devices/index.js +8 -2
- package/addon/controllers/connectivity/events/index.js +31 -1
- package/addon/controllers/connectivity/sensors/index/details.js +1 -1
- package/addon/controllers/connectivity/sensors/index.js +37 -1
- package/addon/controllers/maintenance/equipment/index/details.js +2 -2
- package/addon/controllers/maintenance/equipment/index.js +28 -9
- package/addon/controllers/maintenance/inspection-forms/index.js +32 -12
- package/addon/controllers/maintenance/inspection-submissions/index/details.js +2 -1
- package/addon/controllers/maintenance/inspection-submissions/index.js +49 -9
- package/addon/controllers/maintenance/maintenances/index/details.js +2 -0
- package/addon/controllers/maintenance/maintenances/index.js +20 -1
- package/addon/controllers/maintenance/parts/index/details.js +2 -2
- package/addon/controllers/maintenance/parts/index.js +28 -8
- package/addon/controllers/maintenance/schedules/index.js +33 -4
- package/addon/controllers/maintenance/work-orders/index/details.js +3 -3
- package/addon/controllers/maintenance/work-orders/index.js +39 -8
- package/addon/controllers/management/contacts/customers.js +13 -0
- package/addon/controllers/management/contacts/index.js +43 -1
- package/addon/controllers/management/drivers/index/details.js +1 -0
- package/addon/controllers/management/drivers/index.js +32 -2
- package/addon/controllers/management/fleets/index/details.js +1 -0
- package/addon/controllers/management/fleets/index.js +39 -1
- package/addon/controllers/management/fuel-reports/index.js +22 -2
- package/addon/controllers/management/fuel-transactions/index.js +43 -7
- package/addon/controllers/management/issues/index/details.js +1 -0
- package/addon/controllers/management/issues/index.js +22 -2
- package/addon/controllers/management/places/index.js +36 -1
- package/addon/controllers/management/trailers/index/details.js +1 -0
- package/addon/controllers/management/trailers/index.js +50 -2
- package/addon/controllers/management/vehicles/index/details.js +1 -0
- package/addon/controllers/management/vehicles/index.js +33 -2
- package/addon/controllers/management/vendors/index.js +26 -2
- package/addon/controllers/operations/orders/index/details.js +50 -7
- package/addon/controllers/operations/orders/index.js +59 -4
- package/addon/controllers/operations/scheduler/index.js +45 -14
- package/addon/controllers/operations/service-rates/index.js +15 -1
- package/addon/controllers/settings/index.js +6 -0
- package/addon/controllers/settings/map.js +75 -0
- package/addon/controllers/settings/orchestrator.js +8 -6
- package/addon/controllers/settings/tracking-page.js +212 -0
- package/addon/extension.js +97 -1
- package/addon/helpers/parcel-box-image.js +16 -0
- package/addon/routes/operations/orders/index/details.js +1 -0
- package/addon/routes/operations/orders/index/new.js +5 -4
- package/addon/routes/operations/scheduler/index.js +1 -1
- package/addon/routes/settings/tracking-page.js +31 -0
- package/addon/routes.js +1 -0
- package/addon/services/contact-actions.js +1 -0
- package/addon/services/customer-actions.js +2 -1
- package/addon/services/device-actions.js +1 -0
- package/addon/services/device-event-actions.js +1 -0
- package/addon/services/driver-actions.js +4 -13
- package/addon/services/equipment-actions.js +1 -0
- package/addon/services/fleet-actions.js +1 -0
- package/addon/services/fuel-report-actions.js +1 -0
- package/addon/services/inspection-form-actions.js +1 -0
- package/addon/services/inspection-submission-actions.js +1 -0
- package/addon/services/integrated-vendor-actions.js +1 -0
- package/addon/services/issue-actions.js +1 -0
- package/addon/services/location.js +69 -21
- package/addon/services/maintenance-actions.js +1 -0
- package/addon/services/maintenance-schedule-actions.js +2 -1
- package/addon/services/map-settings.js +28 -0
- package/addon/services/order-actions.js +7 -0
- package/addon/services/order-allocation.js +1 -1
- package/addon/services/order-presentation.js +129 -0
- package/addon/services/part-actions.js +1 -0
- package/addon/services/place-actions.js +1 -0
- package/addon/services/sensor-actions.js +1 -0
- package/addon/services/service-area-actions.js +1 -0
- package/addon/services/service-rate-actions.js +1 -0
- package/addon/services/telematic-actions.js +1 -0
- package/addon/services/trailer-actions.js +4 -14
- package/addon/services/vehicle-actions.js +4 -13
- package/addon/services/vendor-actions.js +1 -0
- package/addon/services/work-order-actions.js +1 -0
- package/addon/services/zone-actions.js +1 -0
- package/addon/styles/fleetops-engine.css +1391 -0
- package/addon/templates/analytics/reports/index/details.hbs +1 -0
- package/addon/templates/analytics/reports/index.hbs +1 -0
- package/addon/templates/connectivity/devices/index/details.hbs +1 -0
- package/addon/templates/connectivity/devices/index.hbs +1 -0
- package/addon/templates/connectivity/events/index.hbs +1 -0
- package/addon/templates/connectivity/sensors/index/details.hbs +1 -0
- package/addon/templates/connectivity/sensors/index.hbs +1 -0
- package/addon/templates/maintenance/equipment/index/details.hbs +1 -0
- package/addon/templates/maintenance/equipment/index.hbs +2 -0
- package/addon/templates/maintenance/inspection-forms/index/details.hbs +1 -0
- package/addon/templates/maintenance/inspection-forms/index.hbs +1 -0
- package/addon/templates/maintenance/inspection-submissions/index/details.hbs +1 -0
- package/addon/templates/maintenance/inspection-submissions/index.hbs +1 -0
- package/addon/templates/maintenance/maintenances/index/details.hbs +1 -0
- package/addon/templates/maintenance/maintenances/index.hbs +1 -0
- package/addon/templates/maintenance/parts/index/details.hbs +1 -0
- package/addon/templates/maintenance/parts/index.hbs +2 -0
- package/addon/templates/maintenance/schedules/index/details.hbs +1 -0
- package/addon/templates/maintenance/schedules/index.hbs +2 -0
- package/addon/templates/maintenance/work-orders/index/details.hbs +1 -0
- package/addon/templates/maintenance/work-orders/index.hbs +1 -0
- package/addon/templates/management/contacts/customers/details.hbs +1 -0
- package/addon/templates/management/contacts/customers.hbs +1 -0
- package/addon/templates/management/contacts/index/details.hbs +1 -0
- package/addon/templates/management/contacts/index.hbs +1 -0
- package/addon/templates/management/contacts.hbs +1 -0
- package/addon/templates/management/drivers/index/details.hbs +1 -0
- package/addon/templates/management/drivers/index.hbs +2 -0
- package/addon/templates/management/fleets/index/details.hbs +1 -0
- package/addon/templates/management/fleets/index.hbs +1 -0
- package/addon/templates/management/fuel-reports/index/details.hbs +1 -0
- package/addon/templates/management/fuel-reports/index.hbs +1 -0
- package/addon/templates/management/fuel-transactions/index.hbs +1 -0
- package/addon/templates/management/issues/index/details.hbs +1 -0
- package/addon/templates/management/issues/index.hbs +1 -0
- package/addon/templates/management/places/index/details.hbs +1 -0
- package/addon/templates/management/places/index.hbs +1 -0
- package/addon/templates/management/trailers/index/details.hbs +1 -0
- package/addon/templates/management/trailers/index.hbs +2 -0
- package/addon/templates/management/vehicles/index/details.hbs +1 -0
- package/addon/templates/management/vehicles/index.hbs +2 -0
- package/addon/templates/management/vendors/index/details.hbs +1 -0
- package/addon/templates/management/vendors/index.hbs +2 -0
- package/addon/templates/management/vendors/integrated.hbs +1 -0
- package/addon/templates/operations/orders/index/details.hbs +1 -0
- package/addon/templates/operations/orders/index.hbs +1 -0
- package/addon/templates/operations/service-rates/index/details.hbs +1 -0
- package/addon/templates/operations/service-rates/index.hbs +1 -0
- package/addon/templates/settings/map.hbs +46 -0
- package/addon/templates/settings/tracking-page.hbs +318 -0
- package/addon/utils/identity-cell-resource.js +2 -56
- package/addon/utils/map-default-view.js +132 -0
- package/addon/utils/normalize-order-config-flow.js +6 -1
- package/addon/utils/placeholder-images.js +4 -69
- package/addon/utils/resource-descriptors/assets.js +2 -57
- package/addon/utils/resource-descriptors/helpers.js +23 -122
- package/addon/utils/resource-descriptors/operations.js +2 -61
- package/addon/utils/resource-descriptors/people.js +3 -142
- package/addon/utils/resource-descriptors/shared.js +18 -0
- package/addon/utils/tracking-live-source.js +123 -0
- package/addon/utils/tracking-page-theme.js +123 -0
- package/app/components/admin/tracking-page-settings.js +1 -0
- package/app/components/tracking-page/full-view.js +1 -0
- package/app/components/tracking-page/locale-selector.js +1 -0
- package/app/components/tracking-page/map.js +1 -0
- package/app/components/tracking-page/order-list.js +1 -0
- package/app/components/tracking-page/public-view.js +1 -0
- package/app/components/tracking-page/settings-preview.js +1 -0
- package/app/components/tracking-page/verify-panel.js +1 -0
- package/app/components/tracking-page.js +1 -0
- package/app/components/widget/proof-of-delivery.js +1 -0
- package/app/controllers/settings/tracking-page.js +1 -0
- package/app/helpers/parcel-box-image.js +1 -0
- package/app/routes/settings/tracking-page.js +1 -0
- package/app/services/order-presentation.js +1 -0
- package/app/templates/settings/tracking-page.js +1 -0
- package/app/utils/map-default-view.js +1 -0
- package/app/utils/tracking-live-source.js +1 -0
- package/app/utils/tracking-page-theme.js +1 -0
- package/composer.json +2 -2
- package/extension.json +1 -1
- package/package.json +4 -4
- package/scripts/pest-bootstrap.php +4 -0
- package/server/config/fleetops.php +4 -0
- package/server/migrations/2026_10_08_000001_create_tracking_sessions_tables.php +51 -0
- package/server/migrations/2026_10_10_000001_add_trashed_index_to_device_events.php +40 -0
- package/server/migrations/2026_10_10_000002_add_trashed_index_to_positions.php +40 -0
- package/server/migrations/2026_10_12_000001_add_deleted_at_to_tracking_sessions_tables.php +32 -0
- package/server/resources/views/labels/default.php +2 -2
- package/server/resources/views/labels/entity-label.php +2 -2
- package/server/resources/views/labels/waypoint-label.php +2 -2
- package/server/src/Auth/Schemas/FleetOps.php +5 -0
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +1 -0
- package/server/src/Console/Commands/PruneTelematicsData.php +101 -26
- package/server/src/Events/OrderChanged.php +257 -0
- package/server/src/Events/OrderDriverUnassigned.php +68 -0
- package/server/src/Exceptions/OrderEditLockedException.php +32 -0
- package/server/src/Expansions/CompanyExpansion.php +3 -2
- package/server/src/Expansions/UserExpansion.php +12 -10
- package/server/src/Http/Controllers/Api/v1/CustomerController.php +108 -18
- package/server/src/Http/Controllers/Api/v1/DriverController.php +95 -10
- package/server/src/Http/Controllers/Api/v1/EntityController.php +66 -0
- package/server/src/Http/Controllers/Api/v1/FleetController.php +10 -4
- package/server/src/Http/Controllers/Api/v1/OrderController.php +139 -36
- package/server/src/Http/Controllers/Api/v1/PayloadController.php +76 -8
- package/server/src/Http/Controllers/Api/v1/PlaceController.php +3 -3
- package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +6 -32
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +5 -0
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +3 -0
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +10 -0
- package/server/src/Http/Controllers/Internal/v1/FleetController.php +16 -2
- package/server/src/Http/Controllers/Internal/v1/InspectionSubmissionController.php +13 -8
- package/server/src/Http/Controllers/Internal/v1/IssueController.php +2 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +4 -2
- package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +93 -11
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +118 -28
- package/server/src/Http/Controllers/Internal/v1/PositionController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/ProofController.php +55 -4
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +303 -10
- package/server/src/Http/Controllers/Internal/v1/TrailerController.php +1 -0
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +1 -0
- package/server/src/Http/Controllers/Public/TrackingController.php +518 -0
- package/server/src/Http/Filter/ContactFilter.php +1 -1
- package/server/src/Http/Filter/InspectionFormFilter.php +23 -0
- package/server/src/Http/Filter/InspectionSubmissionFilter.php +23 -0
- package/server/src/Http/Filter/MaintenanceFilter.php +23 -0
- package/server/src/Http/Filter/OrderFilter.php +39 -4
- package/server/src/Http/Filter/ProofFilter.php +18 -0
- package/server/src/Http/Filter/RouteFilter.php +18 -0
- package/server/src/Http/Filter/TelematicFilter.php +23 -0
- package/server/src/Http/Filter/WarrantyFilter.php +23 -0
- package/server/src/Http/Requests/CancelOrderRequest.php +2 -1
- package/server/src/Http/Resources/v1/Concerns/ResolvesPublicRelationFields.php +14 -1
- package/server/src/Http/Resources/v1/Index/Customer.php +18 -0
- package/server/src/Http/Resources/v1/Index/Order.php +11 -2
- package/server/src/Http/Resources/v1/PublicOrderTracking.php +153 -0
- package/server/src/Http/Resources/v1/TrackingNumber.php +8 -34
- package/server/src/Http/Resources/v1/Zone.php +31 -23
- package/server/src/Jobs/FinalizeApiOrderCreation.php +3 -1
- package/server/src/Jobs/ProcessAllocationJob.php +16 -6
- package/server/src/Jobs/PublishTrackingUpdate.php +50 -0
- package/server/src/Listeners/HandleGeofenceEntered.php +31 -15
- package/server/src/Listeners/HandleOrderCanceled.php +9 -1
- package/server/src/Listeners/HandleUserRemovedFromCompany.php +2 -1
- package/server/src/Listeners/PublishTrackingUpdates.php +27 -0
- package/server/src/Mail/CustomerCredentialsMail.php +4 -2
- package/server/src/Models/AssetConnection.php +3 -0
- package/server/src/Models/Contact.php +3 -0
- package/server/src/Models/Device.php +28 -0
- package/server/src/Models/DeviceEvent.php +7 -0
- package/server/src/Models/Driver.php +20 -7
- package/server/src/Models/Entity.php +12 -4
- package/server/src/Models/Fleet.php +11 -32
- package/server/src/Models/FleetDriver.php +3 -0
- package/server/src/Models/FleetVehicle.php +3 -0
- package/server/src/Models/FuelReport.php +5 -13
- package/server/src/Models/Issue.php +4 -16
- package/server/src/Models/Order.php +234 -11
- package/server/src/Models/OrderConfig.php +129 -0
- package/server/src/Models/Payload.php +227 -35
- package/server/src/Models/Place.php +7 -1
- package/server/src/Models/ServiceArea.php +7 -0
- package/server/src/Models/ServiceRate.php +7 -17
- package/server/src/Models/TrackingNumber.php +109 -6
- package/server/src/Models/TrackingSession.php +33 -0
- package/server/src/Models/TrackingSessionGrant.php +22 -0
- package/server/src/Models/TrackingStatus.php +6 -0
- package/server/src/Models/Vehicle.php +21 -2
- package/server/src/Models/Vendor.php +7 -0
- package/server/src/Models/Waypoint.php +13 -4
- package/server/src/Notifications/OrderAssigned.php +2 -1
- package/server/src/Notifications/OrderCanceled.php +7 -1
- package/server/src/Notifications/OrderChanged.php +87 -0
- package/server/src/Notifications/OrderCompleted.php +2 -1
- package/server/src/Notifications/OrderDispatchFailed.php +2 -1
- package/server/src/Notifications/OrderDispatched.php +2 -1
- package/server/src/Notifications/OrderFailed.php +2 -1
- package/server/src/Notifications/OrderUnassigned.php +66 -0
- package/server/src/Notifications/WaypointCompleted.php +2 -1
- package/server/src/Observers/CompanyUserObserver.php +8 -7
- package/server/src/Observers/DriverObserver.php +6 -1
- package/server/src/Observers/OrderObserver.php +141 -1
- package/server/src/Observers/TrackingNumberObserver.php +18 -6
- package/server/src/Observers/UserObserver.php +2 -1
- package/server/src/Observers/VehicleObserver.php +8 -3
- package/server/src/Orchestration/Engines/RouteSequencingEngine.php +21 -3
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +38 -8
- package/server/src/Orchestration/OrchestrationEngineRegistry.php +61 -1
- package/server/src/Orchestration/Support/OrchestratorSettings.php +61 -0
- package/server/src/Orchestration/Support/RouteMetrics.php +165 -0
- package/server/src/Providers/EventServiceProvider.php +11 -0
- package/server/src/Providers/FleetOpsServiceProvider.php +13 -0
- package/server/src/Support/ApiCacheThrottle.php +76 -0
- package/server/src/Support/LiveOrderQuery.php +3 -1
- package/server/src/Support/OrderEdit.php +365 -0
- package/server/src/Support/OrderEditPolicy.php +292 -0
- package/server/src/Support/ProfileAccountManager.php +54 -1
- package/server/src/Support/ResolvesOrderServiceStops.php +5 -0
- package/server/src/Support/SocketChannels.php +346 -0
- package/server/src/Support/Telematics/TelematicService.php +7 -2
- package/server/src/Support/Telematics/Telemetry/Inbox.php +8 -1
- package/server/src/Support/TrackingChannel.php +55 -0
- package/server/src/Support/TrackingCode.php +242 -0
- package/server/src/Support/TrackingPage/TrackingAccess.php +356 -0
- package/server/src/Support/TrackingPage/TrackingPageConfig.php +264 -0
- package/server/src/Support/TrackingPage/TrackingRecipient.php +111 -0
- package/server/src/Support/TrackingPage/TrackingResolver.php +201 -0
- package/server/src/Support/TrackingPage/TrackingTarget.php +40 -0
- package/server/src/Support/TrackingPage/TrackingView.php +543 -0
- package/server/src/Support/TrackingPublisher.php +261 -0
- package/server/src/Support/TrackingScope.php +182 -0
- package/server/src/Support/TrackingUpdate.php +402 -0
- package/server/src/Support/Utils.php +15 -3
- package/server/src/Traits/HasTrackingNumber.php +2 -0
- package/server/src/routes.php +39 -7
- package/server/tests/ApiCustomerControllerContractsTest.php +54 -7
- package/server/tests/ApiDriverPasswordContractsTest.php +25 -21
- package/server/tests/ApiEntityControllerContractsTest.php +84 -0
- package/server/tests/ApiOrderControllerContractsTest.php +245 -0
- package/server/tests/ApiPayloadControllerContractsTest.php +121 -0
- package/server/tests/ApiPlaceControllerContractsTest.php +1 -1
- package/server/tests/ApiTrackingNumberControllerContractsTest.php +6 -9
- package/server/tests/CompactResourceSerializationTest.php +23 -59
- package/server/tests/ControllerFilterContractsTest.php +1 -1
- package/server/tests/CustomerContactIdentitySafetyTest.php +1 -1
- package/server/tests/EventContractsTest.php +26 -60
- package/server/tests/ExpansionContractsTest.php +15 -2
- package/server/tests/Feature/Http/Api/CustomerControllerHelperSeamsTest.php +29 -3
- package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +23 -0
- package/server/tests/Feature/Http/Api/OrderControllerNearbyFiltersTest.php +16 -16
- package/server/tests/Feature/Http/Api/OrderControllerQueryFiltersTest.php +41 -14
- package/server/tests/Feature/Http/Api/TrackingNumberControllerHelpersTest.php +57 -22
- package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +23 -9
- package/server/tests/Feature/Http/Internal/OrchestrationControllerContractsTest.php +171 -1
- package/server/tests/Feature/Http/Internal/OrderControllerActivityFlowsTest.php +72 -0
- package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +110 -14
- package/server/tests/Feature/Http/Internal/OrderControllerCreateRecordTest.php +26 -0
- package/server/tests/Feature/Http/Internal/OrderControllerHelpersTest.php +7 -5
- package/server/tests/Feature/Http/Internal/PositionControllerReplayChannelTest.php +135 -0
- package/server/tests/Feature/Http/Internal/ProofControllerContractsTest.php +3 -3
- package/server/tests/Feature/Http/Internal/ProofControllerRecentTest.php +170 -0
- package/server/tests/Feature/Http/Public/TrackingControllerTest.php +495 -0
- package/server/tests/IndexCustomerPhotoTest.php +151 -0
- package/server/tests/ModelAccessorContractsTest.php +4 -3
- package/server/tests/NotificationAndMailContractsTest.php +5 -8
- package/server/tests/ObserverContractsTest.php +72 -10
- package/server/tests/OrderActivityFlowRegressionTest.php +3 -2
- package/server/tests/OrderConfigLifecycleTest.php +120 -0
- package/server/tests/OrderFilterExecutionTest.php +167 -2
- package/server/tests/ProcessAllocationJobContractsTest.php +20 -0
- package/server/tests/PublicOrderTrackingResourceTest.php +221 -0
- package/server/tests/QueueJobContractsTest.php +2 -1
- package/server/tests/RequestContractsTest.php +1 -1
- package/server/tests/RouteRegistrationExecutionTest.php +26 -0
- package/server/tests/RouteSequencingEngineTest.php +17 -0
- package/server/tests/SettingControllerContractsTest.php +110 -0
- package/server/tests/Support/TrackingPageDatabase.php +200 -0
- package/server/tests/TenantScopingTest.php +206 -0
- package/server/tests/TrackingPageSettingsTest.php +343 -0
- package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +51 -0
- package/server/tests/Unit/Events/OrderDispatchFailedTest.php +2 -1
- package/server/tests/Unit/Http/Filter/ContactFilterAddressTest.php +61 -0
- package/server/tests/Unit/Http/Resources/IndexOrderResourceTest.php +30 -0
- package/server/tests/Unit/Jobs/FinalizeApiOrderCreationDispatchGuardTest.php +266 -0
- package/server/tests/Unit/Listeners/HandleGeofenceEnteredTest.php +182 -22
- package/server/tests/Unit/Listeners/HandleUserRemovedFromCompanyTest.php +5 -0
- package/server/tests/Unit/Models/DriverAssignVehicleTest.php +81 -0
- package/server/tests/Unit/Models/FleetTest.php +4 -3
- package/server/tests/Unit/Models/OrderCancelReasonTest.php +143 -0
- package/server/tests/Unit/Models/OrderPayloadConfigAndDistanceTest.php +60 -0
- package/server/tests/Unit/Models/OrderPayloadRouteTest.php +4 -2
- package/server/tests/Unit/Models/PayloadTest.php +18 -4
- package/server/tests/Unit/Models/ServiceRatePersistenceAndServicabilityTest.php +2 -2
- package/server/tests/Unit/Models/TrackingNumberTest.php +67 -6
- package/server/tests/Unit/Models/VehicleTest.php +16 -2
- package/server/tests/Unit/Models/WaypointTest.php +4 -3
- package/server/tests/Unit/Notifications/OrderChangeNotificationsTest.php +59 -0
- package/server/tests/Unit/Notifications/TerminalOrderNotificationsTest.php +3 -3
- package/server/tests/Unit/Observers/DriverDeletionCleanupTest.php +158 -0
- package/server/tests/Unit/Observers/FleetOpsCompanyUserAndServiceAreaObserversTest.php +20 -0
- package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +3 -3
- package/server/tests/Unit/Observers/OrderAssignmentObserverTest.php +100 -0
- package/server/tests/Unit/Observers/OrderDeleteCascadeTest.php +213 -0
- package/server/tests/Unit/Observers/VehicleObserverDeleteTest.php +67 -0
- package/server/tests/Unit/Orchestration/EngineSelectionAndRouteMetricsTest.php +336 -0
- package/server/tests/Unit/Orchestration/Engines/VroomOrchestrationEngineLifecycleTest.php +8 -1
- package/server/tests/Unit/Support/ApiCacheDependenciesTest.php +347 -0
- package/server/tests/Unit/Support/OrderEditPolicyTest.php +156 -0
- package/server/tests/Unit/Support/OrderOperationsTest.php +514 -0
- package/server/tests/Unit/Support/OsrmProofAndIssueFilterTest.php +4 -3
- package/server/tests/Unit/Support/ProfileAccountManagerTest.php +141 -0
- package/server/tests/Unit/Support/QuerySeamsTest.php +5 -1
- package/server/tests/Unit/Support/SocketChannelsTest.php +396 -0
- package/server/tests/Unit/Support/TrackingChannelTest.php +232 -0
- package/server/tests/Unit/Support/TrackingCodeTest.php +186 -0
- package/server/tests/Unit/Support/TrackingPage/TrackingAccessTest.php +200 -0
- package/server/tests/Unit/Support/TrackingPage/TrackingRecipientTest.php +51 -0
- package/server/tests/Unit/Support/TrackingPage/TrackingResolverTest.php +181 -0
- package/server/tests/Unit/Support/TrackingPage/TrackingViewTest.php +479 -0
- package/server/tests/Unit/Support/TrackingPublisherTest.php +425 -0
- package/server/tests/Unit/Support/TrackingUpdateTest.php +363 -0
- package/server/tests/Unit/Support/UtilsAdditionalTest.php +9 -0
- package/server/tests/Unit/Support/UtilsGeoMatrixAndVendorTest.php +25 -0
- package/server/tests/VehicleResourceContractsTest.php +46 -0
- package/server/tests/VroomOrchestrationEngineTest.php +34 -1
- package/server/tests/ZoneGeofenceSettingsResourceTest.php +121 -0
- package/translations/ar-ae.yml +274 -0
- package/translations/bg-bg.yaml +274 -0
- package/translations/en-us.yaml +347 -0
- package/translations/es-pa.yaml +274 -0
- package/translations/fr-fr.yaml +274 -0
- package/translations/mn-mn.yaml +274 -0
- package/translations/pt-br.yaml +274 -0
- package/translations/ru-ru.yaml +276 -2
- package/translations/uk-ua.yaml +275 -1
- package/translations/vi-vn.yaml +274 -0
- package/addon/components/cell/contact-identity.hbs +0 -1
- package/addon/components/cell/customer-identity.hbs +0 -1
- package/addon/components/cell/driver-identity.hbs +0 -1
- package/addon/components/cell/fleet-identity.hbs +0 -1
- package/addon/components/cell/order-identity.hbs +0 -1
- package/addon/components/cell/place-identity.hbs +0 -1
- package/addon/components/cell/vehicle-identity.hbs +0 -1
- package/addon/components/cell/vendor-identity.hbs +0 -1
- package/addon/components/contact/pill.hbs +0 -24
- package/addon/components/contact/summary.hbs +0 -1
- package/addon/components/customer/pill.hbs +0 -24
- package/addon/components/customer/summary.hbs +0 -1
- package/addon/components/driver/pill.hbs +0 -24
- package/addon/components/driver/summary.hbs +0 -1
- package/addon/components/fleet/pill.hbs +0 -24
- package/addon/components/fleet/summary.hbs +0 -1
- package/addon/components/order/pill.hbs +0 -24
- package/addon/components/order/summary.hbs +0 -1
- package/addon/components/place/pill.hbs +0 -24
- package/addon/components/place/summary.hbs +0 -1
- package/addon/components/select-option/contact.hbs +0 -12
- package/addon/components/select-option/customer.hbs +0 -12
- package/addon/components/select-option/driver.hbs +0 -12
- package/addon/components/select-option/fleet.hbs +0 -12
- package/addon/components/select-option/order.hbs +0 -12
- package/addon/components/select-option/place.hbs +0 -12
- package/addon/components/select-option/vehicle.hbs +0 -12
- package/addon/components/select-option/vendor.hbs +0 -12
- package/addon/components/vehicle/pill.hbs +0 -24
- package/addon/components/vehicle/summary.hbs +0 -1
- package/addon/components/vendor/pill.hbs +0 -24
- package/addon/components/vendor/summary.hbs +0 -1
- package/app/components/cell/contact-identity.js +0 -1
- package/app/components/cell/customer-identity.js +0 -1
- package/app/components/cell/driver-identity.js +0 -1
- package/app/components/cell/fleet-identity.js +0 -1
- package/app/components/cell/order-identity.js +0 -1
- package/app/components/cell/place-identity.js +0 -1
- package/app/components/cell/vehicle-identity.js +0 -1
- package/app/components/cell/vendor-identity.js +0 -1
- package/app/components/contact/pill.js +0 -1
- package/app/components/contact/summary.js +0 -1
- package/app/components/customer/pill.js +0 -1
- package/app/components/customer/summary.js +0 -1
- package/app/components/driver/pill.js +0 -1
- package/app/components/driver/summary.js +0 -1
- package/app/components/fleet/pill.js +0 -1
- package/app/components/fleet/summary.js +0 -1
- package/app/components/order/pill.js +0 -1
- package/app/components/order/summary.js +0 -1
- package/app/components/place/pill.js +0 -1
- package/app/components/place/summary.js +0 -1
- package/app/components/select-option/contact.js +0 -1
- package/app/components/select-option/customer.js +0 -1
- package/app/components/select-option/driver.js +0 -1
- package/app/components/select-option/fleet.js +0 -1
- package/app/components/select-option/order.js +0 -1
- package/app/components/select-option/place.js +0 -1
- package/app/components/select-option/vehicle.js +0 -1
- package/app/components/select-option/vendor.js +0 -1
- package/app/components/vehicle/pill.js +0 -1
- package/app/components/vehicle/summary.js +0 -1
- package/app/components/vendor/pill.js +0 -1
- package/app/components/vendor/summary.js +0 -1
|
@@ -4,6 +4,7 @@ import { inject as service } from '@ember/service';
|
|
|
4
4
|
import { action, computed } from '@ember/object';
|
|
5
5
|
import { isNone } from '@ember/utils';
|
|
6
6
|
import { isValid as isValidDate } from 'date-fns';
|
|
7
|
+
import { later } from '@ember/runloop';
|
|
7
8
|
import { task } from 'ember-concurrency';
|
|
8
9
|
import isObject from '@fleetbase/ember-core/utils/is-object';
|
|
9
10
|
import isJson from '@fleetbase/ember-core/utils/is-json';
|
|
@@ -11,6 +12,9 @@ import createFullCalendarEventFromOrder from '../../../utils/create-full-calenda
|
|
|
11
12
|
import createFullCalendarEventFromScheduleItem from '../../../utils/create-full-calendar-event-from-schedule-item';
|
|
12
13
|
import toCalendarDate from '../../../utils/to-calendar-date';
|
|
13
14
|
|
|
15
|
+
// The ember-core socket service subscribes ~300 ms after listen() is called.
|
|
16
|
+
const SOCKET_SUBSCRIBE_SETTLE_MS = 500;
|
|
17
|
+
|
|
14
18
|
/**
|
|
15
19
|
* OperationsSchedulerIndexController
|
|
16
20
|
*
|
|
@@ -722,28 +726,55 @@ export default class OperationsSchedulerIndexController extends Controller {
|
|
|
722
726
|
// Real-Time Socket Subscriptions
|
|
723
727
|
// -------------------------------------------------------------------------
|
|
724
728
|
|
|
729
|
+
// Names of the socket channels this board opened, so teardown closes only those
|
|
730
|
+
// and leaves every other subscription (chat, notifications, ...) alone.
|
|
731
|
+
_socketChannelNames = new Set();
|
|
732
|
+
|
|
725
733
|
@action async subscribeToRealTimeUpdates() {
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
734
|
+
const drivers = this.drivers ?? [];
|
|
735
|
+
await Promise.all(
|
|
736
|
+
drivers.map((driver) => {
|
|
737
|
+
if (!driver?.id) return;
|
|
738
|
+
const channelName = `driver.${driver.id}`;
|
|
739
|
+
if (this._socketChannelNames.has(channelName)) return;
|
|
740
|
+
this._socketChannelNames.add(channelName);
|
|
741
|
+
return this.socket.listen(channelName, (payload) => this._handleDriverSocketEvent(payload));
|
|
742
|
+
})
|
|
743
|
+
);
|
|
732
744
|
}
|
|
733
745
|
|
|
734
746
|
@action unsubscribeFromRealTimeUpdates() {
|
|
735
|
-
|
|
736
|
-
|
|
747
|
+
const names = this._socketChannelNames;
|
|
748
|
+
this._socketChannelNames = new Set();
|
|
749
|
+
if (!this.socket || names.size === 0) return;
|
|
750
|
+
|
|
751
|
+
if (typeof this.socket.closeChannel === 'function') {
|
|
752
|
+
names.forEach((name) => this.socket.closeChannel(name));
|
|
753
|
+
return;
|
|
737
754
|
}
|
|
755
|
+
|
|
756
|
+
const remaining = this._closeOpenedChannels(names);
|
|
757
|
+
if (remaining.size === 0) return;
|
|
758
|
+
|
|
759
|
+
// The socket service subscribes after a short delay, so a channel requested just before
|
|
760
|
+
// teardown may not exist yet: sweep once more after that delay.
|
|
761
|
+
later(this, () => this._closeOpenedChannels(remaining), SOCKET_SUBSCRIBE_SETTLE_MS);
|
|
738
762
|
}
|
|
739
763
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
764
|
+
/**
|
|
765
|
+
* Close the socket's channels with the given names, except any the board has opened again
|
|
766
|
+
* since. Returns the names that had no channel yet.
|
|
767
|
+
*/
|
|
768
|
+
_closeOpenedChannels(names) {
|
|
769
|
+
const remaining = new Set([...names].filter((name) => !this._socketChannelNames.has(name)));
|
|
770
|
+
const channels = Array.isArray(this.socket.channels) ? this.socket.channels : [];
|
|
771
|
+
for (const channel of channels) {
|
|
772
|
+
if (!names.has(channel?.name) || this._socketChannelNames.has(channel.name)) continue;
|
|
773
|
+
remaining.delete(channel.name);
|
|
774
|
+
channel.close();
|
|
746
775
|
}
|
|
776
|
+
|
|
777
|
+
return remaining;
|
|
747
778
|
}
|
|
748
779
|
|
|
749
780
|
_handleDriverSocketEvent({ event, data } = {}) {
|
|
@@ -10,7 +10,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
10
10
|
@service intl;
|
|
11
11
|
|
|
12
12
|
/** query params */
|
|
13
|
-
@tracked queryParams = ['page', 'query', 'limit', 'sort', 'zone', 'service_area'];
|
|
13
|
+
@tracked queryParams = this.serviceRateActions.queryParamsFor(['page', 'query', 'limit', 'sort', 'zone', 'service_area']);
|
|
14
14
|
@tracked page = 1;
|
|
15
15
|
@tracked limit;
|
|
16
16
|
@tracked query;
|
|
@@ -20,11 +20,13 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
20
20
|
get actionButtons() {
|
|
21
21
|
return [
|
|
22
22
|
{
|
|
23
|
+
id: 'refresh',
|
|
23
24
|
icon: 'refresh',
|
|
24
25
|
onClick: this.serviceRateActions.refresh,
|
|
25
26
|
helpText: this.intl.t('common.refresh'),
|
|
26
27
|
},
|
|
27
28
|
{
|
|
29
|
+
id: 'create',
|
|
28
30
|
text: this.intl.t('common.new'),
|
|
29
31
|
type: 'primary',
|
|
30
32
|
icon: 'plus',
|
|
@@ -32,6 +34,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
32
34
|
permission: 'fleet-ops create service-rate',
|
|
33
35
|
},
|
|
34
36
|
{
|
|
37
|
+
id: 'export',
|
|
35
38
|
text: this.intl.t('common.export'),
|
|
36
39
|
icon: 'long-arrow-up',
|
|
37
40
|
iconClass: 'rotate-icon-45',
|
|
@@ -46,6 +49,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
46
49
|
get bulkActions() {
|
|
47
50
|
return [
|
|
48
51
|
{
|
|
52
|
+
id: 'bulk-delete',
|
|
49
53
|
label: 'Delete selected...',
|
|
50
54
|
class: 'text-red-500',
|
|
51
55
|
fn: this.serviceRateActions.bulkDelete,
|
|
@@ -58,6 +62,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
58
62
|
get columns() {
|
|
59
63
|
return [
|
|
60
64
|
{
|
|
65
|
+
id: 'public-id',
|
|
61
66
|
sticky: true,
|
|
62
67
|
label: this.intl.t('column.id'),
|
|
63
68
|
valuePath: 'public_id',
|
|
@@ -70,6 +75,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
70
75
|
filterComponent: 'filter/string',
|
|
71
76
|
},
|
|
72
77
|
{
|
|
78
|
+
id: 'service-name',
|
|
73
79
|
label: this.intl.t('column.service'),
|
|
74
80
|
valuePath: 'service_name',
|
|
75
81
|
cellComponent: 'table/cell/base',
|
|
@@ -78,6 +84,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
78
84
|
filterable: false,
|
|
79
85
|
},
|
|
80
86
|
{
|
|
87
|
+
id: 'service-area-name',
|
|
81
88
|
label: this.intl.t('column.service-area'),
|
|
82
89
|
valuePath: 'service_area.name',
|
|
83
90
|
cellComponent: 'cell/service-area-identity',
|
|
@@ -93,6 +100,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
93
100
|
model: 'service-area',
|
|
94
101
|
},
|
|
95
102
|
{
|
|
103
|
+
id: 'zone-name',
|
|
96
104
|
label: this.intl.t('column.zone'),
|
|
97
105
|
valuePath: 'zone.name',
|
|
98
106
|
cellComponent: 'cell/zone-identity',
|
|
@@ -107,6 +115,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
107
115
|
model: 'zone',
|
|
108
116
|
},
|
|
109
117
|
{
|
|
118
|
+
id: 'created-at',
|
|
110
119
|
label: this.intl.t('column.created-at'),
|
|
111
120
|
valuePath: 'createdAt',
|
|
112
121
|
sortParam: 'created_at',
|
|
@@ -116,6 +125,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
116
125
|
filterComponent: 'filter/date',
|
|
117
126
|
},
|
|
118
127
|
{
|
|
128
|
+
id: 'updated-at',
|
|
119
129
|
label: this.intl.t('column.updated-at'),
|
|
120
130
|
valuePath: 'updatedAt',
|
|
121
131
|
sortParam: 'updated_at',
|
|
@@ -126,6 +136,7 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
126
136
|
filterComponent: 'filter/date',
|
|
127
137
|
},
|
|
128
138
|
{
|
|
139
|
+
id: 'row-actions',
|
|
129
140
|
label: '',
|
|
130
141
|
cellComponent: 'table/cell/dropdown',
|
|
131
142
|
ddButtonText: false,
|
|
@@ -137,18 +148,21 @@ export default class OperationsServiceRatesIndexController extends Controller {
|
|
|
137
148
|
width: 60,
|
|
138
149
|
actions: [
|
|
139
150
|
{
|
|
151
|
+
id: 'view',
|
|
140
152
|
label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.service-rate') }),
|
|
141
153
|
icon: 'eye',
|
|
142
154
|
fn: this.serviceRateActions.transition.view,
|
|
143
155
|
permission: 'fleet-ops view service-rate',
|
|
144
156
|
},
|
|
145
157
|
{
|
|
158
|
+
id: 'edit',
|
|
146
159
|
label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.service-rate') }),
|
|
147
160
|
icon: 'pencil',
|
|
148
161
|
fn: this.serviceRateActions.transition.edit,
|
|
149
162
|
permission: 'fleet-ops view service-rate',
|
|
150
163
|
},
|
|
151
164
|
{
|
|
165
|
+
id: 'delete',
|
|
152
166
|
label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.service-rate') }),
|
|
153
167
|
icon: 'trash',
|
|
154
168
|
fn: this.serviceRateActions.delete,
|
|
@@ -28,6 +28,12 @@ export default class SettingsIndexController extends Controller {
|
|
|
28
28
|
description: 'Keep commerce, metadata, and visual conventions aligned.',
|
|
29
29
|
links: [
|
|
30
30
|
{ label: 'Payments', route: 'settings.payments', icon: 'cash-register', description: 'Payment setup for operational commerce workflows.' },
|
|
31
|
+
{
|
|
32
|
+
label: 'Tracking Page',
|
|
33
|
+
route: 'settings.tracking-page',
|
|
34
|
+
icon: 'magnifying-glass-location',
|
|
35
|
+
description: 'The page your customers use to follow deliveries: address, branding and how they verify.',
|
|
36
|
+
},
|
|
31
37
|
{
|
|
32
38
|
label: 'Telematics',
|
|
33
39
|
route: 'settings.telematics',
|
|
@@ -4,6 +4,7 @@ import { inject as service } from '@ember/service';
|
|
|
4
4
|
import { action } from '@ember/object';
|
|
5
5
|
import { task } from 'ember-concurrency';
|
|
6
6
|
import MAP_PROVIDER_OPTIONS from '../../utils/map-provider-options';
|
|
7
|
+
import { isLatitude, isLongitude, isZoom, toCoordinate } from '../../utils/map-default-view';
|
|
7
8
|
|
|
8
9
|
export default class SettingsMapController extends Controller {
|
|
9
10
|
@service fetch;
|
|
@@ -11,6 +12,7 @@ export default class SettingsMapController extends Controller {
|
|
|
11
12
|
@service intl;
|
|
12
13
|
@service mapManager;
|
|
13
14
|
@service mapSettings;
|
|
15
|
+
@service location;
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Available map provider options for the provider selector.
|
|
@@ -39,6 +41,21 @@ export default class SettingsMapController extends Controller {
|
|
|
39
41
|
@tracked showGoogleMapsTrafficLayer = false;
|
|
40
42
|
@tracked showGoogleMapsTransitLayer = false;
|
|
41
43
|
|
|
44
|
+
/**
|
|
45
|
+
* The company's default live map view. Latitude and longitude are both
|
|
46
|
+
* set or both null; zoom is optional.
|
|
47
|
+
*/
|
|
48
|
+
@tracked defaultMapLatitude = null;
|
|
49
|
+
@tracked defaultMapLongitude = null;
|
|
50
|
+
@tracked defaultMapZoom = null;
|
|
51
|
+
@tracked fitMapToVehicles = false;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Bumped to re-create the coordinates input, which only reads its value
|
|
55
|
+
* when it is constructed (e.g. after clearing the default center).
|
|
56
|
+
*/
|
|
57
|
+
@tracked defaultCenterInputKey = 0;
|
|
58
|
+
|
|
42
59
|
/**
|
|
43
60
|
* Whether settings have been loaded from the server.
|
|
44
61
|
*
|
|
@@ -74,6 +91,36 @@ export default class SettingsMapController extends Controller {
|
|
|
74
91
|
return this.mapProvider === 'leaflet';
|
|
75
92
|
}
|
|
76
93
|
|
|
94
|
+
/**
|
|
95
|
+
* The default center as a GeoJSON point for the coordinates input, or null.
|
|
96
|
+
*
|
|
97
|
+
* @memberof SettingsMapController
|
|
98
|
+
* @return {Object|null}
|
|
99
|
+
*/
|
|
100
|
+
get defaultMapCenterPoint() {
|
|
101
|
+
// Not null: CoordinatesInput#isPoint reads `.type` on any object, and typeof null is "object".
|
|
102
|
+
if (!this.hasDefaultMapCenter) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { type: 'Point', coordinates: [this.defaultMapLongitude, this.defaultMapLatitude] };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get hasDefaultMapCenter() {
|
|
110
|
+
return isLatitude(this.defaultMapLatitude) && isLongitude(this.defaultMapLongitude);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The zoom to save: a whole number from 1 to 20, else null.
|
|
115
|
+
*
|
|
116
|
+
* @memberof SettingsMapController
|
|
117
|
+
* @return {Number|null}
|
|
118
|
+
*/
|
|
119
|
+
get normalizedDefaultMapZoom() {
|
|
120
|
+
const zoom = toCoordinate(this.defaultMapZoom);
|
|
121
|
+
return isZoom(zoom) ? zoom : null;
|
|
122
|
+
}
|
|
123
|
+
|
|
77
124
|
// ─── Actions ───────────────────────────────────────────────────────────────
|
|
78
125
|
|
|
79
126
|
/**
|
|
@@ -86,6 +133,24 @@ export default class SettingsMapController extends Controller {
|
|
|
86
133
|
this.mapProvider = option?.value ?? option ?? 'leaflet';
|
|
87
134
|
}
|
|
88
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Receives coordinates typed into, or picked on the map of, the default
|
|
138
|
+
* center input.
|
|
139
|
+
*
|
|
140
|
+
* @param {{latitude: *, longitude: *}} coordinates
|
|
141
|
+
* @memberof SettingsMapController
|
|
142
|
+
*/
|
|
143
|
+
@action setDefaultMapCenter({ latitude, longitude } = {}) {
|
|
144
|
+
this.defaultMapLatitude = toCoordinate(latitude);
|
|
145
|
+
this.defaultMapLongitude = toCoordinate(longitude);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@action clearDefaultMapCenter() {
|
|
149
|
+
this.defaultMapLatitude = null;
|
|
150
|
+
this.defaultMapLongitude = null;
|
|
151
|
+
this.defaultCenterInputKey++;
|
|
152
|
+
}
|
|
153
|
+
|
|
89
154
|
@task *saveSettings() {
|
|
90
155
|
const settings = {
|
|
91
156
|
mapProvider: this.mapProvider,
|
|
@@ -94,12 +159,19 @@ export default class SettingsMapController extends Controller {
|
|
|
94
159
|
googleMapsMapType: this.googleMapsMapType,
|
|
95
160
|
showGoogleMapsTrafficLayer: this.showGoogleMapsTrafficLayer,
|
|
96
161
|
showGoogleMapsTransitLayer: this.showGoogleMapsTransitLayer,
|
|
162
|
+
defaultMapLatitude: this.hasDefaultMapCenter ? this.defaultMapLatitude : null,
|
|
163
|
+
defaultMapLongitude: this.hasDefaultMapCenter ? this.defaultMapLongitude : null,
|
|
164
|
+
defaultMapZoom: this.normalizedDefaultMapZoom,
|
|
165
|
+
fitMapToVehicles: this.fitMapToVehicles,
|
|
97
166
|
};
|
|
98
167
|
|
|
99
168
|
try {
|
|
100
169
|
const response = yield this.fetch.post('fleet-ops/settings/map', { settings });
|
|
101
170
|
this.mapSettings.applySettings(response);
|
|
102
171
|
|
|
172
|
+
// Re-resolve where maps open so an open live map moves to the new default.
|
|
173
|
+
this.location.relocate();
|
|
174
|
+
|
|
103
175
|
if (this.mapManager && typeof this.mapManager.setActiveProvider === 'function') {
|
|
104
176
|
this.mapManager.setActiveProvider(this.mapProvider);
|
|
105
177
|
}
|
|
@@ -124,6 +196,9 @@ export default class SettingsMapController extends Controller {
|
|
|
124
196
|
this.googleMapsMapType = response?.googleMapsMapType ?? 'roadmap';
|
|
125
197
|
this.showGoogleMapsTrafficLayer = Boolean(response?.showGoogleMapsTrafficLayer);
|
|
126
198
|
this.showGoogleMapsTransitLayer = Boolean(response?.showGoogleMapsTransitLayer);
|
|
199
|
+
this.setDefaultMapCenter({ latitude: response?.defaultMapLatitude, longitude: response?.defaultMapLongitude });
|
|
200
|
+
this.defaultMapZoom = response?.defaultMapZoom ?? null;
|
|
201
|
+
this.fitMapToVehicles = Boolean(response?.fitMapToVehicles);
|
|
127
202
|
this.settingsLoaded = true;
|
|
128
203
|
} catch (error) {
|
|
129
204
|
this.notifications.serverError(error);
|
|
@@ -17,7 +17,8 @@ export default class SettingsOrchestratorController extends Controller {
|
|
|
17
17
|
@service intl;
|
|
18
18
|
@service('orchestration-engine') engineRegistry;
|
|
19
19
|
|
|
20
|
-
@tracked allocationEngine = '
|
|
20
|
+
@tracked allocationEngine = 'greedy';
|
|
21
|
+
@tracked serverEngines = null;
|
|
21
22
|
@tracked autoAllocateOnCreate = false;
|
|
22
23
|
@tracked autoReallocateOnComplete = false;
|
|
23
24
|
@tracked maxTravelTimeSeconds = 3600;
|
|
@@ -26,18 +27,19 @@ export default class SettingsOrchestratorController extends Controller {
|
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Engine options for the selector dropdown.
|
|
29
|
-
* Populated from the
|
|
30
|
-
*
|
|
30
|
+
* Populated from the engines registered on the server (the ones a run can
|
|
31
|
+
* actually use), falling back to the frontend allocation-engine registry.
|
|
31
32
|
*/
|
|
32
33
|
get engineOptions() {
|
|
33
|
-
return this.engineRegistry.availableEngines;
|
|
34
|
+
return this.serverEngines ?? this.engineRegistry.availableEngines;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
@task *loadSettings() {
|
|
37
38
|
this.isLoading = true;
|
|
38
39
|
try {
|
|
39
|
-
const settings = yield this.fetch.get('fleet-ops/settings/orchestrator-settings');
|
|
40
|
-
this.
|
|
40
|
+
const [settings, engines] = yield Promise.all([this.fetch.get('fleet-ops/settings/orchestrator-settings'), this.fetch.get('fleet-ops/orchestrator/engines').catch(() => null)]);
|
|
41
|
+
this.serverEngines = engines?.engines ?? null;
|
|
42
|
+
this.allocationEngine = settings.allocation_engine ?? 'greedy';
|
|
41
43
|
this.autoAllocateOnCreate = settings.auto_allocate_on_create ?? false;
|
|
42
44
|
this.autoReallocateOnComplete = settings.auto_reallocate_on_complete ?? false;
|
|
43
45
|
this.maxTravelTimeSeconds = settings.max_travel_time_seconds ?? 3600;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { task, timeout } from 'ember-concurrency';
|
|
6
|
+
import trackingPageTheme, { contrastRatio, inkFor, normalizeHex, DEFAULT_ACCENT } from '../../utils/tracking-page-theme';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The locales a tracking page can be shown in, labelled in their own language.
|
|
10
|
+
*/
|
|
11
|
+
export const TRACKING_PAGE_LOCALES = [
|
|
12
|
+
{ code: 'en-us', label: 'English' },
|
|
13
|
+
{ code: 'ar-ae', label: 'العربية' },
|
|
14
|
+
{ code: 'bg-bg', label: 'Български' },
|
|
15
|
+
{ code: 'es-pa', label: 'Español' },
|
|
16
|
+
{ code: 'fr-fr', label: 'Français' },
|
|
17
|
+
{ code: 'mn-mn', label: 'Монгол' },
|
|
18
|
+
{ code: 'pt-br', label: 'Português' },
|
|
19
|
+
{ code: 'ru-ru', label: 'Русский' },
|
|
20
|
+
{ code: 'uk-ua', label: 'Українська' },
|
|
21
|
+
{ code: 'vi-vn', label: 'Tiếng Việt' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Keys the server adds to the saved config when it reads it back. They are facts about
|
|
26
|
+
* the instance, not settings, so they are kept apart and never sent back on save.
|
|
27
|
+
*/
|
|
28
|
+
const READ_ONLY_KEYS = ['slug_validation', 'accent_ink', 'accent_contrast', 'sms_available', 'customer_portal_installed', 'admin'];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Settings::TrackingPageController
|
|
32
|
+
*
|
|
33
|
+
* The company's customer tracking page: which pages are on and at what address, branding,
|
|
34
|
+
* how customers prove who they are, and what verified customers see.
|
|
35
|
+
*/
|
|
36
|
+
export default class SettingsTrackingPageController extends Controller {
|
|
37
|
+
@service fetch;
|
|
38
|
+
@service notifications;
|
|
39
|
+
@service intl;
|
|
40
|
+
@service currentUser;
|
|
41
|
+
|
|
42
|
+
@tracked config = null;
|
|
43
|
+
@tracked slugValidation = null;
|
|
44
|
+
@tracked smsAvailable = false;
|
|
45
|
+
@tracked customerPortalInstalled = false;
|
|
46
|
+
@tracked loadFailed = false;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Take the settings as the server returns them.
|
|
50
|
+
*/
|
|
51
|
+
load(settings) {
|
|
52
|
+
if (!settings) {
|
|
53
|
+
this.loadFailed = true;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const config = { ...settings };
|
|
58
|
+
READ_ONLY_KEYS.forEach((key) => delete config[key]);
|
|
59
|
+
|
|
60
|
+
this.config = config;
|
|
61
|
+
this.slugValidation = settings.slug_validation ?? null;
|
|
62
|
+
this.smsAvailable = settings.sms_available === true;
|
|
63
|
+
this.customerPortalInstalled = settings.customer_portal_installed === true;
|
|
64
|
+
this.loadFailed = false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get accent() {
|
|
68
|
+
return normalizeHex(this.config?.branding?.accent) ?? DEFAULT_ACCENT;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get accentInk() {
|
|
72
|
+
return inkFor(this.accent);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get accentContrast() {
|
|
76
|
+
return contrastRatio(this.accent, this.accentInk);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get accentReadable() {
|
|
80
|
+
return this.accentContrast >= 4.5;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get previewLightStyle() {
|
|
84
|
+
return trackingPageTheme(this.config?.branding, false);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get previewDarkStyle() {
|
|
88
|
+
return trackingPageTheme(this.config?.branding, true);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get companyName() {
|
|
92
|
+
return this.currentUser.companyName ?? '';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get displayName() {
|
|
96
|
+
return this.config?.branding?.display_name || this.companyName;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get orgPageBase() {
|
|
100
|
+
return `${window.location.origin}/~/t/`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get orgPageUrl() {
|
|
104
|
+
return `${window.location.origin}/~/t/${encodeURIComponent(this.config?.org_page?.slug ?? '')}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get genericPageUrl() {
|
|
108
|
+
return `${window.location.origin}/~/track`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get slugIsValid() {
|
|
112
|
+
return this.slugValidation?.valid === true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
get localeOptions() {
|
|
116
|
+
const enabled = this.config?.branding?.locales ?? [];
|
|
117
|
+
const defaultLocale = this.config?.branding?.default_locale;
|
|
118
|
+
|
|
119
|
+
return TRACKING_PAGE_LOCALES.map((locale) => ({
|
|
120
|
+
...locale,
|
|
121
|
+
enabled: enabled.includes(locale.code),
|
|
122
|
+
isDefault: locale.code === defaultLocale,
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
get linkTargetOptions() {
|
|
127
|
+
return ['auto', 'org', 'generic'].map((value) => ({ value, label: this.intl.t(`tracking-page.settings.links-target-${value}`) }));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get themeOptions() {
|
|
131
|
+
return ['system', 'light'].map((value) => ({ value, label: this.intl.t(`tracking-page.settings.theme-${value}`) }));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get driverContactOptions() {
|
|
135
|
+
return ['company', 'driver'].map((value) => ({ value, label: this.intl.t(`tracking-page.settings.driver-contact-${value}`) }));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Set one value by its dotted path, replacing the config so the form and preview update.
|
|
140
|
+
*/
|
|
141
|
+
@action update(path, value) {
|
|
142
|
+
const config = JSON.parse(JSON.stringify(this.config));
|
|
143
|
+
const keys = path.split('.');
|
|
144
|
+
const last = keys.pop();
|
|
145
|
+
let target = config;
|
|
146
|
+
for (const key of keys) {
|
|
147
|
+
target = target[key];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
target[last] = value;
|
|
151
|
+
this.config = config;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@action updateFromEvent(path, event) {
|
|
155
|
+
this.update(path, event.target.value);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@action updateNumber(path, event) {
|
|
159
|
+
this.update(path, parseInt(event.target.value, 10));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@action selectOption(path, option) {
|
|
163
|
+
this.update(path, option?.value ?? option);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@action updateSlug(event) {
|
|
167
|
+
const slug = event.target.value.toLowerCase().replace(/\s+/g, '-');
|
|
168
|
+
this.update('org_page.slug', slug);
|
|
169
|
+
this.validateSlug.perform(slug);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@action toggleLocale(code) {
|
|
173
|
+
const locales = this.config.branding.locales ?? [];
|
|
174
|
+
if (code === this.config.branding.default_locale) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.update('branding.locales', locales.includes(code) ? locales.filter((locale) => locale !== code) : [...locales, code]);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@action setDefaultLocale(option) {
|
|
182
|
+
const code = option?.value ?? option;
|
|
183
|
+
const locales = this.config.branding.locales ?? [];
|
|
184
|
+
this.update('branding.default_locale', code);
|
|
185
|
+
if (!locales.includes(code)) {
|
|
186
|
+
this.update('branding.locales', [...locales, code]);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
get defaultLocaleOptions() {
|
|
191
|
+
return TRACKING_PAGE_LOCALES.map((locale) => ({ value: locale.code, label: locale.label }));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@task({ restartable: true }) *validateSlug(slug) {
|
|
195
|
+
yield timeout(350);
|
|
196
|
+
try {
|
|
197
|
+
this.slugValidation = yield this.fetch.post('fleet-ops/settings/tracking-page-settings/validate-slug', { slug });
|
|
198
|
+
} catch (error) {
|
|
199
|
+
this.notifications.serverError(error);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@task *saveSettings() {
|
|
204
|
+
try {
|
|
205
|
+
const settings = yield this.fetch.post('fleet-ops/settings/tracking-page-settings', { trackingPage: this.config });
|
|
206
|
+
this.load(settings);
|
|
207
|
+
this.notifications.success(this.intl.t('tracking-page.settings.saved'));
|
|
208
|
+
} catch (error) {
|
|
209
|
+
this.notifications.serverError(error);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|