@fleetbase/fleetops-engine 0.6.49 → 0.6.51

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.
Files changed (271) hide show
  1. package/README.md +185 -67
  2. package/addon/components/contact/panel-header.hbs +11 -48
  3. package/addon/components/customer/create-order-form.hbs +2 -2
  4. package/addon/components/customer/details.hbs +1 -2
  5. package/addon/components/customer/form.hbs +62 -50
  6. package/addon/components/customer/form.js +27 -1
  7. package/addon/components/customer/order-form.hbs +2 -2
  8. package/addon/components/customer/orders.hbs +50 -2
  9. package/addon/components/customer/orders.js +67 -5
  10. package/addon/components/display-place.hbs +2 -2
  11. package/addon/components/driver/form.hbs +1 -1
  12. package/addon/components/home/getting-started-guidance.hbs +113 -0
  13. package/addon/components/home/getting-started-guidance.js +107 -0
  14. package/addon/components/issue/details/comments.hbs +3 -0
  15. package/addon/components/issue/details/comments.js +3 -0
  16. package/addon/components/issue/details/correspondence.hbs +9 -0
  17. package/addon/components/issue/details/correspondence.js +83 -0
  18. package/addon/components/issue/details/documents.hbs +69 -0
  19. package/addon/components/issue/details/documents.js +85 -0
  20. package/addon/components/issue/details.hbs +220 -59
  21. package/addon/components/issue/details.js +245 -0
  22. package/addon/components/issue/form.hbs +19 -1
  23. package/addon/components/issue/panel-header.hbs +43 -0
  24. package/addon/components/issue/panel-header.js +22 -0
  25. package/addon/components/issue/timeline.hbs +40 -0
  26. package/addon/components/issue/timeline.js +45 -0
  27. package/addon/components/leaflet-tracking-marker.js +3 -0
  28. package/addon/components/map/drawer/position-listing.js +3 -0
  29. package/addon/components/map/google-live-map.js +6 -2
  30. package/addon/components/map/leaflet-live-map.hbs +48 -14
  31. package/addon/components/map/leaflet-live-map.js +201 -20
  32. package/addon/components/map/order-list-overlay.hbs +4 -4
  33. package/addon/components/modals/convert-customer-to-vendor.hbs +30 -0
  34. package/addon/components/modals/convert-customer-to-vendor.js +55 -0
  35. package/addon/components/modals/issue-assign.hbs +20 -0
  36. package/addon/components/modals/issue-assign.js +49 -0
  37. package/addon/components/modals/issue-close.hbs +30 -0
  38. package/addon/components/modals/issue-close.js +73 -0
  39. package/addon/components/modals/issue-status.hbs +20 -0
  40. package/addon/components/modals/issue-status.js +43 -0
  41. package/addon/components/modals/order-change-destination.hbs +46 -0
  42. package/addon/components/modals/order-change-destination.js +106 -0
  43. package/addon/components/modals/reset-customer-credentials.js +12 -6
  44. package/addon/components/modals/stop-activity.hbs +28 -0
  45. package/addon/components/modals/stop-activity.js +52 -0
  46. package/addon/components/modals/update-order-activity.hbs +78 -2
  47. package/addon/components/modals/update-order-activity.js +197 -5
  48. package/addon/components/orchestrator/resource-panel.hbs +0 -10
  49. package/addon/components/orchestrator/resource-panel.js +2 -4
  50. package/addon/components/order/activity-list.hbs +2 -2
  51. package/addon/components/order/activity-timeline.hbs +31 -29
  52. package/addon/components/order/details/activity.hbs +3 -3
  53. package/addon/components/order/details/activity.js +13 -2
  54. package/addon/components/order/details/documents.js +2 -0
  55. package/addon/components/order/details/proof.hbs +40 -38
  56. package/addon/components/order/details/proof.js +31 -4
  57. package/addon/components/order/details/purchase-rate.hbs +2 -2
  58. package/addon/components/order/details/route.hbs +11 -3
  59. package/addon/components/order/details/route.js +91 -14
  60. package/addon/components/order/details/tracking.hbs +101 -72
  61. package/addon/components/order/details/tracking.js +149 -2
  62. package/addon/components/order/details.hbs +5 -5
  63. package/addon/components/order/details.js +19 -1
  64. package/addon/components/order/form/details.hbs +3 -3
  65. package/addon/components/order/form/documents.js +11 -4
  66. package/addon/components/order/form/route.hbs +108 -104
  67. package/addon/components/order/form/route.js +37 -1
  68. package/addon/components/order/form/service-rate.hbs +2 -2
  69. package/addon/components/order/header.hbs +1 -1
  70. package/addon/components/order-config-manager/activity-flow.hbs +4 -1
  71. package/addon/components/order-config-manager/activity-flow.js +178 -12
  72. package/addon/components/place/address.js +1 -1
  73. package/addon/components/route-list.hbs +17 -29
  74. package/addon/components/route-list.js +42 -10
  75. package/addon/components/service-rate/details.hbs +42 -1
  76. package/addon/components/service-rate/form.hbs +119 -1
  77. package/addon/components/service-rate/form.js +59 -0
  78. package/addon/components/vehicle/form.js +1 -1
  79. package/addon/components/vehicle/pill.hbs +1 -1
  80. package/addon/components/vendor/personnel-manager.hbs +166 -0
  81. package/addon/components/vendor/personnel-manager.js +143 -0
  82. package/addon/components/widget/live-fleet.hbs +1 -0
  83. package/addon/components/widget/live-fleet.js +2 -7
  84. package/addon/components/widget/revenue-trend.hbs +1 -1
  85. package/addon/components/widget/revenue-trend.js +75 -2
  86. package/addon/controllers/management/contacts/customers/details.js +31 -13
  87. package/addon/controllers/management/contacts/customers.js +16 -5
  88. package/addon/controllers/management/contacts/index/details.js +31 -13
  89. package/addon/controllers/management/contacts/index.js +7 -0
  90. package/addon/controllers/management/issues/index/details.js +52 -6
  91. package/addon/controllers/management/vehicles/index/new.js +1 -1
  92. package/addon/controllers/management/vendors/index/details.js +4 -0
  93. package/addon/controllers/operations/orders/index/details.js +15 -7
  94. package/addon/controllers/operations/orders/index.js +15 -1
  95. package/addon/extension.js +19 -12
  96. package/addon/helpers/format-duration.js +1 -38
  97. package/addon/helpers/place-address-html.js +2 -2
  98. package/addon/initializers/load-leaflet-assets.js +5 -6
  99. package/addon/initializers/patch-ember-leaflet-tooltip-layer.js +51 -0
  100. package/addon/routes/management/issues/index/details.js +1 -1
  101. package/addon/routes/operations/service-rates/index.js +1 -1
  102. package/addon/routes.js +1 -0
  103. package/addon/services/contact-actions.js +231 -1
  104. package/addon/services/geofence.js +163 -19
  105. package/addon/services/getting-started.js +44 -0
  106. package/addon/services/issue-actions.js +71 -0
  107. package/addon/services/leaflet-contextmenu-manager.js +27 -0
  108. package/addon/services/leaflet-map-manager.js +2 -0
  109. package/addon/services/map-adapter/leaflet.js +19 -0
  110. package/addon/services/service-areas.js +3 -0
  111. package/addon/services/vehicle-actions.js +1 -1
  112. package/addon/styles/fleetops-engine.css +1127 -1
  113. package/addon/templates/management/contacts/customers/details.hbs +1 -1
  114. package/addon/templates/management/contacts/index/details.hbs +1 -1
  115. package/addon/templates/management/contacts.hbs +2 -2
  116. package/addon/templates/management/issues/index/details/index.hbs +3 -1
  117. package/addon/templates/management/issues/index/details.hbs +3 -2
  118. package/addon/templates/management/vendors/index/details/personnel.hbs +1 -2
  119. package/addon/templates/operations/orders/index/details/index.hbs +2 -2
  120. package/addon/templates/operations/orders/index.hbs +1 -1
  121. package/addon/templates/operations/service-rates/index/edit.hbs +1 -0
  122. package/addon/templates/operations/service-rates/index/new.hbs +1 -0
  123. package/addon/templates/settings/payments/onboard.hbs +8 -8
  124. package/addon/utils/fleet-ops-options.js +2 -1
  125. package/addon/utils/leaflet-draw-namespace-guard.js +22 -0
  126. package/addon/utils/leaflet-plugin-loader.js +219 -0
  127. package/addon/utils/normalize-order-config-flow.js +41 -0
  128. package/addon/utils/place-address-html.js +3 -2
  129. package/addon/utils/route-visualization.js +54 -7
  130. package/addon/utils/setup-customer-portal.js +4 -64
  131. package/app/components/home/getting-started-guidance.js +1 -0
  132. package/app/components/issue/details/comments.js +1 -0
  133. package/app/components/issue/details/correspondence.js +1 -0
  134. package/app/components/issue/details/documents.js +1 -0
  135. package/app/components/issue/panel-header.js +1 -0
  136. package/app/components/modals/convert-customer-to-vendor.js +1 -0
  137. package/app/components/modals/issue-assign.js +1 -0
  138. package/app/components/modals/issue-close.js +1 -0
  139. package/app/components/modals/issue-status.js +1 -0
  140. package/app/components/modals/order-change-destination.js +1 -0
  141. package/app/components/modals/stop-activity.js +1 -0
  142. package/app/components/vendor/personnel-manager.js +1 -0
  143. package/app/helpers/format-duration.js +1 -1
  144. package/app/services/getting-started.js +1 -0
  145. package/app/utils/leaflet-draw-namespace-guard.js +1 -0
  146. package/app/utils/leaflet-plugin-loader.js +1 -0
  147. package/composer.json +1 -1
  148. package/extension.json +1 -1
  149. package/package.json +5 -5
  150. package/server/migrations/2026_05_21_000001_add_geographic_rules_to_service_rate_fees_table.php +37 -0
  151. package/server/migrations/2026_05_25_000001_add_endpoint_tracking_refs_to_payloads_table.php +50 -0
  152. package/server/migrations/2026_05_27_000001_default_driver_vehicle_statuses_to_available.php +48 -0
  153. package/server/migrations/2026_05_31_000001_add_portal_fields_to_vendor_personnels_table.php +30 -0
  154. package/server/migrations/2026_06_03_000000_ensure_tags_column_on_issues_table.php +31 -0
  155. package/server/migrations/2026_06_03_000001_add_order_uuid_to_issues_table.php +25 -0
  156. package/server/migrations/2026_06_04_000001_backfill_order_transaction_subjects.php +39 -0
  157. package/server/migrations/2026_06_04_000002_backfill_order_transaction_directions.php +24 -0
  158. package/server/resources/views/labels/default.php +57 -49
  159. package/server/resources/views/labels/waypoint-label.php +27 -20
  160. package/server/resources/views/mail/customer-credentials.blade.php +16 -13
  161. package/server/seeders/Testing/ConnectivitySeeder.php +1 -0
  162. package/server/seeders/Testing/FleetSeeder.php +22 -22
  163. package/server/seeders/Testing/OrdersSeeder.php +6 -22
  164. package/server/seeders/Testing/VroomOrchestrationSeeder.php +21 -21
  165. package/server/src/Console/Commands/AuditCustomerUserConflicts.php +75 -0
  166. package/server/src/Exceptions/CustomerUserConflictException.php +13 -0
  167. package/server/src/Expansions/UserFilterExpansion.php +28 -0
  168. package/server/src/Http/Controllers/Api/v1/ContactController.php +17 -2
  169. package/server/src/Http/Controllers/Api/v1/CustomerController.php +876 -0
  170. package/server/src/Http/Controllers/Api/v1/DriverController.php +1 -1
  171. package/server/src/Http/Controllers/Api/v1/IssueController.php +2 -0
  172. package/server/src/Http/Controllers/Api/v1/OrderConfigController.php +54 -0
  173. package/server/src/Http/Controllers/Api/v1/OrderController.php +109 -80
  174. package/server/src/Http/Controllers/Api/v1/PlaceController.php +10 -58
  175. package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +2 -2
  176. package/server/src/Http/Controllers/Api/v1/VehicleController.php +20 -3
  177. package/server/src/Http/Controllers/Internal/v1/ContactController.php +154 -0
  178. package/server/src/Http/Controllers/Internal/v1/CustomerController.php +116 -6
  179. package/server/src/Http/Controllers/Internal/v1/GettingStartedController.php +17 -0
  180. package/server/src/Http/Controllers/Internal/v1/IssueController.php +251 -0
  181. package/server/src/Http/Controllers/Internal/v1/LiveController.php +101 -66
  182. package/server/src/Http/Controllers/Internal/v1/OrderController.php +530 -52
  183. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +10 -68
  184. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +1 -1
  185. package/server/src/Http/Controllers/Internal/v1/SettingController.php +2 -2
  186. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +54 -1
  187. package/server/src/Http/Controllers/Internal/v1/VendorController.php +89 -0
  188. package/server/src/Http/Middleware/AuthenticateCustomerToken.php +34 -0
  189. package/server/src/Http/Requests/CreateCustomerOrderRequest.php +63 -0
  190. package/server/src/Http/Requests/CreateCustomerRequest.php +48 -0
  191. package/server/src/Http/Requests/CreateDriverRequest.php +1 -1
  192. package/server/src/Http/Requests/CreateIssueRequest.php +4 -0
  193. package/server/src/Http/Requests/CreateVehicleRequest.php +25 -1
  194. package/server/src/Http/Requests/Internal/CreateDriverRequest.php +1 -1
  195. package/server/src/Http/Requests/UpdateIssueRequest.php +4 -0
  196. package/server/src/Http/Requests/VerifyCreateCustomerRequest.php +29 -0
  197. package/server/src/Http/Resources/Internal/v1/OrderConfig.php +41 -0
  198. package/server/src/Http/Resources/v1/Customer.php +79 -0
  199. package/server/src/Http/Resources/v1/Index/Order.php +12 -9
  200. package/server/src/Http/Resources/v1/Issue.php +25 -0
  201. package/server/src/Http/Resources/v1/Order.php +20 -18
  202. package/server/src/Http/Resources/v1/OrderConfig.php +74 -0
  203. package/server/src/Http/Resources/v1/Payload.php +23 -20
  204. package/server/src/Http/Resources/v1/ServiceArea.php +33 -19
  205. package/server/src/Http/Resources/v1/ServiceRateFee.php +7 -0
  206. package/server/src/Listeners/HandleOrderDispatched.php +2 -2
  207. package/server/src/Mail/CustomerCredentialsMail.php +5 -6
  208. package/server/src/Models/Contact.php +122 -66
  209. package/server/src/Models/Customer.php +64 -0
  210. package/server/src/Models/Driver.php +12 -3
  211. package/server/src/Models/Entity.php +2 -2
  212. package/server/src/Models/Issue.php +47 -6
  213. package/server/src/Models/Order.php +62 -10
  214. package/server/src/Models/Payload.php +17 -1
  215. package/server/src/Models/ServiceArea.php +1 -1
  216. package/server/src/Models/ServiceRate.php +273 -1
  217. package/server/src/Models/ServiceRateFee.php +39 -9
  218. package/server/src/Models/TrackingNumber.php +8 -2
  219. package/server/src/Models/Vehicle.php +18 -2
  220. package/server/src/Models/VendorPersonnel.php +10 -1
  221. package/server/src/Models/Waypoint.php +2 -2
  222. package/server/src/Models/Zone.php +1 -1
  223. package/server/src/Notifications/LateDeparture.php +2 -2
  224. package/server/src/Notifications/ProlongedStoppage.php +2 -2
  225. package/server/src/Notifications/RouteDeviation.php +2 -2
  226. package/server/src/Observers/ContactObserver.php +2 -0
  227. package/server/src/Observers/PurchaseRateObserver.php +20 -0
  228. package/server/src/Observers/ServiceRateObserver.php +6 -6
  229. package/server/src/Observers/ZoneObserver.php +56 -0
  230. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +1 -1
  231. package/server/src/Providers/FleetOpsServiceProvider.php +2 -0
  232. package/server/src/Support/Analytics/AbstractAnalytics.php +6 -6
  233. package/server/src/Support/Analytics/FuelEfficiency.php +2 -2
  234. package/server/src/Support/Analytics/OrdersByStatus.php +1 -1
  235. package/server/src/Support/Analytics/RevenueTrend.php +0 -1
  236. package/server/src/Support/Analytics/TopDrivers.php +10 -2
  237. package/server/src/Support/CustomerAuth.php +98 -0
  238. package/server/src/Support/GettingStarted.php +144 -0
  239. package/server/src/Support/LabelPdf.php +52 -0
  240. package/server/src/Support/Metrics/AbstractMetric.php +4 -4
  241. package/server/src/Support/PlaceSearch.php +282 -0
  242. package/server/src/Support/ResolvesOrderServiceStops.php +522 -0
  243. package/server/src/Tracking/TrackingContextBuilder.php +41 -38
  244. package/server/src/Tracking/TrackingIntelligenceService.php +109 -9
  245. package/server/src/Tracking/TrackingStop.php +13 -11
  246. package/server/src/routes.php +76 -10
  247. package/server/tests/AnalyticsRoutesTest.php +8 -0
  248. package/server/tests/CapacityAllocationEngineTest.php +10 -10
  249. package/server/tests/CustomerContactIdentitySafetyTest.php +95 -0
  250. package/server/tests/CustomerEndpointTest.php +199 -0
  251. package/server/tests/DriverVehicleStatusDefaultTest.php +39 -0
  252. package/server/tests/GettingStartedStatusTest.php +21 -0
  253. package/server/tests/LabelPdfRenderingTest.php +23 -0
  254. package/server/tests/LiveControllerViewportTest.php +60 -0
  255. package/server/tests/MetricsRegistryTest.php +4 -8
  256. package/server/tests/OrchestrationPayloadBuilderTest.php +2 -2
  257. package/server/tests/OrderActivityFlowRegressionTest.php +116 -0
  258. package/server/tests/OrderConfigEndpointTest.php +86 -0
  259. package/server/tests/OrderFileAttachmentTest.php +20 -0
  260. package/server/tests/ServiceAreaZoneApiShapeTest.php +78 -0
  261. package/server/tests/VehicleDriverAssignmentTest.php +18 -0
  262. package/translations/ar-ae.yml +9 -0
  263. package/translations/bg-bg.yaml +9 -0
  264. package/translations/en-us.yaml +12 -0
  265. package/translations/es-pa.yaml +9 -0
  266. package/translations/fr-fr.yaml +9 -0
  267. package/translations/mn-mn.yaml +9 -0
  268. package/translations/pt-br.yaml +9 -0
  269. package/translations/ru-ru.yaml +9 -0
  270. package/translations/vi-vn.yaml +9 -0
  271. package/server/migrations/2026_05_13_000001_repair_customer_contact_user_types.php +0 -86
