@fleetbase/fleetops-engine 0.6.38 → 0.6.39

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 (429) hide show
  1. package/addon/components/activity/form.hbs +2 -12
  2. package/addon/components/activity/logic-builder.hbs +1 -1
  3. package/addon/components/custom-entity/form.hbs +4 -20
  4. package/addon/components/device/form.hbs +3 -15
  5. package/addon/components/device/panel-header.hbs +13 -2
  6. package/addon/components/driver/details.hbs +33 -2
  7. package/addon/components/driver/form.hbs +42 -0
  8. package/addon/components/driver/panel-header.hbs +8 -1
  9. package/addon/components/driver/schedule.hbs +115 -76
  10. package/addon/components/driver/schedule.js +349 -157
  11. package/addon/components/driver-onboard-settings.hbs +2 -8
  12. package/addon/components/entity-field-editing-settings.hbs +2 -5
  13. package/addon/components/equipment/card.hbs +49 -0
  14. package/addon/components/equipment/card.js +6 -0
  15. package/addon/components/equipment/details.hbs +83 -44
  16. package/addon/components/equipment/form.hbs +111 -41
  17. package/addon/components/equipment/form.js +78 -10
  18. package/addon/components/equipment/panel-header.hbs +36 -0
  19. package/addon/components/equipment/panel-header.js +2 -0
  20. package/addon/components/fleet/driver-listing.hbs +3 -1
  21. package/addon/components/fleet/vehicle-listing.hbs +4 -7
  22. package/addon/components/fleet-panel/vehicle-listing.hbs +1 -6
  23. package/addon/components/fuel-report/form.hbs +1 -5
  24. package/addon/components/layout/fleet-ops-sidebar.hbs +40 -36
  25. package/addon/components/layout/fleet-ops-sidebar.js +61 -10
  26. package/addon/components/maintenance/cost-panel.hbs +176 -0
  27. package/addon/components/maintenance/cost-panel.js +241 -0
  28. package/addon/components/maintenance/details.hbs +123 -60
  29. package/addon/components/maintenance/form.hbs +138 -78
  30. package/addon/components/maintenance/form.js +131 -6
  31. package/addon/components/maintenance/panel-header.hbs +31 -0
  32. package/addon/components/maintenance/panel-header.js +2 -0
  33. package/addon/components/maintenance-schedule/details.hbs +260 -0
  34. package/addon/components/maintenance-schedule/details.js +158 -0
  35. package/addon/components/maintenance-schedule/form.hbs +287 -0
  36. package/addon/components/maintenance-schedule/form.js +199 -0
  37. package/addon/components/map/container.hbs +1 -1
  38. package/addon/components/map/drawer/device-event-listing.hbs +1 -1
  39. package/addon/components/map/drawer/driver-listing.hbs +1 -6
  40. package/addon/components/map/drawer/place-listing.hbs +1 -6
  41. package/addon/components/map/drawer/vehicle-listing.hbs +1 -6
  42. package/addon/components/map/drawer.hbs +8 -1
  43. package/addon/components/map/leaflet-live-map.hbs +2 -1
  44. package/addon/components/map/toolbar/visibility-control-panel.hbs +1 -1
  45. package/addon/components/map/toolbar.hbs +4 -29
  46. package/addon/components/modals/add-driver-shift.hbs +155 -0
  47. package/addon/components/modals/add-driver-shift.js +210 -0
  48. package/addon/components/modals/bulk-assign-orders.hbs +67 -0
  49. package/addon/components/modals/driver-shift.hbs +43 -0
  50. package/addon/components/modals/driver-shift.js +56 -0
  51. package/addon/components/modals/entity-form.hbs +5 -28
  52. package/addon/components/modals/orchestrator-import.hbs +351 -0
  53. package/addon/components/modals/orchestrator-import.js +807 -0
  54. package/addon/components/modals/order-config-new-status.hbs +1 -5
  55. package/addon/components/modals/scheduling-conflict.hbs +47 -0
  56. package/addon/components/modals/scheduling-conflict.js +53 -0
  57. package/addon/components/modals/send-work-order.hbs +91 -0
  58. package/addon/components/modals/send-work-order.js +3 -0
  59. package/addon/components/modals/service-area-form.hbs +1 -6
  60. package/addon/components/modals/set-driver-availability.hbs +50 -0
  61. package/addon/components/modals/set-driver-availability.js +57 -0
  62. package/addon/components/modals/update-order-activity.hbs +13 -9
  63. package/addon/components/modals/user-form.hbs +1 -5
  64. package/addon/components/modals/vehicle-form.hbs +17 -102
  65. package/addon/components/modals/vendor-form.hbs +15 -82
  66. package/addon/components/orchestrator/card-fields-settings.hbs +76 -0
  67. package/addon/components/orchestrator/card-fields-settings.js +134 -0
  68. package/addon/components/orchestrator/order-pool.hbs +264 -0
  69. package/addon/components/orchestrator/order-pool.js +394 -0
  70. package/addon/components/orchestrator/phase-builder.hbs +162 -0
  71. package/addon/components/orchestrator/phase-builder.js +162 -0
  72. package/addon/components/orchestrator/plan-viewer.hbs +278 -0
  73. package/addon/components/orchestrator/plan-viewer.js +342 -0
  74. package/addon/components/orchestrator/resource-panel.hbs +301 -0
  75. package/addon/components/orchestrator/resource-panel.js +106 -0
  76. package/addon/components/orchestrator-workbench.hbs +318 -0
  77. package/addon/components/orchestrator-workbench.js +1087 -0
  78. package/addon/components/order/details/custom-fields.hbs +10 -1
  79. package/addon/components/order/details/detail.hbs +37 -2
  80. package/addon/components/order/details/detail.js +0 -1
  81. package/addon/components/order/details/integrated-vendor-details.hbs +4 -4
  82. package/addon/components/order/details/notes.hbs +1 -7
  83. package/addon/components/order/details/route.hbs +1 -5
  84. package/addon/components/order/form/details.hbs +44 -10
  85. package/addon/components/order/form/details.js +57 -0
  86. package/addon/components/order/form/notes.hbs +1 -7
  87. package/addon/components/order/form/payload.hbs +1 -7
  88. package/addon/components/order/form/route.hbs +3 -15
  89. package/addon/components/order/header.hbs +1 -7
  90. package/addon/components/order/route-editor.hbs +4 -25
  91. package/addon/components/order/schedule-card.hbs +102 -95
  92. package/addon/components/order/schedule-card.js +8 -3
  93. package/addon/components/order-config-manager/details.hbs +2 -10
  94. package/addon/components/order-config-manager/entities.hbs +1 -7
  95. package/addon/components/order-config-manager.hbs +1 -6
  96. package/addon/components/part/card.hbs +49 -0
  97. package/addon/components/part/card.js +6 -0
  98. package/addon/components/part/details.hbs +102 -56
  99. package/addon/components/part/form.hbs +131 -56
  100. package/addon/components/part/form.js +78 -11
  101. package/addon/components/part/panel-header.hbs +36 -0
  102. package/addon/components/part/panel-header.js +2 -0
  103. package/addon/components/place/form.hbs +1 -7
  104. package/addon/components/sensor/details.hbs +1 -1
  105. package/addon/components/sensor/form.hbs +5 -3
  106. package/addon/components/sensor/panel-header.hbs +8 -1
  107. package/addon/components/service-area/form.hbs +1 -6
  108. package/addon/components/service-rate/form.hbs +12 -60
  109. package/addon/components/telematic/form.hbs +6 -2
  110. package/addon/components/vehicle/details/maintenance-history.hbs +42 -0
  111. package/addon/components/vehicle/details/maintenance-history.js +32 -0
  112. package/addon/components/vehicle/details/schedules.hbs +40 -0
  113. package/addon/components/vehicle/details/schedules.js +32 -0
  114. package/addon/components/vehicle/details/work-orders.hbs +42 -0
  115. package/addon/components/vehicle/details/work-orders.js +32 -0
  116. package/addon/components/vehicle/details.hbs +30 -0
  117. package/addon/components/vehicle/form.hbs +39 -0
  118. package/addon/components/vehicle/panel-header.hbs +19 -49
  119. package/addon/components/warranty/details.hbs +3 -2
  120. package/addon/components/warranty/form.hbs +3 -17
  121. package/addon/components/work-order/details.hbs +135 -40
  122. package/addon/components/work-order/form.hbs +178 -45
  123. package/addon/components/work-order/form.js +197 -4
  124. package/addon/components/work-order/panel-header.hbs +31 -0
  125. package/addon/components/work-order/panel-header.js +2 -0
  126. package/addon/controllers/connectivity/devices/index/details.js +1 -1
  127. package/addon/controllers/maintenance/equipment/index/details/index.js +0 -1
  128. package/addon/controllers/maintenance/equipment/index/details.js +36 -1
  129. package/addon/controllers/maintenance/equipment/index/edit.js +56 -1
  130. package/addon/controllers/maintenance/equipment/index/new.js +32 -1
  131. package/addon/controllers/maintenance/equipment/index.js +127 -113
  132. package/addon/controllers/maintenance/maintenances/index/details/index.js +3 -0
  133. package/addon/controllers/maintenance/maintenances/index/details.js +54 -0
  134. package/addon/controllers/maintenance/maintenances/index/edit.js +68 -0
  135. package/addon/controllers/maintenance/maintenances/index/new.js +34 -0
  136. package/addon/controllers/maintenance/maintenances/index.js +191 -0
  137. package/addon/controllers/maintenance/parts/index/details/index.js +0 -1
  138. package/addon/controllers/maintenance/parts/index/details.js +36 -1
  139. package/addon/controllers/maintenance/parts/index/edit.js +56 -1
  140. package/addon/controllers/maintenance/parts/index/new.js +32 -1
  141. package/addon/controllers/maintenance/parts/index.js +135 -113
  142. package/addon/controllers/maintenance/schedules/index/details.js +115 -0
  143. package/addon/controllers/maintenance/schedules/index/edit.js +41 -0
  144. package/addon/controllers/maintenance/schedules/index/new.js +33 -0
  145. package/addon/controllers/maintenance/schedules/index.js +280 -0
  146. package/addon/controllers/maintenance/work-orders/index/details.js +41 -1
  147. package/addon/controllers/maintenance/work-orders/index/edit.js +67 -1
  148. package/addon/controllers/maintenance/work-orders/index/new.js +43 -1
  149. package/addon/controllers/maintenance/work-orders/index.js +105 -113
  150. package/addon/controllers/management/drivers/index/details.js +6 -1
  151. package/addon/controllers/management/vehicles/index/details.js +65 -0
  152. package/addon/controllers/management/vehicles/index.js +18 -0
  153. package/addon/controllers/operations/orchestrator.js +10 -0
  154. package/addon/controllers/operations/orders/index.js +6 -0
  155. package/addon/controllers/operations/scheduler/fleet-schedule.js +341 -0
  156. package/addon/controllers/operations/scheduler/index.js +799 -275
  157. package/addon/controllers/operations/scheduler.js +21 -0
  158. package/addon/controllers/settings/orchestrator.js +70 -0
  159. package/addon/controllers/settings/scheduling.js +155 -0
  160. package/addon/extension.js +19 -0
  161. package/addon/instance-initializers/register-vroom-allocation.js +27 -0
  162. package/addon/models/maintenance-schedule.js +61 -0
  163. package/addon/routes/maintenance/equipment/index/details.js +27 -1
  164. package/addon/routes/maintenance/equipment/index/edit.js +27 -1
  165. package/addon/routes/maintenance/maintenances/index/details/index.js +3 -0
  166. package/addon/routes/maintenance/maintenances/index/details.js +29 -0
  167. package/addon/routes/maintenance/maintenances/index/edit.js +29 -0
  168. package/addon/routes/maintenance/maintenances/index/new.js +3 -0
  169. package/addon/routes/maintenance/maintenances/index.js +23 -0
  170. package/addon/routes/maintenance/maintenances.js +3 -0
  171. package/addon/routes/maintenance/parts/index/details.js +27 -1
  172. package/addon/routes/maintenance/parts/index/edit.js +27 -1
  173. package/addon/routes/maintenance/schedules/index/details/index.js +2 -0
  174. package/addon/routes/maintenance/schedules/index/details/work-orders.js +11 -0
  175. package/addon/routes/maintenance/schedules/index/details.js +25 -0
  176. package/addon/routes/maintenance/schedules/index/edit.js +25 -0
  177. package/addon/routes/maintenance/schedules/index/new.js +2 -0
  178. package/addon/routes/maintenance/schedules/index.js +21 -0
  179. package/addon/routes/maintenance/schedules.js +2 -0
  180. package/addon/routes/maintenance/work-orders/index/details.js +27 -1
  181. package/addon/routes/maintenance/work-orders/index/edit.js +27 -1
  182. package/addon/routes/management/vehicles/index/details/maintenance-history.js +3 -0
  183. package/addon/routes/management/vehicles/index/details/schedules.js +3 -0
  184. package/addon/routes/management/vehicles/index/details/work-orders.js +3 -0
  185. package/addon/routes/operations/orchestrator.js +23 -0
  186. package/addon/routes/operations/scheduler/fleet-schedule.js +28 -0
  187. package/addon/routes/operations/scheduler/index.js +48 -26
  188. package/addon/routes/operations/scheduler.js +14 -1
  189. package/addon/routes/settings/orchestrator.js +27 -0
  190. package/addon/routes/settings/scheduling.js +3 -0
  191. package/addon/routes.js +31 -1
  192. package/addon/services/driver-actions.js +40 -7
  193. package/addon/services/driver-scheduling.js +4 -1
  194. package/addon/services/equipment-actions.js +15 -5
  195. package/addon/services/leaflet-map-manager.js +14 -6
  196. package/addon/services/maintenance-actions.js +17 -14
  197. package/addon/services/maintenance-schedule-actions.js +118 -0
  198. package/addon/services/orchestration-engine-interface.js +49 -0
  199. package/addon/services/orchestration-engine.js +74 -0
  200. package/addon/services/order-actions.js +15 -0
  201. package/addon/services/order-allocation.js +116 -0
  202. package/addon/services/part-actions.js +12 -2
  203. package/addon/services/scheduling.js +316 -0
  204. package/addon/services/vehicle-actions.js +70 -7
  205. package/addon/services/vroom-allocation-engine.js +45 -0
  206. package/addon/services/work-order-actions.js +80 -0
  207. package/addon/styles/fleetops-engine.css +1658 -0
  208. package/addon/templates/analytics/reports/index/edit.hbs +1 -1
  209. package/addon/templates/analytics/reports/index/new.hbs +1 -1
  210. package/addon/templates/application.hbs +6 -1
  211. package/addon/templates/connectivity/devices/index/details/events.hbs +0 -1
  212. package/addon/templates/connectivity/devices.hbs +0 -1
  213. package/addon/templates/connectivity/events/index/details.hbs +0 -1
  214. package/addon/templates/connectivity/events.hbs +0 -1
  215. package/addon/templates/connectivity/sensors.hbs +0 -1
  216. package/addon/templates/connectivity/telematics/index/details/devices.hbs +0 -1
  217. package/addon/templates/connectivity/telematics/index/details/events.hbs +0 -1
  218. package/addon/templates/connectivity/telematics/index/details/sensors.hbs +0 -1
  219. package/addon/templates/connectivity/telematics.hbs +0 -1
  220. package/addon/templates/connectivity/tracking.hbs +0 -1
  221. package/addon/templates/connectivity.hbs +0 -1
  222. package/addon/templates/maintenance/equipment/index/details/index.hbs +1 -2
  223. package/addon/templates/maintenance/equipment/index/details.hbs +15 -2
  224. package/addon/templates/maintenance/equipment/index/edit.hbs +12 -2
  225. package/addon/templates/maintenance/equipment/index/new.hbs +1 -2
  226. package/addon/templates/maintenance/equipment/index.hbs +48 -13
  227. package/addon/templates/maintenance/equipment.hbs +0 -1
  228. package/addon/templates/maintenance/maintenances/index/details/index.hbs +1 -0
  229. package/addon/templates/maintenance/maintenances/index/details.hbs +15 -0
  230. package/addon/templates/maintenance/maintenances/index/edit.hbs +12 -0
  231. package/addon/templates/maintenance/maintenances/index/new.hbs +11 -0
  232. package/addon/templates/maintenance/maintenances/index.hbs +14 -0
  233. package/addon/templates/maintenance/maintenances.hbs +1 -0
  234. package/addon/templates/maintenance/parts/index/details/index.hbs +1 -2
  235. package/addon/templates/maintenance/parts/index/details.hbs +15 -2
  236. package/addon/templates/maintenance/parts/index/edit.hbs +12 -2
  237. package/addon/templates/maintenance/parts/index/new.hbs +1 -2
  238. package/addon/templates/maintenance/parts/index.hbs +48 -13
  239. package/addon/templates/maintenance/parts.hbs +0 -1
  240. package/addon/templates/maintenance/schedules/index/details/index.hbs +1 -0
  241. package/addon/templates/maintenance/schedules/index/details/work-orders.hbs +39 -0
  242. package/addon/templates/maintenance/schedules/index/details.hbs +14 -0
  243. package/addon/templates/maintenance/schedules/index/edit.hbs +12 -0
  244. package/addon/templates/maintenance/schedules/index/new.hbs +11 -0
  245. package/addon/templates/maintenance/schedules/index.hbs +40 -0
  246. package/addon/templates/maintenance/schedules.hbs +1 -0
  247. package/addon/templates/maintenance/work-orders/index/details.hbs +2 -1
  248. package/addon/templates/maintenance/work-orders/index/edit.hbs +2 -4
  249. package/addon/templates/maintenance/work-orders/index/new.hbs +1 -2
  250. package/addon/templates/maintenance/work-orders.hbs +0 -1
  251. package/addon/templates/management/contacts/customers/edit.hbs +1 -2
  252. package/addon/templates/management/contacts/customers/new.hbs +1 -2
  253. package/addon/templates/management/contacts/customers.hbs +1 -1
  254. package/addon/templates/management/contacts/index/edit.hbs +1 -2
  255. package/addon/templates/management/contacts/index/new.hbs +1 -2
  256. package/addon/templates/management/drivers/index/details/orders.hbs +0 -1
  257. package/addon/templates/management/drivers/index/edit.hbs +1 -2
  258. package/addon/templates/management/drivers/index/new.hbs +1 -2
  259. package/addon/templates/management/fleets/index/edit.hbs +1 -2
  260. package/addon/templates/management/fleets/index/new.hbs +1 -2
  261. package/addon/templates/management/fleets/index.hbs +1 -2
  262. package/addon/templates/management/fuel-reports/index/edit.hbs +1 -2
  263. package/addon/templates/management/fuel-reports/index/new.hbs +1 -2
  264. package/addon/templates/management/fuel-reports/index.hbs +1 -2
  265. package/addon/templates/management/issues/index/edit.hbs +1 -2
  266. package/addon/templates/management/issues/index/new.hbs +1 -2
  267. package/addon/templates/management/issues/index.hbs +1 -2
  268. package/addon/templates/management/places/index/details/activity.hbs +0 -1
  269. package/addon/templates/management/places/index/details/comments.hbs +0 -1
  270. package/addon/templates/management/places/index/details/documents.hbs +0 -1
  271. package/addon/templates/management/places/index/details/map.hbs +0 -1
  272. package/addon/templates/management/places/index/details/operations.hbs +0 -1
  273. package/addon/templates/management/places/index/details/performance.hbs +0 -1
  274. package/addon/templates/management/places/index/details/rules.hbs +0 -1
  275. package/addon/templates/management/vehicles/index/details/equipment.hbs +0 -1
  276. package/addon/templates/management/vehicles/index/details/maintenance-history.hbs +2 -0
  277. package/addon/templates/management/vehicles/index/details/schedules.hbs +2 -0
  278. package/addon/templates/management/vehicles/index/details/work-orders.hbs +2 -0
  279. package/addon/templates/management/vehicles/index/details.hbs +1 -1
  280. package/addon/templates/management/vehicles/index/edit.hbs +1 -2
  281. package/addon/templates/management/vehicles/index/new.hbs +1 -2
  282. package/addon/templates/management/vendors/index/edit.hbs +1 -2
  283. package/addon/templates/management/vendors/index/new.hbs +1 -2
  284. package/addon/templates/management/vendors/index.hbs +1 -2
  285. package/addon/templates/management/vendors/integrated.hbs +1 -2
  286. package/addon/templates/operations/orchestrator.hbs +1 -0
  287. package/addon/templates/operations/orders/index.hbs +6 -1
  288. package/addon/templates/operations/scheduler/fleet-schedule.hbs +41 -0
  289. package/addon/templates/operations/scheduler/index.hbs +147 -88
  290. package/addon/templates/operations/scheduler.hbs +7 -1
  291. package/addon/templates/settings/avatars.hbs +1 -1
  292. package/addon/templates/settings/orchestrator.hbs +65 -0
  293. package/addon/templates/settings/payments/index.hbs +1 -5
  294. package/addon/templates/settings/scheduling.hbs +82 -0
  295. package/addon/utils/create-full-calendar-event-from-order.js +52 -14
  296. package/addon/utils/create-full-calendar-event-from-schedule-item.js +50 -0
  297. package/addon/utils/fleet-ops-options.js +254 -0
  298. package/addon/utils/route-colors.js +99 -0
  299. package/addon/utils/to-calendar-date.js +70 -0
  300. package/app/components/driver/schedule.js +1 -0
  301. package/app/components/maintenance/cost-panel.js +1 -0
  302. package/app/components/maintenance/panel-header.js +1 -0
  303. package/app/components/maintenance-schedule/details.js +1 -0
  304. package/app/components/maintenance-schedule/form.js +1 -0
  305. package/app/components/modals/add-driver-shift.js +1 -0
  306. package/app/components/modals/bulk-assign-orders.js +1 -0
  307. package/app/components/modals/driver-shift.js +1 -0
  308. package/app/components/modals/orchestrator-import.js +1 -0
  309. package/app/components/modals/scheduling-conflict.js +1 -0
  310. package/app/components/modals/send-work-order.js +1 -0
  311. package/app/components/modals/set-driver-availability.js +1 -0
  312. package/app/components/orchestrator/card-fields-settings.js +1 -0
  313. package/app/components/orchestrator/order-pool.js +1 -0
  314. package/app/components/orchestrator/phase-builder.js +1 -0
  315. package/app/components/orchestrator/plan-viewer.js +1 -0
  316. package/app/components/orchestrator/resource-panel.js +1 -0
  317. package/app/components/orchestrator-workbench.js +1 -0
  318. package/app/components/vehicle/details/maintenance-history.js +1 -0
  319. package/app/components/vehicle/details/schedules.js +1 -0
  320. package/app/components/vehicle/details/work-orders.js +1 -0
  321. package/app/controllers/operations/orchestrator.js +1 -0
  322. package/app/controllers/settings/orchestrator.js +1 -0
  323. package/app/controllers/settings/scheduling.js +1 -0
  324. package/app/routes/operations/orchestrator.js +1 -0
  325. package/app/routes/settings/orchestrator.js +1 -0
  326. package/app/routes/settings/scheduling.js +1 -0
  327. package/app/services/maintenance-schedule-actions.js +1 -0
  328. package/app/services/orchestration-engine-interface.js +1 -0
  329. package/app/services/orchestration-engine.js +1 -0
  330. package/app/services/order-allocation.js +1 -0
  331. package/app/services/scheduling.js +1 -0
  332. package/app/services/vroom-allocation-engine.js +1 -0
  333. package/app/templates/settings/scheduling.js +1 -0
  334. package/app/utils/create-full-calendar-event-from-schedule-item.js +1 -0
  335. package/app/utils/route-colors.js +1 -0
  336. package/composer.json +5 -3
  337. package/extension.json +1 -1
  338. package/package.json +6 -5
  339. package/server/config/fleetops.php +20 -1
  340. package/server/migrations/2025_08_28_054927_create_parts_table.php +2 -2
  341. package/server/migrations/2025_08_28_054932_add_public_id_to_maintenance_tables.php +45 -0
  342. package/server/migrations/2025_09_01_000001_create_maintenance_schedules_table.php +88 -0
  343. package/server/migrations/2026_04_01_000001_fix_monetary_columns_in_parts_table.php +48 -0
  344. package/server/migrations/2026_04_01_000003_add_photo_uuid_to_equipment_and_parts_tables.php +61 -0
  345. package/server/migrations/2026_04_01_000004_add_public_id_to_equipments_table.php +38 -0
  346. package/server/migrations/2026_04_01_000005_add_missing_columns_to_parts_table.php +67 -0
  347. package/server/migrations/2026_04_04_000001_add_reminder_offsets_to_maintenance_schedules.php +44 -0
  348. package/server/migrations/2026_04_08_000001_add_orchestrator_columns_to_vehicles_table.php +58 -0
  349. package/server/migrations/2026_04_08_000002_add_orchestrator_columns_to_drivers_table.php +41 -0
  350. package/server/migrations/2026_04_08_000003_add_orchestrator_columns_to_orders_table.php +38 -0
  351. package/server/migrations/2026_04_08_000004_add_orchestrator_columns_to_payloads_table.php +41 -0
  352. package/server/migrations/2026_04_08_000005_add_orchestrator_columns_to_waypoints_table.php +38 -0
  353. package/server/migrations/2026_04_09_000001_create_manifests_table.php +48 -0
  354. package/server/migrations/2026_04_09_000002_create_manifest_stops_table.php +48 -0
  355. package/server/migrations/2026_04_09_000003_add_manifest_uuid_to_orders_table.php +28 -0
  356. package/server/migrations/2026_04_13_000001_add_pod_notes_columns_to_waypoints_table.php +39 -0
  357. package/server/resources/views/mail/maintenance-schedule-reminder.blade.php +59 -0
  358. package/server/resources/views/mail/work-order-dispatched.blade.php +67 -0
  359. package/server/src/Auth/Schemas/FleetOps.php +44 -0
  360. package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +150 -0
  361. package/server/src/Console/Commands/SendMaintenanceReminders.php +128 -0
  362. package/server/src/Http/Controllers/Internal/v1/DriverController.php +1 -0
  363. package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +27 -0
  364. package/server/src/Http/Controllers/Internal/v1/LiveController.php +9 -2
  365. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +165 -0
  366. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +304 -0
  367. package/server/src/Http/Controllers/Internal/v1/ManifestController.php +138 -0
  368. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +975 -0
  369. package/server/src/Http/Controllers/Internal/v1/OrderController.php +42 -0
  370. package/server/src/Http/Controllers/Internal/v1/PartController.php +27 -0
  371. package/server/src/Http/Controllers/Internal/v1/SettingController.php +118 -0
  372. package/server/src/Http/Controllers/Internal/v1/Traits/DriverSchedulingTrait.php +214 -0
  373. package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +68 -0
  374. package/server/src/Http/Resources/v1/Driver.php +1 -0
  375. package/server/src/Http/Resources/v1/Maintenance.php +138 -0
  376. package/server/src/Http/Resources/v1/MaintenanceSchedule.php +137 -0
  377. package/server/src/Http/Resources/v1/Orchestrator/Order.php +116 -0
  378. package/server/src/Http/Resources/v1/Order.php +7 -4
  379. package/server/src/Http/Resources/v1/Waypoint.php +7 -0
  380. package/server/src/Http/Resources/v1/WorkOrder.php +136 -0
  381. package/server/src/Imports/EquipmentImport.php +32 -0
  382. package/server/src/Imports/MaintenanceImport.php +32 -0
  383. package/server/src/Imports/MaintenanceScheduleImport.php +32 -0
  384. package/server/src/Imports/PartImport.php +32 -0
  385. package/server/src/Imports/WorkOrderImport.php +32 -0
  386. package/server/src/Jobs/ProcessAllocationJob.php +119 -0
  387. package/server/src/Listeners/HandleDeliveryCompletion.php +47 -0
  388. package/server/src/Listeners/NotifyDriverOnShiftChange.php +63 -0
  389. package/server/src/Mail/MaintenanceScheduleReminder.php +68 -0
  390. package/server/src/Mail/WorkOrderDispatched.php +58 -0
  391. package/server/src/Models/Asset.php +2 -2
  392. package/server/src/Models/Device.php +1 -1
  393. package/server/src/Models/Driver.php +82 -4
  394. package/server/src/Models/Equipment.php +62 -2
  395. package/server/src/Models/Maintenance.php +127 -9
  396. package/server/src/Models/MaintenanceSchedule.php +353 -0
  397. package/server/src/Models/Manifest.php +214 -0
  398. package/server/src/Models/ManifestStop.php +162 -0
  399. package/server/src/Models/Order.php +70 -0
  400. package/server/src/Models/OrderConfig.php +5 -2
  401. package/server/src/Models/Part.php +69 -3
  402. package/server/src/Models/Payload.php +7 -2
  403. package/server/src/Models/Place.php +1 -1
  404. package/server/src/Models/Sensor.php +1 -1
  405. package/server/src/Models/ServiceQuote.php +1 -1
  406. package/server/src/Models/Vehicle.php +20 -1
  407. package/server/src/Models/Warranty.php +1 -1
  408. package/server/src/Models/Waypoint.php +7 -1
  409. package/server/src/Models/WorkOrder.php +122 -12
  410. package/server/src/Notifications/DriverShiftChanged.php +110 -0
  411. package/server/src/Observers/WorkOrderObserver.php +107 -0
  412. package/server/src/Orchestration/Contracts/OrchestrationEngineInterface.php +63 -0
  413. package/server/src/Orchestration/Engines/DriverAssignmentEngine.php +265 -0
  414. package/server/src/Orchestration/Engines/GreedyOrchestrationEngine.php +155 -0
  415. package/server/src/Orchestration/Engines/RouteSequencingEngine.php +272 -0
  416. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +192 -0
  417. package/server/src/Orchestration/OrchestrationEngineRegistry.php +83 -0
  418. package/server/src/Orchestration/Support/OrchestrationPayloadBuilder.php +290 -0
  419. package/server/src/Providers/EventServiceProvider.php +7 -1
  420. package/server/src/Providers/FleetOpsServiceProvider.php +42 -15
  421. package/server/src/routes.php +65 -4
  422. package/translations/ar-ae.yml +44 -12
  423. package/translations/bg-bg.yaml +51 -10
  424. package/translations/en-us.yaml +444 -1
  425. package/translations/fr-fr.yaml +51 -10
  426. package/translations/mn-mn.yaml +51 -10
  427. package/translations/pt-br.yaml +51 -10
  428. package/translations/ru-ru.yaml +51 -10
  429. package/translations/vi-vn.yaml +48 -12
