@fleetbase/fleetops-engine 0.6.71 → 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 +15 -18
- 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/form/route.hbs +1 -1
- package/addon/components/order/form/route.js +13 -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/operations/orders/index/details.js +19 -3
- package/addon/controllers/operations/scheduler/index.js +45 -14
- 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 +65 -1
- package/addon/helpers/parcel-box-image.js +16 -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/location.js +69 -21
- package/addon/services/map-settings.js +28 -0
- package/addon/services/order-allocation.js +1 -1
- package/addon/styles/fleetops-engine.css +1391 -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/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/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 +84 -24
- 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 +200 -9
- 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 +101 -2
- 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/OrderControllerContractsTest.php +110 -14
- 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/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/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 +287 -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
package/RELEASE.md
CHANGED
|
@@ -1,29 +1,26 @@
|
|
|
1
|
-
> v0.6.
|
|
1
|
+
> v0.6.72 ~ "Customer tracking page settings, safer public tracking and structured label codes"
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
## Highlights
|
|
5
5
|
|
|
6
|
-
- **
|
|
7
|
-
-
|
|
8
|
-
-
|
|
6
|
+
- **Tracking Page settings.** A new Fleet-Ops → Settings → Tracking Page lets each organization configure the customer tracking page:
|
|
7
|
+
- its own page at `/t/{slug}`, with a live address check;
|
|
8
|
+
- whether its numbers can be tracked on the shared page;
|
|
9
|
+
- branding: display name, accent colour with a live contrast check, an optional dark-mode accent, support contacts, "Powered by Fleetbase", and languages;
|
|
10
|
+
- how customers verify (text message or email codes, session length, customer sign-in);
|
|
11
|
+
- what verified customers see.
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
- **
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- **
|
|
16
|
-
- **The Order Configuration manager lists every config**, including configs created while the console is open.
|
|
17
|
-
- **An order's activity timeline follows status changes made on the server.**
|
|
18
|
-
- **Fix: the Activity Flow crashed on a flow with a cycle.**
|
|
19
|
-
- **Fix: order details now load the assigned vehicle with the order.**
|
|
20
|
-
- **Fix: the order form failed when its custom fields couldn't load.**
|
|
21
|
-
- **Fix: registered details tabs.** Opening a driver, vehicle or trailer side panel removed the route from tabs other extensions had registered, which broke them in the full details view. Side panels also left out the tabs they could render.
|
|
22
|
-
- **Fix: the sensor details view showed the tabs registered for places.**
|
|
13
|
+
Administrators set the shared page's defaults under Fleet-Ops Config → Tracking Page. The new tracking pages themselves arrive in a later release; these settings are what they will read.
|
|
14
|
+
- **Safer public order lookup.** `GET int/v1/fleet-ops/lookup` is rate limited per address and returns a minimal resource: tracking number, status, timeline, ETA, stop coordinates and items. It no longer returns notes, meta, internal ids, files, rates or customer details. The driver's location is included only while the order is under way. Unknown and malformed tracking numbers get the same answer.
|
|
15
|
+
- **Structured label codes.** Tracking-number QR codes now carry a tracking URL holding the tracking number and the owner's public id, which a phone camera opens as the tracking page. Barcodes use Code 128. Every scan endpoint still accepts the uuid codes already printed on parcels.
|
|
16
|
+
- **Fix: signatures on private S3 buckets.** Signatures were not stored on buckets that reject ACLs; they are now written without one and served through signed URLs. Legacy absolute avatar URLs on vehicles, drivers and places are re-signed when read.
|
|
17
|
+
- **Fix: the customer credentials email** linked to an unrouted page; it now links to `/customer-access/{slug}`.
|
|
18
|
+
- **Fix: parcel box images** on the service rate form and details showed broken images in production builds.
|
|
23
19
|
|
|
24
20
|
---
|
|
25
21
|
## Upgrading
|
|
26
|
-
|
|
22
|
+
- Run `php artisan fleetbase:create-permissions` to register the new `tracking-page-settings` permission.
|
|
23
|
+
- Private-bucket signature storage pairs with fleetbase/core-api's `File::signStoredUrl()`; on older core-api releases stored avatar URLs pass through unchanged.
|
|
27
24
|
|
|
28
25
|
---
|
|
29
26
|
## Need help?
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<ContentPanel @title="Generic Tracking Page" @open={{true}} @wrapperClass="bordered-classic">
|
|
2
|
+
<div class="space-y-5">
|
|
3
|
+
<div class="flex items-start justify-between gap-4">
|
|
4
|
+
<div>
|
|
5
|
+
<div class="text-sm font-semibold">Enable the generic tracking page</div>
|
|
6
|
+
<div class="text-xs text-gray-600 dark:text-gray-300">Serves /~/track for every organization that allows it. Organizations can also run their own page from their Fleet-Ops settings.</div>
|
|
7
|
+
</div>
|
|
8
|
+
<Toggle @isToggled={{this.genericEnabled}} @onToggle={{fn (mut this.genericEnabled)}} />
|
|
9
|
+
</div>
|
|
10
|
+
<div>
|
|
11
|
+
<label for="admin-tracking-page-name" class="block text-sm font-semibold mb-1">Display name</label>
|
|
12
|
+
<input id="admin-tracking-page-name" type="text" class="form-input w-full" value={{this.displayName}} placeholder="Fleetbase" {{on "input" (fn this.setValue "displayName")}} />
|
|
13
|
+
<p class="mt-1 text-xs text-gray-600 dark:text-gray-300">Shown before a lookup. The logo comes from the instance branding.</p>
|
|
14
|
+
</div>
|
|
15
|
+
<div>
|
|
16
|
+
<label for="admin-tracking-page-accent" class="block text-sm font-semibold mb-1">Accent colour</label>
|
|
17
|
+
<div class="flex items-center gap-3">
|
|
18
|
+
<input id="admin-tracking-page-accent" type="color" class="h-10 w-14 rounded-md border border-gray-300 dark:border-gray-700 bg-transparent cursor-pointer" value={{this.accent}} {{on "input" (fn this.setValue "accent")}} />
|
|
19
|
+
<span class="font-mono text-sm">{{this.accent}}</span>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
23
|
+
<div>
|
|
24
|
+
<label for="admin-tracking-page-phone" class="block text-sm font-semibold mb-1">Support phone</label>
|
|
25
|
+
<input id="admin-tracking-page-phone" type="tel" class="form-input w-full" value={{this.supportPhone}} placeholder="+1 555 010 0100" {{on "input" (fn this.setValue "supportPhone")}} />
|
|
26
|
+
</div>
|
|
27
|
+
<div>
|
|
28
|
+
<label for="admin-tracking-page-email" class="block text-sm font-semibold mb-1">Support email</label>
|
|
29
|
+
<input id="admin-tracking-page-email" type="email" class="form-input w-full" value={{this.supportEmail}} placeholder="support@example.com" {{on "input" (fn this.setValue "supportEmail")}} />
|
|
30
|
+
</div>
|
|
31
|
+
<div>
|
|
32
|
+
<label for="admin-tracking-page-website" class="block text-sm font-semibold mb-1">Website</label>
|
|
33
|
+
<input id="admin-tracking-page-website" type="url" class="form-input w-full" value={{this.website}} placeholder="https://example.com" {{on "input" (fn this.setValue "website")}} />
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="flex items-start justify-between gap-4">
|
|
37
|
+
<div>
|
|
38
|
+
<div class="text-sm font-semibold">Show "Powered by Fleetbase"</div>
|
|
39
|
+
<div class="text-xs text-gray-600 dark:text-gray-300">The default for organizations that haven't chosen.</div>
|
|
40
|
+
</div>
|
|
41
|
+
<Toggle @isToggled={{this.poweredBy}} @onToggle={{fn (mut this.poweredBy)}} />
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</ContentPanel>
|
|
45
|
+
|
|
46
|
+
<EmberWormhole @to="next-view-section-subheader-actions">
|
|
47
|
+
<Button
|
|
48
|
+
@type="primary"
|
|
49
|
+
@size="sm"
|
|
50
|
+
@icon="save"
|
|
51
|
+
@text="Save Changes"
|
|
52
|
+
@onClick={{perform this.saveSettings}}
|
|
53
|
+
@isLoading={{or this.saveSettings.isRunning this.loadSettings.isRunning}}
|
|
54
|
+
@disabled={{this.saveSettings.isRunning}}
|
|
55
|
+
/>
|
|
56
|
+
</EmberWormhole>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
import { tracked } from '@glimmer/tracking';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Instance-wide defaults for the generic customer tracking page: whether it is on, and the
|
|
9
|
+
* branding it shows before a lookup (and for companies without their own).
|
|
10
|
+
*/
|
|
11
|
+
export default class AdminTrackingPageSettingsComponent extends Component {
|
|
12
|
+
@service fetch;
|
|
13
|
+
@service notifications;
|
|
14
|
+
@tracked genericEnabled = true;
|
|
15
|
+
@tracked displayName = '';
|
|
16
|
+
@tracked accent = '#1F5FA8';
|
|
17
|
+
@tracked supportPhone = '';
|
|
18
|
+
@tracked supportEmail = '';
|
|
19
|
+
@tracked website = '';
|
|
20
|
+
@tracked poweredBy = true;
|
|
21
|
+
|
|
22
|
+
constructor() {
|
|
23
|
+
super(...arguments);
|
|
24
|
+
this.loadSettings.perform();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@task *loadSettings() {
|
|
28
|
+
try {
|
|
29
|
+
const settings = yield this.fetch.get('fleet-ops/settings/admin-tracking-page-settings');
|
|
30
|
+
this.genericEnabled = settings?.generic_page?.enabled ?? true;
|
|
31
|
+
this.displayName = settings?.branding?.display_name ?? '';
|
|
32
|
+
this.accent = settings?.branding?.accent ?? '#1F5FA8';
|
|
33
|
+
this.supportPhone = settings?.branding?.support_phone ?? '';
|
|
34
|
+
this.supportEmail = settings?.branding?.support_email ?? '';
|
|
35
|
+
this.website = settings?.branding?.website ?? '';
|
|
36
|
+
this.poweredBy = settings?.branding?.powered_by ?? true;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
this.notifications.serverError(error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@action setValue(property, event) {
|
|
43
|
+
this[property] = event.target.value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@task *saveSettings() {
|
|
47
|
+
try {
|
|
48
|
+
yield this.fetch.post('fleet-ops/settings/admin-tracking-page-settings', {
|
|
49
|
+
trackingPage: {
|
|
50
|
+
generic_page: { enabled: this.genericEnabled },
|
|
51
|
+
branding: {
|
|
52
|
+
display_name: this.displayName,
|
|
53
|
+
accent: this.accent,
|
|
54
|
+
support_phone: this.supportPhone,
|
|
55
|
+
support_email: this.supportEmail,
|
|
56
|
+
website: this.website,
|
|
57
|
+
powered_by: this.poweredBy,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
this.notifications.success('Tracking page defaults saved.');
|
|
63
|
+
} catch (error) {
|
|
64
|
+
this.notifications.serverError(error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
|
|
138
138
|
<InputGroup @name={{t "device.fields.installation-date"}}>
|
|
139
139
|
<DatePicker
|
|
140
|
-
@value={{@resource.installation_date}}
|
|
140
|
+
@value={{format-date-fns @resource.installation_date "yyyy-MM-dd"}}
|
|
141
141
|
@onChange={{fn (mut @resource.installation_date)}}
|
|
142
142
|
@placeholder={{t "device.fields.installation-date-placeholder"}}
|
|
143
143
|
@disabled={{cannot-write @resource}}
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
|
|
148
148
|
<InputGroup @name={{t "device.fields.last-maintenance-date"}}>
|
|
149
149
|
<DatePicker
|
|
150
|
-
@value={{@resource.last_maintenance_date}}
|
|
150
|
+
@value={{format-date-fns @resource.last_maintenance_date "yyyy-MM-dd"}}
|
|
151
151
|
@onChange={{fn (mut @resource.last_maintenance_date)}}
|
|
152
152
|
@placeholder={{t "device.fields.last-maintenance-date-placeholder"}}
|
|
153
153
|
@disabled={{cannot-write @resource}}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
</div>
|
|
28
28
|
<div class="field-info-container md:col-span-3">
|
|
29
29
|
<div class="field-name">{{t "driver.fields.license-expiry"}}</div>
|
|
30
|
-
<div class="field-value">{{n-a (format-date-fns @resource.license_expiry)}}</div>
|
|
30
|
+
<div class="field-value">{{n-a (format-date-fns @resource.license_expiry "yyyy-MM-dd")}}</div>
|
|
31
31
|
</div>
|
|
32
32
|
<div class="field-info-container">
|
|
33
33
|
<div class="field-name">{{t "resource.vehicle"}}</div>
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
|
|
67
67
|
<InputGroup @name={{t "driver.fields.license-expiry"}}>
|
|
68
68
|
<DatePicker
|
|
69
|
-
@value={{@resource.license_expiry}}
|
|
69
|
+
@value={{format-date-fns @resource.license_expiry "yyyy-MM-dd"}}
|
|
70
70
|
@onChange={{fn (mut @resource.license_expiry)}}
|
|
71
71
|
@placeholder={{t "driver.fields.license-expiry"}}
|
|
72
72
|
@disabled={{cannot-write @resource}}
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
</InputGroup>
|
|
160
160
|
<InputGroup @name="Purchase Date">
|
|
161
161
|
<DatePicker
|
|
162
|
-
@value={{or (format-date-fns @resource.purchased_at "
|
|
162
|
+
@value={{or (format-date-fns @resource.purchased_at "yyyy-MM-dd") null}}
|
|
163
163
|
@onChange={{fn (mut @resource.purchased_at)}}
|
|
164
164
|
@placeholder="DD-MM-YYYY"
|
|
165
165
|
class="filter-date-input w-full flex-1"
|
|
@@ -208,6 +208,13 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
208
208
|
this.createItem('menu.routing', 'route', 'settings.routing', 'fleet-ops view routing-settings', 'fleet-ops see routing-settings'),
|
|
209
209
|
this.createItem('menu.orchestrator', 'circle-nodes', 'settings.orchestrator', 'fleet-ops view routing-settings', 'fleet-ops see routing-settings'),
|
|
210
210
|
this.createItem('menu.scheduling', 'calendar-days', 'settings.scheduling', 'fleet-ops view scheduling-settings', 'fleet-ops see scheduling-settings'),
|
|
211
|
+
this.createItem(
|
|
212
|
+
'tracking-page.settings.menu',
|
|
213
|
+
'magnifying-glass-location',
|
|
214
|
+
'settings.tracking-page',
|
|
215
|
+
'fleet-ops view tracking-page-settings',
|
|
216
|
+
'fleet-ops see tracking-page-settings'
|
|
217
|
+
),
|
|
211
218
|
this.createItem('menu.telematics-settings', 'satellite-dish', 'settings.telematics', 'fleet-ops view telematics-settings', 'fleet-ops see telematics-settings'),
|
|
212
219
|
this.createItem('menu.custom-fields', 'pen-to-square', 'settings.custom-fields', 'fleet-ops list custom-field', 'fleet-ops see custom-field'),
|
|
213
220
|
this.createItem('menu.avatars', 'icons', 'settings.avatars', 'fleet-ops list avatar', 'fleet-ops see avatar'),
|
|
@@ -406,9 +413,10 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
406
413
|
'settings.routing': 5,
|
|
407
414
|
'settings.orchestrator': 6,
|
|
408
415
|
'settings.scheduling': 7,
|
|
409
|
-
'settings.
|
|
410
|
-
'settings.
|
|
411
|
-
'settings.
|
|
416
|
+
'settings.tracking-page': 8,
|
|
417
|
+
'settings.telematics': 9,
|
|
418
|
+
'settings.custom-fields': 10,
|
|
419
|
+
'settings.avatars': 11,
|
|
412
420
|
};
|
|
413
421
|
|
|
414
422
|
return priorities[route] ?? 0;
|
|
@@ -185,7 +185,7 @@
|
|
|
185
185
|
</div>
|
|
186
186
|
<InputGroup @name="Scheduled At">
|
|
187
187
|
<DatePicker
|
|
188
|
-
@value={{or (format-date-fns @resource.scheduled_at "
|
|
188
|
+
@value={{or (format-date-fns @resource.scheduled_at "yyyy-MM-dd") null}}
|
|
189
189
|
@onChange={{fn (mut @resource.scheduled_at)}}
|
|
190
190
|
@placeholder="DD-MM-YYYY"
|
|
191
191
|
class="filter-date-input w-full flex-1"
|
|
@@ -193,7 +193,7 @@
|
|
|
193
193
|
</InputGroup>
|
|
194
194
|
<InputGroup @name="Started At">
|
|
195
195
|
<DatePicker
|
|
196
|
-
@value={{or (format-date-fns @resource.started_at "
|
|
196
|
+
@value={{or (format-date-fns @resource.started_at "yyyy-MM-dd") null}}
|
|
197
197
|
@onChange={{fn (mut @resource.started_at)}}
|
|
198
198
|
@placeholder="DD-MM-YYYY"
|
|
199
199
|
class="filter-date-input w-full flex-1"
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
</InputGroup>
|
|
202
202
|
<InputGroup @name="Completed At">
|
|
203
203
|
<DatePicker
|
|
204
|
-
@value={{or (format-date-fns @resource.completed_at "
|
|
204
|
+
@value={{or (format-date-fns @resource.completed_at "yyyy-MM-dd") null}}
|
|
205
205
|
@onChange={{fn (mut @resource.completed_at)}}
|
|
206
206
|
@placeholder="DD-MM-YYYY"
|
|
207
207
|
class="filter-date-input w-full flex-1"
|
|
@@ -59,7 +59,7 @@ export default class MapGoogleLiveMapComponent extends Component {
|
|
|
59
59
|
const marker = this.mapManager.getMarker(driver.id);
|
|
60
60
|
if (!marker) {
|
|
61
61
|
const createdMarker = await this.mapManager.addMarker(driver.id, coords.lat, coords.lng, {
|
|
62
|
-
iconUrl: driver.vehicle_avatar ?? '/engines-dist/images/
|
|
62
|
+
iconUrl: driver.vehicle_avatar ?? '/engines-dist/images/map-marker.png',
|
|
63
63
|
iconSize: [20, 20],
|
|
64
64
|
title: driver.name,
|
|
65
65
|
tooltip: buildDriverLiveMapContent(driver),
|
|
@@ -89,7 +89,7 @@ export default class MapGoogleLiveMapComponent extends Component {
|
|
|
89
89
|
const marker = this.mapManager.getMarker(vehicle.id);
|
|
90
90
|
if (!marker) {
|
|
91
91
|
const createdMarker = await this.mapManager.addMarker(vehicle.id, coords.lat, coords.lng, {
|
|
92
|
-
iconUrl: vehicle.avatar_url ?? '/engines-dist/images/
|
|
92
|
+
iconUrl: vehicle.avatar_url ?? '/engines-dist/images/map-marker.png',
|
|
93
93
|
iconSize: [20, 20],
|
|
94
94
|
title: vehicle.displayName,
|
|
95
95
|
tooltip: buildVehicleLiveMapContent(vehicle),
|
|
@@ -12,6 +12,7 @@ import { task, timeout } from 'ember-concurrency';
|
|
|
12
12
|
import { next } from '@ember/runloop';
|
|
13
13
|
import getModelName from '@fleetbase/ember-core/utils/get-model-name';
|
|
14
14
|
import ensureLeafletPluginsReady, { hasLeafletPluginsReady } from '../../utils/leaflet-plugin-loader';
|
|
15
|
+
import { FIT_VEHICLES_MAX_ZOOM, isZoom, positionedBounds } from '../../utils/map-default-view';
|
|
15
16
|
|
|
16
17
|
export default class MapLeafletLiveMapComponent extends Component {
|
|
17
18
|
liveViewportReloadDebounceMs = 300;
|
|
@@ -243,9 +244,45 @@ export default class MapLeafletLiveMapComponent extends Component {
|
|
|
243
244
|
this.rebuildMapContextMenu();
|
|
244
245
|
}
|
|
245
246
|
|
|
247
|
+
/**
|
|
248
|
+
* When the company chose "Fit to my vehicles", frame every positioned
|
|
249
|
+
* vehicle before the first viewport-filtered load. With no positioned
|
|
250
|
+
* vehicles the map stays on the default view resolved by the location
|
|
251
|
+
* service.
|
|
252
|
+
*
|
|
253
|
+
* @return {Boolean} whether the view was fitted
|
|
254
|
+
*/
|
|
255
|
+
@task *fitToPositionedVehicles() {
|
|
256
|
+
if (!this.mapSettings.fitMapToVehicles || this.abilities.cannot('fleet-ops list vehicle')) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
const vehicles = yield this.fetch.get('fleet-ops/live/vehicles', { limit: this.liveViewportResourceLimit });
|
|
262
|
+
const bounds = positionedBounds(vehicles);
|
|
263
|
+
if (!bounds) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const options = { maxZoom: FIT_VEHICLES_MAX_ZOOM, padding: [40, 40], animate: false };
|
|
268
|
+
if (typeof this.mapManager.fitBounds === 'function' && this.mapManager.adapter) {
|
|
269
|
+
this.mapManager.fitBounds(bounds, options);
|
|
270
|
+
} else {
|
|
271
|
+
this.map?.fitBounds?.(bounds, options);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return true;
|
|
275
|
+
} catch (err) {
|
|
276
|
+
debug('Failed to fit live map to vehicles: ' + err.message);
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
246
281
|
/** load resources and wait for stuff here and trigger map ready **/
|
|
247
282
|
@task *load() {
|
|
248
283
|
try {
|
|
284
|
+
yield this.fitToPositionedVehicles.perform();
|
|
285
|
+
|
|
249
286
|
// Get initial map bounds for spatial filtering (provider-agnostic)
|
|
250
287
|
const mapBounds = this.mapManager.getBounds?.() ?? (this.map ? this.map.getBounds() : null);
|
|
251
288
|
const bounds = this.#serializeBoundsForRequest(mapBounds);
|
|
@@ -360,6 +397,11 @@ export default class MapLeafletLiveMapComponent extends Component {
|
|
|
360
397
|
if (typeof zoom === 'number' && !isNaN(zoom) && zoom >= 1 && zoom <= 20) {
|
|
361
398
|
return zoom;
|
|
362
399
|
}
|
|
400
|
+
// The company's default view (or a country centre) suggests its own zoom
|
|
401
|
+
const locationZoom = this.location.getZoom?.();
|
|
402
|
+
if (isZoom(locationZoom)) {
|
|
403
|
+
return locationZoom;
|
|
404
|
+
}
|
|
363
405
|
// Return default zoom of 14 if invalid
|
|
364
406
|
return 14;
|
|
365
407
|
}
|
|
@@ -428,6 +470,9 @@ export default class MapLeafletLiveMapComponent extends Component {
|
|
|
428
470
|
if (coordinates && typeof coordinates.latitude === 'number' && typeof coordinates.longitude === 'number') {
|
|
429
471
|
this.latitude = coordinates.latitude;
|
|
430
472
|
this.longitude = coordinates.longitude;
|
|
473
|
+
if (isZoom(coordinates.zoom) && !isZoom(this.args.zoom)) {
|
|
474
|
+
this.zoom = coordinates.zoom;
|
|
475
|
+
}
|
|
431
476
|
|
|
432
477
|
// Update map position if map is loaded
|
|
433
478
|
if (this.map && this.map.setView) {
|
|
@@ -860,36 +905,4 @@ export default class MapLeafletLiveMapComponent extends Component {
|
|
|
860
905
|
|
|
861
906
|
return contextmenuRegistry;
|
|
862
907
|
}
|
|
863
|
-
|
|
864
|
-
/**
|
|
865
|
-
* Safely gets a valid latitude value with fallback to default
|
|
866
|
-
* @returns {number} Valid latitude value
|
|
867
|
-
*/
|
|
868
|
-
#getValidLatitude() {
|
|
869
|
-
const lat = this.location.getLatitude();
|
|
870
|
-
|
|
871
|
-
// Validate latitude is a number and within valid range (-90 to 90)
|
|
872
|
-
if (typeof lat === 'number' && !isNaN(lat) && lat >= -90 && lat <= 90) {
|
|
873
|
-
return lat;
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// Fallback to default Singapore latitude
|
|
877
|
-
return 1.369;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
/**
|
|
881
|
-
* Safely gets a valid longitude value with fallback to default
|
|
882
|
-
* @returns {number} Valid longitude value
|
|
883
|
-
*/
|
|
884
|
-
#getValidLongitude() {
|
|
885
|
-
const lng = this.location.getLongitude();
|
|
886
|
-
|
|
887
|
-
// Validate longitude is a number and within valid range (-180 to 180)
|
|
888
|
-
if (typeof lng === 'number' && !isNaN(lng) && lng >= -180 && lng <= 180) {
|
|
889
|
-
return lng;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
// Fallback to default Singapore longitude
|
|
893
|
-
return 103.8864;
|
|
894
|
-
}
|
|
895
908
|
}
|
|
@@ -15,6 +15,7 @@ import { inject as service } from '@ember/service';
|
|
|
15
15
|
*
|
|
16
16
|
* @arg phases - Array of phase objects (managed externally)
|
|
17
17
|
* @arg availableEngines - Array of { id, name } engine options
|
|
18
|
+
* @arg defaultEngine - Engine id selected in Orchestrator settings; new phases start with it
|
|
18
19
|
* @arg onPhasesChange - Action(phases) — called when phases array changes
|
|
19
20
|
* @arg onRunPhases - Action(phases) — called when "Run" is clicked
|
|
20
21
|
*/
|
|
@@ -49,7 +50,7 @@ export default class OrchestratorPhaseBuilderComponent extends Component {
|
|
|
49
50
|
id: crypto.randomUUID(),
|
|
50
51
|
mode,
|
|
51
52
|
label: this.intl.t(`orchestrator.mode-${mode.replace(/_/g, '-')}`),
|
|
52
|
-
engine: 'greedy',
|
|
53
|
+
engine: this.args.defaultEngine ?? 'greedy',
|
|
53
54
|
allocationStrategy: 'route_aware',
|
|
54
55
|
vehiclePacking: 'minimize_vehicles',
|
|
55
56
|
orderStatuses: ['created'],
|
|
@@ -59,7 +59,13 @@
|
|
|
59
59
|
{{! ── Phase builder panel (collapsible, below toolbar) ── }}
|
|
60
60
|
{{#if this.showPhaseBuilder}}
|
|
61
61
|
<div class="workbench-phase-panel border-b dark:border-gray-700 bg-white dark:bg-gray-900 flex-shrink-0 h-80">
|
|
62
|
-
<Orchestrator::PhaseBuilder
|
|
62
|
+
<Orchestrator::PhaseBuilder
|
|
63
|
+
@phases={{this.phases}}
|
|
64
|
+
@availableEngines={{this.availableEngines}}
|
|
65
|
+
@defaultEngine={{this.defaultEngine}}
|
|
66
|
+
@onPhasesChange={{this.onPhasesChange}}
|
|
67
|
+
@onRunPhases={{this.onRunPhases}}
|
|
68
|
+
/>
|
|
63
69
|
</div>
|
|
64
70
|
{{/if}}
|
|
65
71
|
|
|
@@ -49,6 +49,8 @@ export default class OrchestratorWorkbenchComponent extends Component {
|
|
|
49
49
|
@tracked availableVehicles = [];
|
|
50
50
|
@tracked availableDrivers = [];
|
|
51
51
|
@tracked availableEngines = [];
|
|
52
|
+
/** The engine selected in Orchestrator settings; new phases start with it. */
|
|
53
|
+
@tracked defaultEngine = null;
|
|
52
54
|
|
|
53
55
|
// ── Plan state ────────────────────────────────────────────────────────────
|
|
54
56
|
|
|
@@ -204,6 +206,12 @@ export default class OrchestratorWorkbenchComponent extends Component {
|
|
|
204
206
|
} catch {
|
|
205
207
|
this.availableEngines = [{ id: 'greedy', name: 'Greedy (built-in)' }];
|
|
206
208
|
}
|
|
209
|
+
try {
|
|
210
|
+
const settings = yield this.fetch.get('fleet-ops/settings/orchestrator-settings');
|
|
211
|
+
this.defaultEngine = settings?.allocation_engine ?? null;
|
|
212
|
+
} catch {
|
|
213
|
+
this.defaultEngine = null;
|
|
214
|
+
}
|
|
207
215
|
}
|
|
208
216
|
|
|
209
217
|
@task *loadCardFields() {
|
|
@@ -270,7 +278,8 @@ export default class OrchestratorWorkbenchComponent extends Component {
|
|
|
270
278
|
mode: phase.mode,
|
|
271
279
|
order_statuses: phase.orderStatuses ?? ['created'],
|
|
272
280
|
options: {
|
|
273
|
-
|
|
281
|
+
// Without an explicit engine the server runs the one selected in Orchestrator settings.
|
|
282
|
+
engine: phase.engine ?? null,
|
|
274
283
|
allocation_strategy: phase.allocationStrategy ?? 'route_aware',
|
|
275
284
|
vehicle_packing: phase.vehiclePacking ?? 'minimize_vehicles',
|
|
276
285
|
balance_workload: phase.balanceWorkload ?? false,
|
|
@@ -311,6 +320,11 @@ export default class OrchestratorWorkbenchComponent extends Component {
|
|
|
311
320
|
if (result.message) {
|
|
312
321
|
this.orchestratorRunMessage = result.message;
|
|
313
322
|
}
|
|
323
|
+
// The server substituted another engine (e.g. VROOM unavailable) — say so.
|
|
324
|
+
if (result.warning) {
|
|
325
|
+
this.orchestratorRunMessage = result.warning;
|
|
326
|
+
this.notifications.warning(result.warning, { autoClear: true, clearDuration: 10000 });
|
|
327
|
+
}
|
|
314
328
|
// If the run returned zero assignments, surface the error/message to
|
|
315
329
|
// the user immediately — otherwise the right panel stays blank with
|
|
316
330
|
// no feedback (PlanViewer is only rendered when hasProposedPlan).
|
|
@@ -401,7 +415,7 @@ export default class OrchestratorWorkbenchComponent extends Component {
|
|
|
401
415
|
id: 'legacy',
|
|
402
416
|
mode: 'allocate',
|
|
403
417
|
label: 'Allocate',
|
|
404
|
-
engine:
|
|
418
|
+
engine: null,
|
|
405
419
|
allocationStrategy: 'route_aware',
|
|
406
420
|
orderStatuses: ['created'],
|
|
407
421
|
balanceWorkload: false,
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
<div class="flex items-center justify-end">
|
|
152
152
|
<div class="flex-row space-x-1 pr-0.5">
|
|
153
153
|
{{#if @resource.payload.pickup}}
|
|
154
|
-
<a href="javascript:;" {{on "click" (fn this.editPlace @resource.payload.pickup)}}>
|
|
154
|
+
<a href="javascript:;" data-test-edit-place="pickup" {{on "click" (fn this.editPlace @resource.payload.pickup)}}>
|
|
155
155
|
<FaIcon @icon="edit" />
|
|
156
156
|
</a>
|
|
157
157
|
<a href="javascript:;" {{on "click" (fn this.setPayloadPlace "pickup" null)}}>
|
|
@@ -206,7 +206,19 @@ export default class OrderFormRouteComponent extends Component {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
@action editPlace(place) {
|
|
209
|
-
|
|
209
|
+
// The place is edited in place, so the form already shows the change; there is no list
|
|
210
|
+
// to refresh, only the route preview and quote that depend on its location.
|
|
211
|
+
this.placeActions.modal.edit(
|
|
212
|
+
place,
|
|
213
|
+
{},
|
|
214
|
+
{
|
|
215
|
+
refresh: false,
|
|
216
|
+
callback: () => {
|
|
217
|
+
this.previewRoute();
|
|
218
|
+
this.requestServiceQuoteRefresh('route.place.updated');
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
);
|
|
210
222
|
}
|
|
211
223
|
|
|
212
224
|
@action async previewRoute() {
|
|
@@ -214,7 +214,7 @@
|
|
|
214
214
|
<div class="dark:text-gray-100">
|
|
215
215
|
<div class="grid grid-cols-7">
|
|
216
216
|
<div class="flex flex-col items-start justify-start pt-3">
|
|
217
|
-
<img src=
|
|
217
|
+
<img src={{parcel-box-image parcelFee.size}} alt="parcel size {{parcelFee.size}}" width="44" class="w-11" />
|
|
218
218
|
<div class="mt-2 text-sm font-medium">
|
|
219
219
|
{{humanize parcelFee.size}}
|
|
220
220
|
</div>
|
|
@@ -423,7 +423,7 @@
|
|
|
423
423
|
<div class="dark:text-gray-100">
|
|
424
424
|
<div class="grid grid-cols-7">
|
|
425
425
|
<div class="flex flex-col items-start justify-start pt-3">
|
|
426
|
-
<img src=
|
|
426
|
+
<img src={{parcel-box-image parcelFee.size}} alt="parcel size {{parcelFee.size}}" width="44" class="w-11" />
|
|
427
427
|
<label class="mt-2">{{humanize parcelFee.size}}</label>
|
|
428
428
|
</div>
|
|
429
429
|
<div class="col-span-6 dimensions-box space-x-2">
|