package/README.md CHANGED
@@ -1,122 +1,240 @@
1
1
  <p align="center">
2
- <img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/fleetbase-logo-svg.svg" width="380" height="100" />
2
+ <img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/fleetbase-logo-svg.svg" alt="Fleetbase" width="380" height="100">
3
3
  </p>
4
+
5
+ <h1 align="center">Fleet-Ops</h1>
6
+
7
+ <p align="center">
8
+ Open-source fleet, dispatch, transport management, and real-time logistics operations for Fleetbase.
9
+ </p>
10
+
4
11
  <p align="center">
5
- Open-source Fleet & Transport Management Extension for Fleetbase
12
+ <a href="https://github.com/fleetbase/fleetops">
13
+ <img src="https://img.shields.io/badge/repo-fleetbase%2Ffleetops-111827?style=flat-square" alt="Repository">
14
+ </a>
15
+ <a href="https://github.com/fleetbase/fleetops/blob/master/LICENSE.md">
16
+ <img src="https://img.shields.io/badge/license-AGPL--3.0--or--later-blue?style=flat-square" alt="License: AGPL-3.0-or-later">
17
+ </a>
18
+ <a href="https://www.npmjs.com/package/@fleetbase/fleetops-engine">
19
+ <img src="https://img.shields.io/badge/npm-%40fleetbase%2Ffleetops--engine-CB3837?style=flat-square" alt="NPM package">
20
+ </a>
21
+ <a href="https://packagist.org/packages/fleetbase/fleetops-api">
22
+ <img src="https://img.shields.io/badge/packagist-fleetbase%2Ffleetops--api-F28D1A?style=flat-square" alt="Packagist package">
23
+ </a>
24
+ <a href="https://www.fleetbase.io/docs/fleet-ops">
25
+ <img src="https://img.shields.io/badge/docs-fleet--ops-0EA5E9?style=flat-square" alt="Fleet-Ops documentation">
26
+ </a>
27
+ <img src="https://img.shields.io/badge/node-%3E%3D18-339933?style=flat-square" alt="Node >= 18">
28
+ <img src="https://img.shields.io/badge/php-%5E8.0-777BB4?style=flat-square" alt="PHP ^8.0">
6
29
  </p>