@@ -0,0 +1,287 @@
1
+ <div class="schedule-form" ...attributes>
2
+
3
+ {{! ===== IDENTIFICATION ===== }}
4
+ <ContentPanel @title="Schedule Details" @open={{true}} @wrapperClass="bordered-top">
5
+ <div class="grid grid-cols-1 gap-2 lg:grid-cols-2 lg:gap-2 no-input-group-padding text-xs">
6
+ <InputGroup @name="Schedule Name" @wrapperClass="col-span-2">
7
+ <Input @value={{@resource.name}} @type="text" class="w-full form-input" placeholder="e.g. Oil & Filter Change — Truck #4" disabled={{cannot-write @resource}} />
8
+ </InputGroup>
9
+
10
+ <InputGroup @name="Type">
11
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
12
+ <PowerSelect
13
+ @options={{this.typeOptions}}
14
+ @selected={{@resource.type}}
15
+ @onChange={{fn (mut @resource.type)}}
16
+ @placeholder="Select Type"
17
+ @triggerClass="form-select form-input"
18
+ @disabled={{cannot-write @resource}}
19
+ as |type|
20
+ >
21
+ {{smart-humanize type}}
22
+ </PowerSelect>
23
+ </div>
24
+ </InputGroup>
25
+
26
+ <InputGroup @name="Status">
27
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
28
+ <PowerSelect
29
+ @options={{this.statusOptions}}
30
+ @selected={{@resource.status}}
31
+ @onChange={{fn (mut @resource.status)}}
32
+ @placeholder="Select Status"
33
+ @triggerClass="form-select form-input"
34
+ @disabled={{cannot-write @resource}}
35
+ as |status|
36
+ >
37
+ {{smart-humanize status}}
38
+ </PowerSelect>
39
+ </div>
40
+ </InputGroup>
41
+
42
+ </div>
43
+ </ContentPanel>
44
+
45
+ {{! ===== ASSET (SUBJECT) ===== }}
46
+ <ContentPanel @title="Asset" @open={{true}} @wrapperClass="bordered-top">
47
+ <div class="grid grid-cols-1 gap-2 lg:grid-cols-2 lg:gap-2 no-input-group-padding text-xs">
48
+
49
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-1">
50
+ Which asset does this schedule apply to?
51
+ </div>
52
+
53
+ <InputGroup @name="Asset Type">
54
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
55
+ <PowerSelect
56
+ @options={{this.subjectTypeOptions}}
57
+ @selected={{this.selectedSubjectType}}
58
+ @onChange={{this.onSubjectTypeChange}}
59
+ @placeholder="Select Asset Type"
60
+ @triggerClass="form-select form-input"
61
+ @disabled={{cannot-write @resource}}
62
+ as |option|
63
+ >
64
+ {{option.label}}
65
+ </PowerSelect>
66
+ </div>
67
+ </InputGroup>
68
+
69
+ {{#if this.subjectModelName}}
70
+ <InputGroup @name="Asset">
71
+ <ModelSelect
72
+ @modelName={{this.subjectModelName}}
73
+ @selectedModel={{@resource.subject}}
74
+ @placeholder="Select Asset"
75
+ @triggerClass="form-select form-input"
76
+ @infiniteScroll={{false}}
77
+ @renderInPlace={{true}}
78
+ @onChange={{this.assignSubject}}
79
+ @disabled={{cannot-write @resource}}
80
+ as |model|
81
+ >
82
+ {{or model.displayName model.name model.public_id}}
83
+ </ModelSelect>
84
+ </InputGroup>
85
+ {{/if}}
86
+
87
+ </div>
88
+ </ContentPanel>
89
+
90
+ {{! ===== INTERVAL ===== }}
91
+ <ContentPanel @title="Maintenance Interval" @open={{true}} @wrapperClass="bordered-top">
92
+ <div class="grid grid-cols-1 gap-2 lg:grid-cols-2 lg:gap-2 no-input-group-padding text-xs">
93
+
94
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-1">
95
+ How should this maintenance be triggered?
96
+ </div>
97
+
98
+ {{! Interval method selector — drives which fields are shown below }}
99
+ <InputGroup @name="Interval Method" @wrapperClass="col-span-2">
100
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
101
+ <PowerSelect
102
+ @options={{this.intervalMethodOptions}}
103
+ @selected={{this.selectedIntervalMethod}}
104
+ @onChange={{this.onIntervalMethodChange}}
105
+ @placeholder="Select interval method"
106
+ @triggerClass="form-select form-input"
107
+ @disabled={{cannot-write @resource}}
108
+ as |option|
109
+ >
110
+ {{option.label}}
111
+ </PowerSelect>
112
+ </div>
113
+ </InputGroup>
114
+
115
+ {{! TIME-BASED fields }}
116
+ {{#if this.isTimeBased}}
117
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-3">
118
+ Time-Based Interval
119
+ </div>
120
+ <InputGroup @name="Every">
121
+ <Input @value={{@resource.interval_value}} @type="number" class="w-full form-input" placeholder="e.g. 3" disabled={{cannot-write @resource}} />
122
+ </InputGroup>
123
+ <InputGroup @name="Unit">
124
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
125
+ <PowerSelect
126
+ @options={{this.intervalUnitOptions}}
127
+ @selected={{@resource.interval_unit}}
128
+ @onChange={{fn (mut @resource.interval_unit)}}
129
+ @placeholder="Select unit"
130
+ @triggerClass="form-select form-input"
131
+ @disabled={{cannot-write @resource}}
132
+ as |unit|
133
+ >
134
+ {{smart-humanize unit}}
135
+ </PowerSelect>
136
+ </div>
137
+ </InputGroup>
138
+ <InputGroup @name="Next Due Date" @wrapperClass="col-span-2">
139
+ <DateTimeInput
140
+ class="form-input"
141
+ @value={{@resource.next_due_date}}
142
+ @minDate={{format-date-fns (now) "yyyy-MM-dd"}}
143
+ @minTime={{format-date-fns (now) "HH:mm"}}
144
+ @onUpdate={{fn (mut @resource.next_due_date)}}
145
+ @disabled={{cannot-write @resource}}
146
+ />
147
+ </InputGroup>
148
+ {{/if}}
149
+
150
+ {{! DISTANCE-BASED fields }}
151
+ {{#if this.isDistanceBased}}
152
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-3">
153
+ Distance-Based Interval
154
+ </div>
155
+ <InputGroup @name="Every (km)">
156
+ <Input @value={{@resource.interval_distance}} @type="number" class="w-full form-input" placeholder="e.g. 5000" disabled={{cannot-write @resource}} />
157
+ </InputGroup>
158
+ <InputGroup @name="Next Due Odometer (km)">
159
+ <Input @value={{@resource.next_due_odometer}} @type="number" class="w-full form-input" placeholder="e.g. 47000" disabled={{cannot-write @resource}} />
160
+ </InputGroup>
161
+ {{/if}}
162
+
163
+ {{! ENGINE HOURS-BASED fields }}
164
+ {{#if this.isEngineHoursBased}}
165
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-3">
166
+ Engine Hours-Based Interval
167
+ </div>
168
+ <InputGroup @name="Every (Engine Hours)">
169
+ <Input @value={{@resource.interval_engine_hours}} @type="number" class="w-full form-input" placeholder="e.g. 250" disabled={{cannot-write @resource}} />
170
+ </InputGroup>
171
+ <InputGroup @name="Next Due Engine Hours">
172
+ <Input @value={{@resource.next_due_engine_hours}} @type="number" class="w-full form-input" placeholder="e.g. 1250" disabled={{cannot-write @resource}} />
173
+ </InputGroup>
174
+ {{/if}}
175
+
176
+ </div>
177
+ </ContentPanel>
178
+
179
+ {{! ===== WORK ORDER DEFAULTS ===== }}
180
+ <ContentPanel @title="Work Order Defaults" @open={{true}} @wrapperClass="bordered-top">
181
+ <div class="grid grid-cols-1 gap-2 lg:grid-cols-2 lg:gap-2 no-input-group-padding text-xs">
182
+
183
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-1">
184
+ These settings are used when a work order is auto-generated from this schedule.
185
+ </div>
186
+
187
+ <InputGroup @name="Default Priority">
188
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
189
+ <PowerSelect
190
+ @options={{this.priorityOptions}}
191
+ @selected={{@resource.default_priority}}
192
+ @onChange={{fn (mut @resource.default_priority)}}
193
+ @placeholder="Select Priority"
194
+ @triggerClass="form-select form-input"
195
+ @disabled={{cannot-write @resource}}
196
+ as |priority|
197
+ >
198
+ {{smart-humanize priority}}
199
+ </PowerSelect>
200
+ </div>
201
+ </InputGroup>
202
+
203
+ <InputGroup @name="Default Assignee Type">
204
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
205
+ <PowerSelect
206
+ @options={{this.assigneeTypeOptions}}
207
+ @selected={{this.selectedAssigneeType}}
208
+ @onChange={{this.onAssigneeTypeChange}}
209
+ @placeholder="Select Assignee Type"
210
+ @triggerClass="form-select form-input"
211
+ @disabled={{cannot-write @resource}}
212
+ as |option|
213
+ >
214
+ {{option.label}}
215
+ </PowerSelect>
216
+ </div>
217
+ </InputGroup>
218
+
219
+ {{#if this.assigneeModelName}}
220
+ <InputGroup @name="Default Assignee" @wrapperClass="col-span-2">
221
+ <ModelSelect
222
+ @modelName={{this.assigneeModelName}}
223
+ @selectedModel={{@resource.default_assignee}}
224
+ @placeholder="Select Default Assignee"
225
+ @triggerClass="form-select form-input"
226
+ @infiniteScroll={{false}}
227
+ @renderInPlace={{true}}
228
+ @onChange={{this.assignDefaultAssignee}}
229
+ @disabled={{cannot-write @resource}}
230
+ as |model|
231
+ >
232
+ {{or model.displayName model.name model.public_id}}
233
+ </ModelSelect>
234
+ </InputGroup>
235
+ {{/if}}
236
+
237
+ <InputGroup @name="Instructions" @wrapperClass="col-span-2">
238
+ <Textarea
239
+ @value={{@resource.instructions}}
240
+ class="w-full form-input"
241
+ rows="3"
242
+ placeholder="Instructions for the technician performing this maintenance..."
243
+ disabled={{cannot-write @resource}}
244
+ />
245
+ </InputGroup>
246
+
247
+ </div>
248
+ </ContentPanel>
249
+
250
+ {{! ===== REMINDER OFFSETS ===== }}
251
+ <ContentPanel @title="Reminder Emails" @open={{true}} @wrapperClass="bordered-top">
252
+ <div class="grid grid-cols-1 gap-2 no-input-group-padding text-xs">
253
+
254
+ <div class="text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-1">
255
+ Send email reminders before the next due date
256
+ </div>
257
+
258
+ <InputGroup @name="Reminder Days Before" @wrapperClass="col-span-2">
259
+ <div class="flex flex-wrap gap-1 p-1 border border-gray-300 dark:border-gray-600 rounded form-input min-h-[36px] items-center">
260
+ {{#each this.reminderOffsets as |offset index|}}
261
+ <span class="inline-flex items-center gap-1 bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 text-xs px-2 py-0.5 rounded">
262
+ {{offset}}
263
+ days
264
+ <button type="button" class="ml-1 text-blue-500 hover:text-red-500" {{on "click" (fn this.removeReminderOffset index)}}>
265
+ &times;
266
+ </button>
267
+ </span>
268
+ {{/each}}
269
+ <Input
270
+ @value={{this.newReminderOffset}}
271
+ @type="number"
272
+ class="flex-1 min-w-[80px] border-0 outline-none bg-transparent text-xs p-0"
273
+ placeholder="Add days (e.g. 7)"
274
+ min="1"
275
+ {{on "keydown" this.onReminderOffsetKeydown}}
276
+ disabled={{cannot-write @resource}}
277
+ />
278
+ </div>
279
+ <p class="text-[11px] text-gray-400 mt-1">
280
+ Press Enter or comma to add each offset. The default assignee will receive an email for each configured offset.
281
+ </p>
282
+ </InputGroup>
283
+
284
+ </div>
285
+ </ContentPanel>
286
+
287
+ </div>
@@ -0,0 +1,199 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { action } from '@ember/object';
4
+
5
+ /**
6
+ * Maps a polymorphic type string to the Ember Data model name used by ModelSelect.
7
+ */
8
+ const TYPE_TO_MODEL = {
9
+ 'fleet-ops:vehicle': 'vehicle',
10
+ 'fleet-ops:equipment': 'equipment',
11
+ 'fleet-ops:vendor': 'vendor',
12
+ 'fleet-ops:contact': 'contact',
13
+ 'fleet-ops:driver': 'driver',
14
+ };
15
+
16
+ /**
17
+ * Maps a concrete Ember Data model name back to the backend polymorphic type string.
18
+ * Used to restore the type selector when editing an existing record that has a
19
+ * loaded @belongsTo('maintenance-subject', {polymorphic: true}) relationship.
20
+ */
21
+ const MODEL_TO_TYPE = {
22
+ 'maintenance-subject-vehicle': 'fleet-ops:vehicle',
23
+ 'maintenance-subject-equipment': 'fleet-ops:equipment',
24
+ // Fall-through for raw vehicle/equipment models passed from vehicle-actions.js
25
+ vehicle: 'fleet-ops:vehicle',
26
+ equipment: 'fleet-ops:equipment',
27
+ vendor: 'fleet-ops:vendor',
28
+ contact: 'fleet-ops:contact',
29
+ driver: 'fleet-ops:driver',
30
+ };
31
+
32
+ /**
33
+ * Maps a concrete Ember Data model name back to the backend polymorphic type string
34
+ * for the default_assignee relationship.
35
+ */
36
+ const ASSIGNEE_MODEL_TO_TYPE = {
37
+ 'facilitator-vendor': 'fleet-ops:vendor',
38
+ 'facilitator-contact': 'fleet-ops:contact',
39
+ 'facilitator-integrated-vendor': 'fleet-ops:vendor',
40
+ vendor: 'fleet-ops:vendor',
41
+ contact: 'fleet-ops:contact',
42
+ driver: 'fleet-ops:driver',
43
+ };
44
+
45
+ const SUBJECT_TYPE_OPTIONS = [
46
+ { label: 'Vehicle', value: 'fleet-ops:vehicle' },
47
+ { label: 'Equipment', value: 'fleet-ops:equipment' },
48
+ ];
49
+
50
+ const ASSIGNEE_TYPE_OPTIONS = [
51
+ { label: 'Vendor', value: 'fleet-ops:vendor' },
52
+ { label: 'Contact', value: 'fleet-ops:contact' },
53
+ { label: 'Driver', value: 'fleet-ops:driver' },
54
+ ];
55
+
56
+ const INTERVAL_METHOD_OPTIONS = [
57
+ { label: 'Time-Based (days / weeks / months)', value: 'time' },
58
+ { label: 'Distance-Based (km / miles)', value: 'distance' },
59
+ { label: 'Engine Hours-Based', value: 'engine_hours' },
60
+ ];
61
+
62
+ export default class MaintenanceScheduleFormComponent extends Component {
63
+ @tracked selectedSubjectType = null;
64
+ @tracked selectedAssigneeType = null;
65
+ @tracked subjectModelName = null;
66
+ @tracked assigneeModelName = null;
67
+ @tracked selectedIntervalMethod = null;
68
+ @tracked reminderOffsets = [];
69
+ @tracked newReminderOffset = '';
70
+
71
+ subjectTypeOptions = SUBJECT_TYPE_OPTIONS;
72
+ assigneeTypeOptions = ASSIGNEE_TYPE_OPTIONS;
73
+ intervalMethodOptions = INTERVAL_METHOD_OPTIONS;
74
+
75
+ statusOptions = ['active', 'paused', 'completed'];
76
+ priorityOptions = ['low', 'normal', 'high', 'critical'];
77
+ intervalUnitOptions = ['days', 'weeks', 'months', 'years'];
78
+ typeOptions = ['oil_change', 'tire_rotation', 'inspection', 'brake_service', 'air_filter', 'transmission', 'coolant', 'battery', 'other'];
79
+
80
+ get isTimeBased() {
81
+ return this.selectedIntervalMethod?.value === 'time';
82
+ }
83
+
84
+ get isDistanceBased() {
85
+ return this.selectedIntervalMethod?.value === 'distance';
86
+ }
87
+
88
+ get isEngineHoursBased() {
89
+ return this.selectedIntervalMethod?.value === 'engine_hours';
90
+ }
91
+
92
+ constructor() {
93
+ super(...arguments);
94
+ const { resource } = this.args;
95
+ if (resource) {
96
+ // Restore subject type selection from the polymorphic relationship.
97
+ // When editing an existing record, resource.subject is a loaded MaintenanceSubject model.
98
+ // When creating from vehicle-actions.js, resource.subject may be a raw vehicle/equipment model.
99
+ const subject = resource.subject;
100
+ if (subject) {
101
+ const modelName = subject.constructor?.modelName ?? subject.modelName;
102
+ const typeValue = MODEL_TO_TYPE[modelName] ?? null;
103
+ if (typeValue) {
104
+ this.selectedSubjectType = SUBJECT_TYPE_OPTIONS.find((o) => o.value === typeValue) ?? null;
105
+ this.subjectModelName = TYPE_TO_MODEL[typeValue] ?? null;
106
+ }
107
+ }
108
+ // Restore assignee type selection from the polymorphic relationship.
109
+ const defaultAssignee = resource.default_assignee;
110
+ if (defaultAssignee) {
111
+ const modelName = defaultAssignee.constructor?.modelName ?? defaultAssignee.modelName;
112
+ const typeValue = ASSIGNEE_MODEL_TO_TYPE[modelName] ?? null;
113
+ if (typeValue) {
114
+ this.selectedAssigneeType = ASSIGNEE_TYPE_OPTIONS.find((o) => o.value === typeValue) ?? null;
115
+ this.assigneeModelName = TYPE_TO_MODEL[typeValue] ?? null;
116
+ }
117
+ }
118
+ // Restore reminder_offsets from the resource
119
+ if (Array.isArray(resource.reminder_offsets)) {
120
+ this.reminderOffsets = [...resource.reminder_offsets];
121
+ }
122
+ // Restore interval method from stored interval_method field, or infer from populated fields
123
+ if (resource.interval_method) {
124
+ this.selectedIntervalMethod = INTERVAL_METHOD_OPTIONS.find((o) => o.value === resource.interval_method) ?? null;
125
+ } else if (resource.interval_distance) {
126
+ this.selectedIntervalMethod = INTERVAL_METHOD_OPTIONS.find((o) => o.value === 'distance') ?? null;
127
+ } else if (resource.interval_engine_hours) {
128
+ this.selectedIntervalMethod = INTERVAL_METHOD_OPTIONS.find((o) => o.value === 'engine_hours') ?? null;
129
+ } else if (resource.interval_value) {
130
+ this.selectedIntervalMethod = INTERVAL_METHOD_OPTIONS.find((o) => o.value === 'time') ?? null;
131
+ }
132
+ }
133
+ }
134
+
135
+ @action onSubjectTypeChange(option) {
136
+ this.selectedSubjectType = option;
137
+ // Clear the subject relationship — user must re-select the asset
138
+ this.args.resource.subject = null;
139
+ this.subjectModelName = TYPE_TO_MODEL[option.value] ?? null;
140
+ }
141
+
142
+ @action assignSubject(model) {
143
+ this.args.resource.subject = model;
144
+ }
145
+
146
+ @action onAssigneeTypeChange(option) {
147
+ this.selectedAssigneeType = option;
148
+ // Clear the default_assignee relationship — user must re-select
149
+ this.args.resource.default_assignee = null;
150
+ this.assigneeModelName = TYPE_TO_MODEL[option.value] ?? null;
151
+ }
152
+
153
+ @action assignDefaultAssignee(model) {
154
+ this.args.resource.default_assignee = model;
155
+ }
156
+
157
+ @action addReminderOffset(value) {
158
+ const days = parseInt(value, 10);
159
+ if (!isNaN(days) && days > 0 && !this.reminderOffsets.includes(days)) {
160
+ this.reminderOffsets = [...this.reminderOffsets, days].sort((a, b) => b - a);
161
+ this.args.resource.reminder_offsets = [...this.reminderOffsets];
162
+ }
163
+ this.newReminderOffset = '';
164
+ }
165
+
166
+ @action removeReminderOffset(index) {
167
+ const updated = [...this.reminderOffsets];
168
+ updated.splice(index, 1);
169
+ this.reminderOffsets = updated;
170
+ this.args.resource.reminder_offsets = [...this.reminderOffsets];
171
+ }
172
+
173
+ @action onReminderOffsetKeydown(event) {
174
+ if (event.key === 'Enter' || event.key === ',') {
175
+ event.preventDefault();
176
+ this.addReminderOffset(this.newReminderOffset);
177
+ }
178
+ }
179
+
180
+ @action onIntervalMethodChange(option) {
181
+ this.selectedIntervalMethod = option;
182
+ // Store the method on the resource so it round-trips correctly on edit
183
+ this.args.resource.interval_method = option.value;
184
+ // Clear fields from the other methods to avoid stale data being sent
185
+ if (option.value !== 'time') {
186
+ this.args.resource.interval_value = null;
187
+ this.args.resource.interval_unit = null;
188
+ this.args.resource.next_due_date = null;
189
+ }
190
+ if (option.value !== 'distance') {
191
+ this.args.resource.interval_distance = null;
192
+ this.args.resource.next_due_odometer = null;
193
+ }
194
+ if (option.value !== 'engine_hours') {
195
+ this.args.resource.interval_engine_hours = null;
196
+ this.args.resource.next_due_engine_hours = null;
197
+ }
198
+ }
199
+ }
@@ -1,3 +1,3 @@
1
- <div class="next-map-container next-map-container-layout-{{or @layout "map"}}" {{did-insert this.didInsert}}>
1
+ <div class="next-map-container next-map-container-layout-{{or @layout 'map'}}" {{did-insert this.didInsert}}>
2
2
  {{yield (hash (component "map/toolbar"))}}
3
3
  </div>
@@ -13,7 +13,7 @@
13
13
  >
14
14
  <div class="space-x-2 text-sm">
15
15
  <div class="inline-block align-top">
16
- <div class="hide-from-trigger h-1.5 w-full" />
16
+ <div class="hide-from-trigger h-1.5 w-full"></div>
17
17
  <Image src={{model.provider_descriptor.icon}} class="w-5 h-5" />
18
18
  </div>
19
19
  <div class="inline-block">
@@ -1,11 +1,6 @@
1
1
  <div class="flex flex-row items-center px-5 py-2 border-b border-gray-200 dark:border-gray-700">
2
2
  <div>
3
- <Input
4
- @value={{this.query}}
5
- @type="text"
6
- class="form-input form-input-sm w-60"
7
- placeholder={{t "live-map-drawer.driver-listing.message"}}
8
- />
3
+ <Input @value={{this.query}} @type="text" class="form-input form-input-sm w-60" placeholder={{t "live-map-drawer.driver-listing.message"}} />
9
4
  </div>
10
5
  </div>
11
6
  <Table @rows={{this.filteredDrivers}} @columns={{this.columns}} />
@@ -1,11 +1,6 @@
1
1
  <div class="flex flex-row items-center px-5 py-2 border-b border-gray-200 dark:border-gray-700">
2
2
  <div>
3
- <Input
4
- @value={{this.query}}
5
- @type="text"
6
- class="form-input form-input-sm w-60"
7
- placeholder={{t "live-map-drawer.place-listing.message"}}
8
- />
3
+ <Input @value={{this.query}} @type="text" class="form-input form-input-sm w-60" placeholder={{t "live-map-drawer.place-listing.message"}} />
9
4
  </div>
10
5
  </div>
11
6
  <Table @rows={{this.filteredPlaces}} @columns={{this.columns}} />
@@ -1,11 +1,6 @@
1
1
  <div class="flex flex-row items-center px-5 py-2 border-b border-gray-200 dark:border-gray-700">
2
2
  <div>
3
- <Input
4
- @value={{this.query}}
5
- @type="text"
6
- class="form-input form-input-sm w-60"
7
- placeholder={{t "live-map-drawer.vehicle-listing.message"}}
8
- />
3
+ <Input @value={{this.query}} @type="text" class="form-input form-input-sm w-60" placeholder={{t "live-map-drawer.vehicle-listing.message"}} />
9
4
  </div>
10
5
  </div>
11
6
  <Table @rows={{this.filteredVehicles}} @columns={{this.columns}} />
@@ -1,4 +1,11 @@
1
- <Drawer @onResizeEnd={{this.mapDrawer.handleResizeEnd}} @onResizeStart={{@onResizeStart}} @isMinimized={{this.mapDrawer.isMinimized}} @isOpen={{@isOpen}} @notchEnabled={{true}} @onLoad={{this.setDrawerContext}}>
1
+ <Drawer
2
+ @onResizeEnd={{this.mapDrawer.handleResizeEnd}}
3
+ @onResizeStart={{@onResizeStart}}
4
+ @isMinimized={{this.mapDrawer.isMinimized}}
5
+ @isOpen={{@isOpen}}
6
+ @notchEnabled={{true}}
7
+ @onLoad={{this.setDrawerContext}}
8
+ >
2
9
  <TabNavigation @tabs={{this.tabs}} @activeTabId={{this.mapDrawer.activeTabId}} @onTabChange={{this.mapDrawer.setActiveTab}} as |activeTab|>
3
10
  {{component (lazy-engine-component activeTab.component)}}
4
11
  </TabNavigation>
@@ -49,7 +49,8 @@
49
49
  <div class="text-xs font-semibold">{{driver.name}}</div>
50
50
  <div class="text-xs">{{t "common.phone"}}: {{n-a driver.phone}}</div>
51
51
  <div class="text-xs">{{t "resource.vehicle"}}: {{n-a driver.vehicle_name}}</div>
52
- <div class="text-xs">{{t "common.status"}}: <span class="{{if driver.online 'text-green-500' 'text-red-400'}}">{{if driver.online "Online" "Offline"}}</span></div>
52
+ <div class="text-xs">{{t "common.status"}}:
53
+ <span class="{{if driver.online 'text-green-500' 'text-red-400'}}">{{if driver.online "Online" "Offline"}}</span></div>
53
54
  <div class="text-xs truncate">{{t "common.pos"}}: {{point-coordinates driver.location}}</div>
54
55
  </div>
55
56
  </div>
@@ -1,4 +1,4 @@
1
- {{!-- template-lint-disable require-context-role --}}
1
+ {{! template-lint-disable require-context-role }}
2
2
  <div class="next-dd-menu overflow-visible">
3
3
  <div class="px-1">
4
4
  <div class="text-sm flex flex-row items-center px-3 py-0.5 rounded-md my-1 text-gray-800 dark:text-gray-300">
@@ -29,13 +29,7 @@
29
29
  </button>
30
30
  {{/let}}
31
31
  {{#let (cannot "fleet-ops list order") as |unauthorized|}}
32
- <button
33
- type="button"
34
- id="map-toolbar-search-button"
35
- class="toolbar-button {{if unauthorized 'unauthorized'}}"
36
- {{on "click" this.globalSearch.toggle}}
37
- disabled={{unauthorized}}
38
- >
32
+ <button type="button" id="map-toolbar-search-button" class="toolbar-button {{if unauthorized 'unauthorized'}}" {{on "click" this.globalSearch.toggle}} disabled={{unauthorized}}>
39
33
  <FaIcon @icon="search" />
40
34
  <Attach::Tooltip @class="clean" @animation="scale" @placement="right">
41
35
  {{#let (if unauthorized (concat (t "common.unauthorized-to") " " (t "common.search")) (t "common.search")) as |unauthorizedMessage|}}
@@ -45,12 +39,7 @@
45
39
  </button>
46
40
  {{/let}}
47
41
  {{#let (cannot "fleet-ops list order") as |unauthorized|}}
48
- <button
49
- type="button"
50
- id="map-toolbar-view-orders-button"
51
- class="toolbar-button relative {{if unauthorized 'unauthorized'}}"
52
- {{on "click" this.orderListOverlay.toggle}}
53
- >
42
+ <button type="button" id="map-toolbar-view-orders-button" class="toolbar-button relative {{if unauthorized 'unauthorized'}}" {{on "click" this.orderListOverlay.toggle}}>
54
43
  <div class="active-orders-count absolute top-0 right-0 -mr-2.5 -mt-1">
55
44
  <div class="relative flex w-5 h-5 rounded-full">
56
45
  <div class="absolute inset-0 rounded-full w-5 h-5 text-xs bg-blue-500 opacity-75 {{if this.activeOrderCount 'animate-ping'}}"></div>
@@ -59,14 +48,7 @@
59
48
  </div>
60
49
  <FaIcon @icon="layer-group" />
61
50
  <Attach::Tooltip @class="clean" @animation="scale" @placement="right">
62
- {{#let
63
- (if
64
- unauthorized
65
- (concat (t "common.unauthorized-to") " " (t "map.toolbar.view-order"))
66
- (t "map.toolbar.view-order")
67
- )
68
- as |unauthorizedMessage|
69
- }}
51
+ {{#let (if unauthorized (concat (t "common.unauthorized-to") " " (t "map.toolbar.view-order")) (t "map.toolbar.view-order")) as |unauthorizedMessage|}}
70
52
  <InputInfo @text={{unauthorizedMessage}} @iconClass="hidden" class="py-1 px-2 bg-gray-900 -mt-1" />
71
53
  {{/let}}
72
54
  </Attach::Tooltip>
@@ -77,14 +59,7 @@
77
59
  <dd.Trigger class="toolbar-button {{if unauthorized 'unauthorized'}}">
78
60
  <FaIcon @icon="map-marked-alt" />
79
61
  <Attach::Tooltip @class="clean" @animation="scale" @placement="right">
80
- {{#let
81
- (if
82
- unauthorized
83
- (concat (t "common.unauthorized-to") " " (t "map.toolbar.view-service-area"))
84
- (t "map.toolbar.view-service-area")
85
- )
86
- as |unauthorizedMessage|
87
- }}
62
+ {{#let (if unauthorized (concat (t "common.unauthorized-to") " " (t "map.toolbar.view-service-area")) (t "map.toolbar.view-service-area")) as |unauthorizedMessage|}}
88
63
  <InputInfo @text={{unauthorizedMessage}} @iconClass="hidden" class="{{if dd.isOpen 'hidden'}} py-1 px-2 bg-gray-900 -mt-1" />
89
64
  {{/let}}
90
65
  </Attach::Tooltip>