7
30
 
8
- ---
31
+ <p align="center">
32
+ <img src="https://www.fleetbase.io/images/screenshots/fleet-ops/fleet-ops-multi-waypoint-order.webp" alt="Fleet-Ops multi-waypoint order with live map, route, driver assignment, and order details" width="900">
33
+ </p>
9
34
 
10
- ## Overview
35
+ ## What is Fleet-Ops?
11
36
 
12
- This monorepo contains both the frontend and backend components of the FleetOps extension for Fleetbase. The frontend is built using Ember.js and the backend is implemented in PHP.
37
+ Fleet-Ops is the core logistics and fleet management extension for the [Fleetbase](https://www.fleetbase.io) platform. It gives operations teams a dispatch console for managing orders, drivers, vehicles, fleets, service areas, live maps, route execution, analytics, maintenance, and connected telematics.
13
38
 
14
- ### Requirements
39
+ Fleet-Ops ships as two packages:
15
40
 
16
- * PHP 8.0 or above
17
- * Ember.js v4.8 or above
18
- * Ember CLI v4.8 or above
19
- * Node.js v18 or above
41
+ | Package | Purpose |
42
+ | --- | --- |
43
+ | `@fleetbase/fleetops-engine` | Ember Engine/Add-on that powers the Fleet-Ops console UI. |
44
+ | `fleetbase/fleetops-api` | Laravel/PHP package that provides the Fleet-Ops API, models, jobs, events, and integrations. |
20
45
 
21
- ## Structure
46
+ Fleet-Ops is included with Fleetbase Cloud and self-hosted Fleetbase installations. For product concepts, workflows, and setup guides, start with the [Fleet-Ops documentation](https://www.fleetbase.io/docs/fleet-ops).
22
47
 
48
+ ## Features
49
+
50
+ ### Operations
51
+
52
+ - Create, import, schedule, dispatch, start, cancel, and complete delivery orders.
53
+ - Manage multi-waypoint routes, payloads, entities, labels, order metadata, notes, comments, files, and proofs.
54
+ - Track live order progress with ETAs, route overlays, driver pings, activity timelines, and configurable status flows.
55
+ - Configure custom order types, activity flows, entity fields, proof requirements, and service-rate rules.
56
+ - Run orchestration workflows for order allocation, driver assignment, vehicle capacity, and route sequencing.
57
+ - Plan work with the scheduler, fleet schedule, service quotes, routes, manifests, and manifest stops.
58
+
59
+ ### Live Map
60
+
61
+ - View live drivers, vehicles, active orders, routes, places, service areas, zones, and geofences.
62
+ - Filter and inspect operational layers with Fleet-Ops map controls and drawer panels.
63
+ - Support Leaflet-based and Google-based map experiences through Fleetbase map settings.
64
+ - Capture positions, replay movement, track vehicles and drivers, and surface geofence events.
65
+
66
+ ### Fleet Management
67
+
68
+ - Manage drivers, vehicles, fleets, places, contacts, customers, vendors, and integrated vendors.
69
+ - Assign drivers and vehicles to fleets, vendors, and orders.
70
+ - Track driver schedules, availability, positions, active shifts, and hours-of-service status.
71
+ - Track vehicle status, devices, positions, equipment, schedules, work orders, and maintenance history.
72
+ - Manage issues, fuel reports, imports, exports, bulk actions, and custom resource fields.
73
+
74
+ ### Maintenance
75
+
76
+ - Define preventive maintenance schedules and calendar feeds.
77
+ - Manage work orders, maintenance records, line items, equipment, parts, and warranties.
78
+ - Send work orders, trigger schedule runs, pause and resume schedules, and review maintenance history.
79
+
80
+ ### Connectivity
81
+
82
+ - Connect telematics providers, devices, sensors, events, and tracking data.
83
+ - Discover and link telematics devices, test provider credentials, and receive telematics webhooks.
84
+ - Use Fleet-Ops tracking providers for calculated, OSRM, and Google Routes-backed route intelligence.
85
+
86
+ ### Analytics and Dashboards
87
+
88
+ - Use Fleet-Ops KPI widgets for earnings, average order value, distance, active orders, online drivers, and open issues.
89
+ - Review analytics for operations pulse, live fleet, revenue trends, order status volume, on-time delivery, top drivers, fuel efficiency, issues, maintenance, and geofence violations.
90
+ - Create and view reports from the Fleet-Ops analytics workspace.
91
+
92
+ ### Settings and Extensions
93
+
94
+ - Configure Navigator app onboarding, routing, tracking, map providers, notifications, scheduling, payments, orchestrator settings, custom fields, and avatars.
95
+ - Expose Fleet-Ops order tracking on the Fleetbase login surface.
96
+ - Integrate Fleet-Ops entities into other Fleetbase extensions through registered components and virtual detail tabs.
97
+
98
+ ## Architecture
99
+
100
+ Fleet-Ops follows the Fleetbase extension architecture: an Ember Engine for the console interface and a Laravel package for API and backend capabilities.
101
+
102
+ ```text
103
+ fleetops/
104
+ +-- addon/ # Ember Engine source: routes, controllers, components, services, templates
105
+ +-- app/ # Ember app re-exports and integration points
106
+ +-- assets/ # Frontend assets bundled with the engine
107
+ +-- translations/ # Fleet-Ops locale files
108
+ +-- server/
109
+ | +-- config/ # Fleet-Ops API configuration
110
+ | +-- migrations/ # Database migrations
111
+ | +-- resources/ # Backend views and resources
112
+ | +-- seeders/ # Seed data
113
+ | +-- src/ # Controllers, models, jobs, events, support services, providers
114
+ | +-- tests/ # Backend test suite
115
+ +-- tests/ # Ember test suite
116
+ +-- package.json # Frontend package metadata and scripts
117
+ +-- composer.json # Backend package metadata and scripts
23
118
  ```
24
- ├── addon
25
- ├── app
26
- ├── assets
27
- ├── translations
28
- ├── config
29
- ├── node_modules
30
- ├── server
31
- │ ├── config
32
- │ ├── data
33
- │ ├── migrations
34
- │ ├── resources
35
- │ ├── src
36
- │ ├── tests
37
- │ └── vendor
38
- ├── tests
39
- ├── testem.js
40
- ├── index.js
41
- ├── package.json
42
- ├── phpstan.neon.dist
43
- ├── phpunit.xml.dist
44
- ├── pnpm-lock.yaml
45
- ├── ember-cli-build.js
46
- ├── composer.json
47
- ├── CONTRIBUTING.md
48
- ├── LICENSE.md
49
- ├── README.md
50
- ```
51
119
 
52
- ## Installation
120
+ Core frontend dependencies include Ember Octane, Ember Engines, Fleetbase Ember Core, Fleetbase UI, Fleet-Ops Data, Leaflet, Leaflet Draw, Turf, JointJS, and Stripe Connect. Core backend capabilities are provided by Laravel, Fleetbase Core API, Fleet-Ops models/controllers, orchestration engines, tracking providers, analytics, notifications, jobs, and telematics integrations.
121
+
122
+ ## Getting Started
53
123
 
54
- ### Backend
124
+ Fleet-Ops comes pre-installed with Fleetbase Cloud and standard self-hosted Fleetbase installations. If you are setting up the Fleetbase platform itself, use the Fleetbase documentation:
55
125
 
56
- Install the PHP packages using Composer:
126
+ - [Fleet-Ops documentation](https://www.fleetbase.io/docs/fleet-ops)
127
+ - [Fleetbase documentation](https://www.fleetbase.io/docs)
128
+ - [Fleetbase console](https://console.fleetbase.io)
129
+
130
+ When developing Fleet-Ops from source, install both frontend and backend dependencies:
57
131
 
58
132
  ```bash
59
- composer require fleetbase/core-api
60
- composer require fleetbase/fleetops-api
133
+ pnpm install
134
+ composer install
61
135
  ```
62
- ### Frontend
63
136
 
64
- Install the Ember.js Engine/Addon:
137
+ ### Link Fleet-Ops into Fleetbase
138
+
139
+ When working from the Fleetbase monorepo, use the Fleetbase package linker to connect this local package to the running Console and API applications. From the Fleetbase repository root:
65
140
 
66
141
  ```bash
67
- pnpm install @fleetbase/fleetops-engine
142
+ flb-package-linker enable fleetops
143
+ flb-package-linker install fleetops
68
144
  ```
69
145
 
70
- ## Usage
146
+ This links the local Fleet-Ops Ember engine and Laravel package so Console and API use your source checkout instead of the published packages. See the [Fleetbase development setup guide](https://www.fleetbase.io/docs/platform/quickstart/development-setup) for the full package-linking workflow, Docker setup, Octane reload notes, and frontend hot-reload options.
71
147
 
72
- ### Backend
148
+ ### Link Fleet-Ops Data
149
+
150
+ Fleet-Ops also depends on the shared `@fleetbase/fleetops-data` package. That package contains Fleet-Ops Ember Data models, adapters, and serializers, and can be reused by other Fleetbase modules that need to read or write Fleet-Ops resources without duplicating data-layer definitions.
151
+
152
+ If you are changing shared Fleet-Ops data models or consuming them from another extension, link `fleetops-data` through the root Console workspace:
73
153
 
74
- 🧹 Keep a modern codebase with **PHP CS Fixer**:
75
154
  ```bash
76
- composer lint
155
+ flb-package-linker enable-shared fleetops-data
156
+ flb-package-linker install
77
157
  ```
78
158
 
79
- ⚗️ Run static analysis using **PHPStan**:
159
+ For broader Fleet-Ops frontend work, you may also link the common shared Ember packages used by Fleetbase:
160
+
80
161
  ```bash
81
- composer test:types
162
+ flb-package-linker enable fleetops --shared ember-core ember-ui fleetops-data
163
+ flb-package-linker install fleetops
82
164
  ```
83
165
 
84
- ✅ Run unit tests using **PEST**
166
+ ## Development
167
+
168
+ Start the Ember Engine in development mode:
169
+
85
170
  ```bash
86
- composer test:unit
171
+ pnpm start
87
172
  ```
88
173
 
89
- 🚀 Run the entire test suite:
174
+ Build the production frontend bundle:
175
+
90
176
  ```bash
91
- composer test
177
+ pnpm build
92
178
  ```
93
179
 
94
- ### Frontend
180
+ Run frontend linting:
95
181
 
96
- 🧹 Keep a modern codebase with **ESLint**:
97
182
  ```bash
98
183
  pnpm lint
99
184
  ```
100
185
 
101
- ✅ Run unit tests using **Ember/QUnit**
186
+ Run backend linting:
187
+
188
+ ```bash
189
+ composer test:lint
190
+ ```
191
+
192
+ ## Testing
193
+
194
+ Run the Ember/QUnit test suite:
195
+
102
196
  ```bash
103
- pnpm test
104
197
  pnpm test:ember
105
- pnpm test:ember-compatibility
106
198
  ```
107
199
 
108
- 🚀 Start the Ember Addon/Engine
200
+ Run the full frontend check suite:
201
+
109
202
  ```bash
110
- pnpm start
203
+ pnpm test
111
204
  ```
112
205
 
113
- 🔨 Build the Ember Addon/Engine
206
+ Run the backend test suite:
207
+
114
208
  ```bash
115
- pnpm build
209
+ composer test
210
+ ```
211
+
212
+ Run backend checks individually:
213
+
214
+ ```bash
215
+ composer test:lint
216
+ composer test:types
217
+ composer test:unit
116
218
  ```
117
219
 
220
+ ## Documentation
221
+
222
+ - [Fleet-Ops docs](https://www.fleetbase.io/docs/fleet-ops)
223
+ - [Fleet-Ops quickstart](https://www.fleetbase.io/docs/fleet-ops/getting-started/quickstart)
224
+ - [Fleet-Ops core concepts](https://www.fleetbase.io/docs/fleet-ops/getting-started/core-concepts)
225
+ - [Navigator app setup](https://www.fleetbase.io/docs/fleet-ops/getting-started/navigator-app-setup)
226
+ - [Fleetbase docs](https://www.fleetbase.io/docs)
227
+
118
228
  ## Contributing
119
- See the Contributing Guide for details on how to contribute to this project.
229
+
230
+ Contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request.
231
+
232
+ Useful project files:
233
+
234
+ - [package.json](package.json) for frontend scripts and package metadata.
235
+ - [composer.json](composer.json) for backend scripts and package metadata.
236
+ - [extension.json](extension.json) for Fleetbase extension metadata.
120
237
 
121
238
  ## License
122
- This project is licensed under the MIT License.
239
+
240
+ Fleet-Ops is open-source software licensed under the [GNU Affero General Public License v3.0 or later](LICENSE.md).
@@ -13,55 +13,18 @@
13
13
  </div>
14
14
  </div>
15
15
  <div class="next-view-header-right">
16
- <div class="flex flex-row flex-1 justify-end space-x-2">
16
+ <Layout::Resource::Panel::HeaderActions
17
+ @resource={{@resource}}
18
+ @saveTask={{@saveTask}}
19
+ @saveOptions={{@saveOptions}}
20
+ @saveDisabled={{@saveDisabled}}
21
+ @pojoResource={{@pojoResource}}
22
+ @authSchema={{@authSchema}}
23
+ @actionButtons={{@actionButtons}}
24
+ @onPressCancel={{@onPressCancel}}
25
+ >
17
26
  {{yield}}
18
- {{#if @saveTask}}
19
- <Button
20
- @type="primary"
21
- @icon={{if @resource.isNew "check" "save"}}
22
- @text={{if @resource.isNew (concat "Create " this.modelName) "Save Changes"}}
23
- @onClick={{perform @saveTask @resource}}
24
- @disabled={{cannot-write @resource schema=@authSchema}}
25
- @isLoading={{@saveTask.isRunning}}
26
- />
27
- {{/if}}
28
- {{#each @actionButtons as |actionButton|}}
29
- <Button
30
- @type={{actionButton.type}}
31
- @text={{actionButton.text}}
32
- @onClick={{if actionButton.perform (perform actionButton.perform) (or actionButton.onClick actionButton.fn)}}
33
- @size={{actionButton.size}}
34
- @buttonType={{actionButton.buttonType}}
35
- @disabled={{actionButton.disabled}}
36
- @exampleText={{actionButton.exampleText}}
37
- @helpText={{actionButton.helpText}}
38
- @icon={{actionButton.icon}}
39
- @iconClass={{actionButton.iconClass}}
40
- @iconFlip={{actionButton.iconFlip}}
41
- @iconPrefix={{actionButton.iconPrefix}}
42
- @iconRotation={{actionButton.iconRotation}}
43
- @iconSize={{actionButton.iconSize}}
44
- @isLoading={{actionButton.isLoading}}
45
- @outline={{actionButton.outline}}
46
- @permission={{actionButton.permission}}
47
- @wrapperClass={{actionButton.wrapperClass}}
48
- @textClass={{actionButton.textClass}}
49
- @tooltipPlacement={{actionButton.tooltipPlacement}}
50
- @visible={{actionButton.visible}}
51
- />
52
- {{/each}}
53
- {{#if @onPressCancel}}
54
- <button
55
- type="button"
56
- class="next-content-overlay-panel-cancel-button {{@cancelButtonClass}}"
57
- {{set-height @cancelButtonHeight}}
58
- {{set-width @cancelButtonWidth}}
59
- {{on "click" @onPressCancel}}
60
- >
61
- <FaIcon @icon={{or @cancelIcon "times"}} @size={{@iconSize}} @prefix={{or @iconPrefix "fas"}} class={{@iconClass}} />
62
- </button>
63
- {{/if}}
64
- </div>
27
+ </Layout::Resource::Panel::HeaderActions>
65
28
  </div>
66
29
  </div>
67
30
  </div>
@@ -335,7 +335,7 @@
335
335
  {{#each serviceQuote.items as |item|}}
336
336
  <tr>
337
337
  <td>
338
- <span class="font-semibold">{{smart-humanize item.details}}</span>
338
+ <span class="font-semibold">{{item.details}}</span>
339
339
  </td>
340
340
  <td>
341
341
  <span>{{format-currency item.amount serviceQuote.currency}}</span>
@@ -449,4 +449,4 @@
449
449
 
450
450
  <Spacer @height="300px" />
451
451
  </Overlay::Body>
452
- </Overlay>
452
+ </Overlay>
@@ -47,6 +47,5 @@
47
47
  </div>
48
48
  </div>
49
49
  </ContentPanel>
50
-
51
50
  <CustomField::Yield @subject={{@resource}} @viewMode={{true}} @wrapperClass="bordered-top" />
52
- </div>
51
+ </div>
@@ -1,53 +1,4 @@
1
1
  <div class="form-wrapper" ...attributes>
2
- <ContentPanel @title={{t "customer.fields.user-account"}} @open={{true}} @actionButtons={{this.userAccountActionButtons}} @wrapperClass="bordered-top">
3
- <div class="space-y-2">
4
- <InputGroup @name={{t "customer.fields.user-account"}} @helpText={{t "customer.fields.user-account-help-text"}}>
5
- <ModelSelect
6
- @modelName="user"
7
- @selectedModel={{@resource.user}}
8
- @placeholder={{t "customer.fields.select-user"}}
9
- @query={{hash doesnt_have_contact=true}}
10
- @triggerClass="form-select form-input"
11
- @infiniteScroll={{false}}
12
- @renderInPlace={{true}}
13
- @onChange={{fn (mut @resource.user)}}
14
- @permission="fleet-ops update-user-for customer"
15
- as |model|
16
- >
17
- <div class="flex flex-row">
18
- <div class="mr-2 w-6">
19
- <Image src={{model.avatar_url}} @fallbackSrc={{config "defaultValues.userImage"}} alt={{this.user.name}} class="w-6 h-6 rounded-md" />
20
- </div>
21
- <div class="flex flex-col">
22
- <div class="font-semibold">{{model.name}}</div>
23
- <div class="text-xs flex flex-row items-center leading-4">
24
- <FaIcon @icon="envelope" @size="sm" class="mr-1 opacity-75" />
25
- <span>{{n-a model.email}}</span>
26
- </div>
27
- <div class="text-xs flex flex-row items-center leading-4">
28
- <FaIcon @icon="phone" @size="sm" class="mr-1 opacity-75" />
29
- <span>{{n-a model.phone}}</span>
30
- </div>
31
- </div>
32
- </div>
33
- </ModelSelect>
34
- </InputGroup>
35
- {{#if @resource.user}}
36
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-2 no-input-group-padding">
37
- <InputGroup @name={{t "common.name"}} @wrapperClass="col-span-2 mb-0i">
38
- <Input @value={{@resource.user.name}} @type="text" class="w-full form-input" placeholder={{t "common.name"}} disabled={{true}} />
39
- </InputGroup>
40
- <InputGroup @name={{t "common.email"}} @wrapperClass="mb-0i">
41
- <Input @value={{@resource.user.email}} @type="text" class="w-full form-input" placeholder={{t "common.email"}} disabled={{true}} />
42
- </InputGroup>
43
- <InputGroup @name={{t "common.phone"}} @wrapperClass="mb-0i">
44
- <PhoneInput @value={{@resource.user.phone}} @onInput={{fn (mut @resource.phone)}} class="form-input w-full" disabled={{true}} />
45
- </InputGroup>
46
- </div>
47
- {{/if}}
48
- </div>
49
- </ContentPanel>
50
-
51
2
  <ContentPanel @title={{t "customer.fields.customer-details"}} @open={{true}} @wrapperClass="bordered-top">
52
3
  <div class="flex flex-row space-x-3 mb-3">
53
4
  <div class="flex items-center justify-start rounded-full">
@@ -125,17 +76,78 @@
125
76
  as |model|
126
77
  >
127
78
  <div class="flex items-center flex-row justify-between">
128
- <div class="truncate flex-1">{{n-a model.address}}</div>
79
+ <div class="truncate flex-1">{{place-address-html model}}</div>
129
80
  <Badge @hideStatusDot={{true}} @status="info">{{model.public_id}}</Badge>
130
81
  </div>
131
82
  </ModelSelect>
132
83
  </InputGroup>
84
+ {{#if this.showWelcomeEmailOption}}
85
+ <div class="col-span-2 mt-3">
86
+ <Checkbox
87
+ @value={{this.sendWelcomeEmail}}
88
+ @label={{t "customer.fields.send-welcome-email"}}
89
+ @helpText={{t "customer.fields.send-welcome-email-help-text"}}
90
+ @onToggle={{this.toggleWelcomeEmail}}
91
+ @alignItems="center"
92
+ @labelClass="mb-0i"
93
+ />
94
+ </div>
95
+ {{/if}}
133
96
  <RegistryYield @registry="fleet-ops:component:customer:form:details" as |RegistryComponent|>
134
97
  <RegistryComponent @resource={{@resource}} @controller={{@controller}} @permission={{get-write-permission @resource}} />
135
98
  </RegistryYield>
136
99
  </div>
137
100
  </ContentPanel>
138
101
 
102
+ <ContentPanel @title={{t "customer.fields.user-account"}} @open={{true}} @actionButtons={{this.userAccountActionButtons}} @wrapperClass="bordered-top">
103
+ <div class="space-y-2">
104
+ <InputGroup @name={{t "customer.fields.user-account"}} @helpText={{t "customer.fields.user-account-help-text"}}>
105
+ <ModelSelect
106
+ @modelName="user"
107
+ @selectedModel={{@resource.user}}
108
+ @placeholder={{t "customer.fields.select-user"}}
109
+ @query={{hash doesnt_have_contact=true is_customer=true}}
110
+ @triggerClass="form-select form-input"
111
+ @infiniteScroll={{false}}
112
+ @renderInPlace={{true}}
113
+ @onChange={{fn (mut @resource.user)}}
114
+ @permission="fleet-ops update-user-for customer"
115
+ as |model|
116
+ >
117
+ <div class="flex flex-row">
118
+ <div class="mr-2 w-6">
119
+ <Image src={{model.avatar_url}} @fallbackSrc={{config "defaultValues.userImage"}} alt={{this.user.name}} class="w-6 h-6 rounded-md" />
120
+ </div>
121
+ <div class="flex flex-col">
122
+ <div class="font-semibold">{{model.name}}</div>
123
+ <div class="text-xs flex flex-row items-center leading-4">
124
+ <FaIcon @icon="envelope" @size="sm" class="mr-1 opacity-75" />
125
+ <span>{{n-a model.email}}</span>
126
+ </div>
127
+ <div class="text-xs flex flex-row items-center leading-4">
128
+ <FaIcon @icon="phone" @size="sm" class="mr-1 opacity-75" />
129
+ <span>{{n-a model.phone}}</span>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ </ModelSelect>
134
+ </InputGroup>
135
+ {{#if @resource.user}}
136
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-2 no-input-group-padding">
137
+ <InputGroup @name={{t "common.name"}} @wrapperClass="col-span-2 mb-0i">
138
+ <Input @value={{@resource.user.name}} @type="text" class="w-full form-input" placeholder={{t "common.name"}} disabled={{true}} />
139
+ </InputGroup>
140
+ <InputGroup @name={{t "common.email"}} @wrapperClass="mb-0i">
141
+ <Input @value={{@resource.user.email}} @type="text" class="w-full form-input" placeholder={{t "common.email"}} disabled={{true}} />
142
+ </InputGroup>
143
+ <InputGroup @name={{t "common.phone"}} @wrapperClass="mb-0i">
144
+ <PhoneInput @value={{@resource.user.phone}} @onInput={{fn (mut @resource.phone)}} class="form-input w-full" disabled={{true}} />
145
+ </InputGroup>
146
+ </div>
147
+ {{/if}}
148
+ </div>
149
+ </ContentPanel>
150
+
139
151
  <CustomField::Yield @subject={{@resource}} @wrapperClass="bordered-top" />
140
152
 
141
153
  <RegistryYield @registry="fleet-ops:component:customer:form" as |RegistryComponent|>
@@ -11,12 +11,17 @@ export default class CustomerFormComponent extends Component {
11
11
  @service currentUser;
12
12
  @service notifications;
13
13
  @service modalsManager;
14
+ @service('universe/extension-manager') extensionManager;
15
+
14
16
  @tracked userAccountActionButtons = [
15
17
  {
16
18
  icon: 'user-plus',
17
19
  size: 'xs',
18
20
  permission: 'iam create user',
19
- onClick: () => {
21
+ onClick: async () => {
22
+ // Load IAM engine for user-form modal component
23
+ await this.extensionManager.ensureEngineLoaded('@fleetbase/iam-engine');
24
+
20
25
  const user = this.store.createRecord('user', {
21
26
  status: 'pending',
22
27
  type: 'user',
@@ -61,6 +66,27 @@ export default class CustomerFormComponent extends Component {
61
66
  },
62
67
  ];
63
68
 
69
+ get showWelcomeEmailOption() {
70
+ return this.args.resource?.isNew && this.extensionManager.isInstalled('@fleetbase/customer-portal-engine');
71
+ }
72
+
73
+ get sendWelcomeEmail() {
74
+ return Boolean(this.args.resource?.meta?.customer_portal?.send_welcome_email);
75
+ }
76
+
77
+ @action toggleWelcomeEmail(value = !this.sendWelcomeEmail) {
78
+ const meta = this.args.resource.meta ?? {};
79
+ const customerPortal = meta.customer_portal ?? {};
80
+
81
+ this.args.resource.set('meta', {
82
+ ...meta,
83
+ customer_portal: {
84
+ ...customerPortal,
85
+ send_welcome_email: value,
86
+ },
87
+ });
88
+ }
89
+
64
90
  @action selectPlace(place) {
65
91
  if (!place) return;
66
92
  this.args.resource.setProperties({
@@ -351,7 +351,7 @@
351
351
  {{#each serviceQuote.items as |item|}}
352
352
  <tr>
353
353
  <td>
354
- <span class="font-semibold">{{smart-humanize item.details}}</span>
354
+ <span class="font-semibold">{{item.details}}</span>
355
355
  </td>
356
356
  <td>
357
357
  <span>{{format-currency item.amount serviceQuote.currency}}</span>
@@ -473,4 +473,4 @@
473
473
 
474
474
  <Spacer @height="300px" />
475
475
  </Overlay::Body>
476
- </Overlay>
476
+ </Overlay>