@fleetbase/fleetops-engine 0.6.38 → 0.6.40

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 (432) 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 +43 -38
  25. package/addon/components/layout/fleet-ops-sidebar.js +103 -24
  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 +1088 -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 +52 -0
  117. package/addon/components/vehicle/form.hbs +51 -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 +79 -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 +4 -2
  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 +53 -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 +38 -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/migrations/2026_04_14_000001_drop_redundant_capacity_columns_from_payloads_table.php +42 -0
  358. package/server/migrations/2026_04_14_000002_rename_capacity_columns_on_vehicles_table.php +48 -0
  359. package/server/resources/views/mail/maintenance-schedule-reminder.blade.php +59 -0
  360. package/server/resources/views/mail/work-order-dispatched.blade.php +67 -0
  361. package/server/src/Auth/Schemas/FleetOps.php +44 -0
  362. package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +150 -0
  363. package/server/src/Console/Commands/SendMaintenanceReminders.php +128 -0
  364. package/server/src/Http/Controllers/Api/v1/OrderController.php +15 -2
  365. package/server/src/Http/Controllers/Api/v1/VehicleController.php +18 -2
  366. package/server/src/Http/Controllers/Internal/v1/DriverController.php +1 -0
  367. package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +27 -0
  368. package/server/src/Http/Controllers/Internal/v1/LiveController.php +9 -2
  369. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +165 -0
  370. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +304 -0
  371. package/server/src/Http/Controllers/Internal/v1/ManifestController.php +138 -0
  372. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +975 -0
  373. package/server/src/Http/Controllers/Internal/v1/OrderController.php +42 -0
  374. package/server/src/Http/Controllers/Internal/v1/PartController.php +27 -0
  375. package/server/src/Http/Controllers/Internal/v1/SettingController.php +118 -0
  376. package/server/src/Http/Controllers/Internal/v1/Traits/DriverSchedulingTrait.php +214 -0
  377. package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +68 -0
  378. package/server/src/Http/Resources/v1/Driver.php +1 -0
  379. package/server/src/Http/Resources/v1/Maintenance.php +138 -0
  380. package/server/src/Http/Resources/v1/MaintenanceSchedule.php +137 -0
  381. package/server/src/Http/Resources/v1/Orchestrator/Order.php +116 -0
  382. package/server/src/Http/Resources/v1/Order.php +7 -4
  383. package/server/src/Http/Resources/v1/Waypoint.php +7 -0
  384. package/server/src/Http/Resources/v1/WorkOrder.php +136 -0
  385. package/server/src/Imports/EquipmentImport.php +32 -0
  386. package/server/src/Imports/MaintenanceImport.php +32 -0
  387. package/server/src/Imports/MaintenanceScheduleImport.php +32 -0
  388. package/server/src/Imports/PartImport.php +32 -0
  389. package/server/src/Imports/WorkOrderImport.php +32 -0
  390. package/server/src/Jobs/ProcessAllocationJob.php +119 -0
  391. package/server/src/Listeners/HandleDeliveryCompletion.php +47 -0
  392. package/server/src/Listeners/NotifyDriverOnShiftChange.php +63 -0
  393. package/server/src/Mail/MaintenanceScheduleReminder.php +68 -0
  394. package/server/src/Mail/WorkOrderDispatched.php +58 -0
  395. package/server/src/Models/Asset.php +2 -2
  396. package/server/src/Models/Device.php +1 -1
  397. package/server/src/Models/Driver.php +82 -4
  398. package/server/src/Models/Equipment.php +62 -2
  399. package/server/src/Models/Maintenance.php +127 -9
  400. package/server/src/Models/MaintenanceSchedule.php +353 -0
  401. package/server/src/Models/Manifest.php +214 -0
  402. package/server/src/Models/ManifestStop.php +162 -0
  403. package/server/src/Models/Order.php +70 -0
  404. package/server/src/Models/OrderConfig.php +5 -2
  405. package/server/src/Models/Part.php +69 -3
  406. package/server/src/Models/Place.php +1 -1
  407. package/server/src/Models/Sensor.php +1 -1
  408. package/server/src/Models/ServiceQuote.php +1 -1
  409. package/server/src/Models/Vehicle.php +18 -1
  410. package/server/src/Models/Warranty.php +1 -1
  411. package/server/src/Models/Waypoint.php +7 -1
  412. package/server/src/Models/WorkOrder.php +122 -12
  413. package/server/src/Notifications/DriverShiftChanged.php +110 -0
  414. package/server/src/Observers/WorkOrderObserver.php +107 -0
  415. package/server/src/Orchestration/Contracts/OrchestrationEngineInterface.php +63 -0
  416. package/server/src/Orchestration/Engines/DriverAssignmentEngine.php +265 -0
  417. package/server/src/Orchestration/Engines/GreedyOrchestrationEngine.php +155 -0
  418. package/server/src/Orchestration/Engines/RouteSequencingEngine.php +272 -0
  419. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +192 -0
  420. package/server/src/Orchestration/OrchestrationEngineRegistry.php +83 -0
  421. package/server/src/Orchestration/Support/OrchestrationPayloadBuilder.php +380 -0
  422. package/server/src/Providers/EventServiceProvider.php +7 -1
  423. package/server/src/Providers/FleetOpsServiceProvider.php +42 -15
  424. package/server/src/routes.php +65 -4
  425. package/translations/ar-ae.yml +44 -12
  426. package/translations/bg-bg.yaml +51 -10
  427. package/translations/en-us.yaml +444 -1
  428. package/translations/fr-fr.yaml +51 -10
  429. package/translations/mn-mn.yaml +51 -10
  430. package/translations/pt-br.yaml +51 -10
  431. package/translations/ru-ru.yaml +51 -10
  432. package/translations/vi-vn.yaml +48 -12
@@ -1,10 +1,22 @@
1
- <div class="form-wrapper" ...attributes>
2
- <ContentPanel @title="Work Order Details" @open={{true}} @wrapperClass="bordered-top">
1
+ <div class="work-order-form" ...attributes>
2
+
3
+ {{! ===== IDENTIFICATION ===== }}
4
+ <ContentPanel @title="Identification" @open={{true}} @wrapperClass="bordered-top">
3
5
  <div class="grid grid-cols-1 gap-2 lg:grid-cols-2 lg:gap-2 no-input-group-padding text-xs">
6
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-1">
7
+ Work Order Details
8
+ </div>
4
9
  <InputGroup @name="Code">
5
- <Input @value={{@resource.code}} @type="text" class="w-full form-input" placeholder="Work Order Code" disabled={{cannot-write @resource}} />
10
+ <Input @value={{@resource.code}} @type="text" class="w-full form-input" placeholder="Auto-generated if left blank" disabled={{cannot-write @resource}} />
11
+ </InputGroup>
12
+ <InputGroup @name="Subject" @wrapperClass="col-span-2">
13
+ <Input @value={{@resource.subject}} @type="text" class="w-full form-input" placeholder="Brief description of the work order" disabled={{cannot-write @resource}} />
6
14
  </InputGroup>
7
15
 
16
+ {{! Status & Priority }}
17
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-3">
18
+ Status & Priority
19
+ </div>
8
20
  <InputGroup @name="Status">
9
21
  <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
10
22
  <PowerSelect
@@ -20,11 +32,6 @@
20
32
  </PowerSelect>
21
33
  </div>
22
34
  </InputGroup>
23
-
24
- <InputGroup @name="Subject" @wrapperClass="col-span-2">
25
- <Input @value={{@resource.subject}} @type="text" class="w-full form-input" placeholder="Subject" disabled={{cannot-write @resource}} />
26
- </InputGroup>
27
-
28
35
  <InputGroup @name="Priority">
29
36
  <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
30
37
  <PowerSelect
@@ -40,74 +47,200 @@
40
47
  </PowerSelect>
41
48
  </div>
42
49
  </InputGroup>
50
+ </div>
51
+ </ContentPanel>
43
52
 
44
- <InputGroup @name="Assignee">
45
- <ModelSelect
46
- @modelName="user"
47
- @selectedModel={{@resource.assignee}}
48
- @placeholder="Select Assignee"
49
- @triggerClass="form-select form-input"
50
- @infiniteScroll={{false}}
51
- @renderInPlace={{true}}
52
- @onChange={{fn (mut @resource.assignee)}}
53
- @onChangeId={{fn (mut @resource.assignee_uuid)}}
54
- @disabled={{cannot-write @resource}}
55
- as |model|
56
- >
57
- {{model.name}}
58
- </ModelSelect>
53
+ {{! ===== ASSIGNMENT ===== }}
54
+ <ContentPanel @title="Assignment" @open={{true}} @wrapperClass="bordered-top">
55
+ <div class="grid grid-cols-1 gap-2 lg:grid-cols-2 lg:gap-2 no-input-group-padding text-xs">
56
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-1">
57
+ Target Asset
58
+ </div>
59
+ <InputGroup @name="Target Type">
60
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
61
+ <PowerSelect
62
+ @options={{this.targetTypeOptions}}
63
+ @selected={{this.selectedTargetType}}
64
+ @onChange={{this.onTargetTypeChange}}
65
+ @placeholder="Select target type"
66
+ @triggerClass="form-select form-input"
67
+ @disabled={{cannot-write @resource}}
68
+ as |option|
69
+ >
70
+ {{option.label}}
71
+ </PowerSelect>
72
+ </div>
59
73
  </InputGroup>
74
+ {{#if this.targetModelName}}
75
+ <InputGroup @name="Target">
76
+ <ModelSelect
77
+ @modelName={{this.targetModelName}}
78
+ @selectedModel={{@resource.target}}
79
+ @placeholder="Select target asset"
80
+ @triggerClass="form-select form-input"
81
+ @infiniteScroll={{false}}
82
+ @renderInPlace={{true}}
83
+ @onChange={{this.assignTarget}}
84
+ @disabled={{cannot-write @resource}}
85
+ as |model|
86
+ >
87
+ {{or model.name model.subject model.public_id}}
88
+ </ModelSelect>
89
+ </InputGroup>
90
+ {{/if}}
60
91
 
92
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-3">
93
+ Assignee
94
+ </div>
95
+ <InputGroup @name="Assignee Type">
96
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
97
+ <PowerSelect
98
+ @options={{this.assigneeTypeOptions}}
99
+ @selected={{this.selectedAssigneeType}}
100
+ @onChange={{this.onAssigneeTypeChange}}
101
+ @placeholder="Select assignee type"
102
+ @triggerClass="form-select form-input"
103
+ @disabled={{cannot-write @resource}}
104
+ as |option|
105
+ >
106
+ {{option.label}}
107
+ </PowerSelect>
108
+ </div>
109
+ </InputGroup>
110
+ {{#if this.assigneeModelName}}
111
+ <InputGroup @name="Assignee">
112
+ <ModelSelect
113
+ @modelName={{this.assigneeModelName}}
114
+ @selectedModel={{@resource.assignee}}
115
+ @placeholder="Select assignee"
116
+ @triggerClass="form-select form-input"
117
+ @infiniteScroll={{false}}
118
+ @renderInPlace={{true}}
119
+ @onChange={{this.assignAssignee}}
120
+ @disabled={{cannot-write @resource}}
121
+ as |model|
122
+ >
123
+ {{or model.name model.public_id}}
124
+ </ModelSelect>
125
+ </InputGroup>
126
+ {{/if}}
127
+ </div>
128
+ </ContentPanel>
129
+
130
+ {{! ===== SCHEDULING ===== }}
131
+ <ContentPanel @title="Scheduling" @open={{true}} @wrapperClass="bordered-top">
132
+ <div class="grid grid-cols-1 gap-2 lg:grid-cols-2 lg:gap-2 no-input-group-padding text-xs">
133
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-1">
134
+ Dates
135
+ </div>
61
136
  <InputGroup @name="Opened At">
62
137
  <DatePicker
63
- @value={{@resource.opened_at}}
138
+ @value={{or (format-date-fns @resource.opened_at "dd-MM-yyyy") null}}
64
139
  @onChange={{fn (mut @resource.opened_at)}}
65
- @placeholder="Select Opened Date"
66
- @disabled={{cannot-write @resource}}
67
- class="w-full form-input"
140
+ @placeholder="DD-MM-YYYY"
141
+ class="filter-date-input w-full flex-1"
68
142
  />
69
143
  </InputGroup>
70
-
71
144
  <InputGroup @name="Due At">
72
145
  <DatePicker
73
- @value={{@resource.due_at}}
146
+ @value={{or (format-date-fns @resource.due_at "dd-MM-yyyy") null}}
74
147
  @onChange={{fn (mut @resource.due_at)}}
75
- @placeholder="Select Due Date"
76
- @disabled={{cannot-write @resource}}
77
- class="w-full form-input"
148
+ @placeholder="DD-MM-YYYY"
149
+ class="filter-date-input w-full flex-1"
78
150
  />
79
151
  </InputGroup>
80
-
81
152
  <InputGroup @name="Closed At">
82
153
  <DatePicker
83
- @value={{@resource.closed_at}}
154
+ @value={{or (format-date-fns @resource.closed_at "dd-MM-yyyy") null}}
84
155
  @onChange={{fn (mut @resource.closed_at)}}
85
- @placeholder="Select Closed Date"
86
- @disabled={{cannot-write @resource}}
87
- class="w-full form-input"
156
+ @placeholder="DD-MM-YYYY"
157
+ class="filter-date-input w-full flex-1"
88
158
  />
89
159
  </InputGroup>
160
+ </div>
161
+ </ContentPanel>
90
162
 
91
- <InputGroup @name="Instructions" @wrapperClass="col-span-2">
163
+ {{! ===== INSTRUCTIONS ===== }}
164
+ <ContentPanel @title="Instructions" @open={{true}} @wrapperClass="bordered-top">
165
+ <div class="grid grid-cols-1 gap-2 no-input-group-padding text-xs">
166
+ <InputGroup @name="Instructions">
92
167
  <Textarea
93
168
  @value={{@resource.instructions}}
94
169
  aria-label="Instructions"
95
170
  class="w-full form-input"
96
171
  disabled={{cannot-write @resource}}
97
- placeholder="Instructions"
172
+ placeholder="Step-by-step instructions for the technician"
98
173
  rows={{5}}
99
174
  />
100
175
  </InputGroup>
101
-
102
- <RegistryYield @registry="fleet-ops:component:work-order:form:details" as |RegistryComponent|>
103
- <RegistryComponent @resource={{@resource}} @controller={{@controller}} @permission={{get-write-permission @resource}} />
104
- </RegistryYield>
105
176
  </div>
106
177
  </ContentPanel>
107
178
 
108
- <CustomField::Yield @subject={{@resource}} @wrapperClass="bordered-top" />
179
+ {{! ===== COMPLETION DATA (shown when status = closed) ===== }}
180
+ {{#if this.isCompleting}}
181
+ <ContentPanel @title="Completion Details" @open={{true}} @wrapperClass="bordered-top">
182
+ <div class="grid grid-cols-1 gap-2 lg:grid-cols-2 lg:gap-2 no-input-group-padding text-xs">
183
+ <div class="col-span-1 lg:col-span-2 text-[11px] uppercase tracking-wide text-gray-500 font-semibold mt-1">
184
+ Record what was actually done — this will auto-create a Maintenance History entry.
185
+ </div>
186
+
187
+ <InputGroup @name="Odometer at Completion (km)">
188
+ <Input
189
+ @value={{this.completionOdometer}}
190
+ @type="number"
191
+ class="w-full form-input"
192
+ placeholder="e.g. 47250"
193
+ {{on "input" (fn this.setCompletionOdometer this.completionOdometer)}}
194
+ {{on "change" (fn this.setCompletionOdometer this.completionOdometer)}}
195
+ />
196
+ </InputGroup>
197
+
198
+ <InputGroup @name="Engine Hours at Completion">
199
+ <Input
200
+ @value={{this.completionEngineHours}}
201
+ @type="number"
202
+ class="w-full form-input"
203
+ placeholder="e.g. 1420"
204
+ {{on "input" (fn this.setCompletionEngineHours this.completionEngineHours)}}
205
+ {{on "change" (fn this.setCompletionEngineHours this.completionEngineHours)}}
206
+ />
207
+ </InputGroup>
208
+
209
+ <InputGroup @name="Labour Cost">
210
+ <MoneyInput @value={{this.completionLaborCost}} @currency={{or @resource.currency "USD"}} @disabled={{false}} @onChange={{this.setCompletionLaborCost}} />
211
+ </InputGroup>
212
+
213
+ <InputGroup @name="Parts Cost">
214
+ <MoneyInput @value={{this.completionPartsCost}} @currency={{or @resource.currency "USD"}} @disabled={{false}} @onChange={{this.setCompletionPartsCost}} />
215
+ </InputGroup>
109
216
 
217
+ <InputGroup @name="Tax">
218
+ <MoneyInput @value={{this.completionTax}} @currency={{or @resource.currency "USD"}} @disabled={{false}} @onChange={{this.setCompletionTax}} />
219
+ </InputGroup>
220
+
221
+ <InputGroup @name="Completion Notes" @wrapperClass="col-span-2">
222
+ <Textarea
223
+ @value={{this.completionNotes}}
224
+ class="w-full form-input"
225
+ rows="3"
226
+ placeholder="Notes on what was done, parts replaced, observations..."
227
+ {{on "input" (fn this.setCompletionNotes this.completionNotes)}}
228
+ {{on "change" (fn this.setCompletionNotes this.completionNotes)}}
229
+ />
230
+ </InputGroup>
231
+ </div>
232
+ </ContentPanel>
233
+ {{/if}}
234
+
235
+ {{! ===== REGISTRY & METADATA ===== }}
236
+ <RegistryYield @registry="fleet-ops:component:work-order:form:details" as |RegistryComponent|>
237
+ <RegistryComponent @resource={{@resource}} @controller={{@controller}} @permission={{get-write-permission @resource}} />
238
+ </RegistryYield>
239
+ <CustomField::Yield @subject={{@resource}} @wrapperClass="bordered-top" />
110
240
  <RegistryYield @registry="fleet-ops:component:work-order:form" as |RegistryComponent|>
111
241
  <RegistryComponent @resource={{@resource}} @controller={{@controller}} @permission={{get-write-permission @resource}} />
112
242
  </RegistryYield>
113
- </div>
243
+ <ContentPanel @title="Metadata" @open={{false}} @wrapperClass="bordered-top">
244
+ <MetadataEditor @value={{@resource.meta}} @onChange={{fn (mut @resource.meta)}} />
245
+ </ContentPanel>
246
+ </div>
@@ -1,13 +1,206 @@
1
1
  import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { action } from '@ember/object';
4
+
5
+ /**
6
+ * Maps a user-facing polymorphic type string to the Ember Data model name
7
+ * used by ModelSelect.
8
+ */
9
+ const TYPE_TO_MODEL = {
10
+ 'fleet-ops:vehicle': 'vehicle',
11
+ 'fleet-ops:equipment': 'equipment',
12
+ 'fleet-ops:vendor': 'vendor',
13
+ 'fleet-ops:contact': 'contact',
14
+ 'Auth:User': 'user',
15
+ };
16
+
17
+ /**
18
+ * Maps a concrete Ember Data model name back to the backend polymorphic type string.
19
+ * Used to restore the type selector when editing an existing record that has a
20
+ * loaded @belongsTo('maintenance-subject', {polymorphic: true}) relationship.
21
+ */
22
+ const TARGET_MODEL_TO_TYPE = {
23
+ 'maintenance-subject-vehicle': 'fleet-ops:vehicle',
24
+ 'maintenance-subject-equipment': 'fleet-ops:equipment',
25
+ // Fall-through for raw models passed from vehicle-actions.js
26
+ vehicle: 'fleet-ops:vehicle',
27
+ equipment: 'fleet-ops:equipment',
28
+ };
29
+
30
+ /**
31
+ * Maps a concrete Ember Data model name back to the backend polymorphic type string
32
+ * for the assignee relationship.
33
+ */
34
+ const ASSIGNEE_MODEL_TO_TYPE = {
35
+ 'facilitator-vendor': 'fleet-ops:vendor',
36
+ 'facilitator-contact': 'fleet-ops:contact',
37
+ 'facilitator-integrated-vendor': 'fleet-ops:vendor',
38
+ vendor: 'fleet-ops:vendor',
39
+ contact: 'fleet-ops:contact',
40
+ user: 'Auth:User',
41
+ };
2
42
 
3
43
  export default class WorkOrderFormComponent extends Component {
44
+ /** Status options for work orders. */
45
+ statusOptions = ['open', 'in_progress', 'on_hold', 'completed', 'cancelled'];
46
+
47
+ /** Priority options for work orders. */
48
+ priorityOptions = ['low', 'medium', 'high', 'critical'];
49
+
4
50
  /**
5
- * Status options for work orders
51
+ * Polymorphic target type options the asset a work order is raised against.
6
52
  */
7
- statusOptions = ['open', 'in_progress', 'on_hold', 'completed', 'cancelled'];
53
+ targetTypeOptions = [
54
+ { value: 'fleet-ops:vehicle', label: 'Vehicle' },
55
+ { value: 'fleet-ops:equipment', label: 'Equipment' },
56
+ ];
8
57
 
9
58
  /**
10
- * Priority options
59
+ * Polymorphic assignee type options — who is responsible for completing
60
+ * the work order.
11
61
  */
12
- priorityOptions = ['low', 'medium', 'high', 'critical'];
62
+ assigneeTypeOptions = [
63
+ { value: 'fleet-ops:vendor', label: 'Vendor' },
64
+ { value: 'fleet-ops:contact', label: 'Contact' },
65
+ { value: 'Auth:User', label: 'User' },
66
+ ];
67
+
68
+ /** Derived Ember Data model name for the currently selected target type. */
69
+ @tracked targetModelName = null;
70
+
71
+ /** Derived Ember Data model name for the currently selected assignee type. */
72
+ @tracked assigneeModelName = null;
73
+
74
+ /** The currently selected target type option object (drives the PowerSelect trigger label). */
75
+ @tracked selectedTargetType = null;
76
+
77
+ /** The currently selected assignee type option object. */
78
+ @tracked selectedAssigneeType = null;
79
+
80
+ /**
81
+ * Completion data fields — only used when status is being set to 'closed'.
82
+ * These are pure UI state; they are never persisted directly. Instead, the
83
+ * controller reads them via the @onCompletionChange callback and passes them
84
+ * to workOrderActions.prepareForSave() before calling workOrder.save().
85
+ */
86
+ @tracked completionOdometer = null;
87
+ @tracked completionEngineHours = null;
88
+ @tracked completionLaborCost = null;
89
+ @tracked completionPartsCost = null;
90
+ @tracked completionTax = null;
91
+ @tracked completionNotes = null;
92
+
93
+ /**
94
+ * Returns true when the work order status is set to 'closed', which
95
+ * reveals the Completion Details panel.
96
+ */
97
+ get isCompleting() {
98
+ return this.args.resource?.status === 'closed';
99
+ }
100
+
101
+ constructor(owner, args) {
102
+ super(owner, args);
103
+ const { resource } = args;
104
+
105
+ // Restore target type selection from the polymorphic relationship.
106
+ const target = resource?.target;
107
+ if (target) {
108
+ const modelName = target.constructor?.modelName ?? target.modelName;
109
+ const typeValue = TARGET_MODEL_TO_TYPE[modelName] ?? null;
110
+ if (typeValue) {
111
+ this.targetModelName = TYPE_TO_MODEL[typeValue] ?? null;
112
+ this.selectedTargetType = this.targetTypeOptions.find((o) => o.value === typeValue) ?? null;
113
+ }
114
+ }
115
+
116
+ // Restore assignee type selection from the polymorphic relationship.
117
+ const assignee = resource?.assignee;
118
+ if (assignee) {
119
+ const modelName = assignee.constructor?.modelName ?? assignee.modelName;
120
+ const typeValue = ASSIGNEE_MODEL_TO_TYPE[modelName] ?? null;
121
+ if (typeValue) {
122
+ this.assigneeModelName = TYPE_TO_MODEL[typeValue] ?? null;
123
+ this.selectedAssigneeType = this.assigneeTypeOptions.find((o) => o.value === typeValue) ?? null;
124
+ }
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Handles a change to the target type selector. Resets the target
130
+ * relationship so a stale association is not persisted.
131
+ */
132
+ @action onTargetTypeChange(option) {
133
+ this.selectedTargetType = option;
134
+ this.args.resource.target = null;
135
+ this.targetModelName = TYPE_TO_MODEL[option.value] ?? null;
136
+ }
137
+
138
+ /** Assigns the selected target model to the resource. */
139
+ @action assignTarget(model) {
140
+ this.args.resource.target = model;
141
+ }
142
+
143
+ /**
144
+ * Handles a change to the assignee type selector. Resets the assignee
145
+ * relationship so a stale association is not persisted.
146
+ */
147
+ @action onAssigneeTypeChange(option) {
148
+ this.selectedAssigneeType = option;
149
+ this.args.resource.assignee = null;
150
+ this.assigneeModelName = TYPE_TO_MODEL[option.value] ?? null;
151
+ }
152
+
153
+ /** Assigns the selected assignee model to the resource. */
154
+ @action assignAssignee(model) {
155
+ this.args.resource.assignee = model;
156
+ }
157
+
158
+ /**
159
+ * Notifies the parent (controller) of the current completion field values
160
+ * whenever any completion input changes. The controller stores this plain
161
+ * object and passes it to workOrderActions.prepareForSave() before saving —
162
+ * no component reference is ever held by the controller.
163
+ */
164
+ _notifyCompletionChange() {
165
+ if (typeof this.args.onCompletionChange === 'function') {
166
+ this.args.onCompletionChange({
167
+ odometer: this.completionOdometer,
168
+ engineHours: this.completionEngineHours,
169
+ laborCost: this.completionLaborCost,
170
+ partsCost: this.completionPartsCost,
171
+ tax: this.completionTax,
172
+ notes: this.completionNotes,
173
+ });
174
+ }
175
+ }
176
+
177
+ @action setCompletionOdometer(value) {
178
+ this.completionOdometer = value;
179
+ this._notifyCompletionChange();
180
+ }
181
+
182
+ @action setCompletionEngineHours(value) {
183
+ this.completionEngineHours = value;
184
+ this._notifyCompletionChange();
185
+ }
186
+
187
+ @action setCompletionLaborCost(value) {
188
+ this.completionLaborCost = value;
189
+ this._notifyCompletionChange();
190
+ }
191
+
192
+ @action setCompletionPartsCost(value) {
193
+ this.completionPartsCost = value;
194
+ this._notifyCompletionChange();
195
+ }
196
+
197
+ @action setCompletionTax(value) {
198
+ this.completionTax = value;
199
+ this._notifyCompletionChange();
200
+ }
201
+
202
+ @action setCompletionNotes(value) {
203
+ this.completionNotes = value;
204
+ this._notifyCompletionChange();
205
+ }
13
206
  }
@@ -0,0 +1,31 @@
1
+ <div class="px-4 py-2">
2
+ <div class="flex flex-1 flex-row items-start justify-between">
3
+ <div class="flex flex-col">
4
+ <div class="flex flex-row items-center space-x-2">
5
+ <h1 class="text-gray-900 dark:text-white font-semibold text-lg">{{or @resource.code @resource.subject}}</h1>
6
+ <Badge @status={{@resource.status}}>{{smart-humanize @resource.status}}</Badge>
7
+ </div>
8
+ <div class="flex flex-row space-x-3 mt-1">
9
+ <div class="text-xs text-gray-400 dark:text-gray-500">{{smart-humanize @resource.type}}</div>
10
+ {{#if @resource.priority}}
11
+ <div class="text-xs text-gray-400 dark:text-gray-500">{{t "column.priority"}}: {{smart-humanize @resource.priority}}</div>
12
+ {{/if}}
13
+ {{#if @resource.assignee_name}}
14
+ <div class="text-xs text-gray-400 dark:text-gray-500">{{t "column.assignee"}}: {{@resource.assignee_name}}</div>
15
+ {{/if}}
16
+ </div>
17
+ </div>
18
+ <div class="next-view-header-right">
19
+ <Layout::Resource::Panel::HeaderActions
20
+ @resource={{@resource}}
21
+ @saveTask={{@saveTask}}
22
+ @saveOptions={{@saveOptions}}
23
+ @saveDisabled={{@saveDisabled}}
24
+ @pojoResource={{@pojoResource}}
25
+ @authSchema={{@authSchema}}
26
+ @actionButtons={{@actionButtons}}
27
+ @onPressCancel={{@onPressCancel}}
28
+ />
29
+ </div>
30
+ </div>
31
+ </div>
@@ -0,0 +1,2 @@
1
+ import Component from '@glimmer/component';
2
+ export default class WorkOrderPanelHeaderComponent extends Component {}
@@ -7,7 +7,7 @@ export default class ConnectivityDevicesIndexDetailsController extends Controlle
7
7
  @service hostRouter;
8
8
 
9
9
  get tabs() {
10
- const registeredTabs = this.menuService.getMenuItems('fleet-ops:component:place:details');
10
+ const registeredTabs = this.menuService.getMenuItems('fleet-ops:component:device:details');
11
11
  return [
12
12
  {
13
13
  route: 'connectivity.devices.index.details.index',
@@ -1,3 +1,2 @@
1
1
  import Controller from '@ember/controller';
2
-
3
2
  export default class MaintenanceEquipmentIndexDetailsIndexController extends Controller {}
@@ -1,3 +1,38 @@
1
1
  import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { isArray } from '@ember/array';
2
6
 
3
- export default class MaintenanceEquipmentIndexDetailsController extends Controller {}
7
+ export default class MaintenanceEquipmentIndexDetailsController extends Controller {
8
+ @service equipmentActions;
9
+ @service hostRouter;
10
+ @service intl;
11
+ @service('universe/menu-service') menuService;
12
+
13
+ @tracked overlay;
14
+
15
+ get tabs() {
16
+ const registeredTabs = this.menuService.getMenuItems('fleet-ops:component:equipment:details');
17
+ return [{ route: 'maintenance.equipment.index.details.index', label: this.intl.t('common.overview') }, ...(isArray(registeredTabs) ? registeredTabs : [])];
18
+ }
19
+
20
+ get actionButtons() {
21
+ return [
22
+ { icon: 'edit', fn: this.edit, permission: 'fleet-ops update equipment' },
23
+ { icon: 'trash', fn: this.delete, type: 'danger', permission: 'fleet-ops delete equipment' },
24
+ ];
25
+ }
26
+
27
+ @action edit() {
28
+ return this.hostRouter.transitionTo('console.fleet-ops.maintenance.equipment.index.edit', this.model);
29
+ }
30
+
31
+ @action delete() {
32
+ return this.equipmentActions.delete(this.model, {
33
+ onConfirm: () => {
34
+ this.hostRouter.transitionTo('console.fleet-ops.maintenance.equipment.index');
35
+ },
36
+ });
37
+ }
38
+ }
@@ -1,3 +1,58 @@
1
1
  import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { task } from 'ember-concurrency';
2
6
 
3
- export default class MaintenanceEquipmentIndexEditController extends Controller {}
7
+ export default class MaintenanceEquipmentIndexEditController extends Controller {
8
+ @service hostRouter;
9
+ @service intl;
10
+ @service notifications;
11
+ @service modalsManager;
12
+ @service events;
13
+
14
+ @tracked overlay;
15
+
16
+ get actionButtons() {
17
+ return [{ icon: 'eye', fn: this.view }];
18
+ }
19
+
20
+ @task *save(equipment) {
21
+ try {
22
+ yield equipment.save();
23
+ this.events.trackResourceUpdated(equipment);
24
+ this.overlay?.close();
25
+ yield this.hostRouter.transitionTo('console.fleet-ops.maintenance.equipment.index.details', equipment);
26
+ this.notifications.success(this.intl.t('common.resource-updated-success', { resource: this.intl.t('resource.equipment'), resourceName: equipment.name }));
27
+ } catch (err) {
28
+ this.notifications.serverError(err);
29
+ }
30
+ }
31
+
32
+ @action cancel() {
33
+ if (this.model.hasDirtyAttributes) {
34
+ return this.#confirmContinueWithUnsavedChanges(this.model);
35
+ }
36
+ return this.hostRouter.transitionTo('console.fleet-ops.maintenance.equipment.index');
37
+ }
38
+
39
+ @action view() {
40
+ if (this.model.hasDirtyAttributes) {
41
+ return this.#confirmContinueWithUnsavedChanges(this.model);
42
+ }
43
+ return this.hostRouter.transitionTo('console.fleet-ops.maintenance.equipment.index.details', this.model);
44
+ }
45
+
46
+ #confirmContinueWithUnsavedChanges(equipment, options = {}) {
47
+ return this.modalsManager.confirm({
48
+ title: this.intl.t('common.continue-without-saving'),
49
+ body: this.intl.t('common.continue-without-saving-prompt', { resource: this.intl.t('resource.equipment') }),
50
+ acceptButtonText: this.intl.t('common.continue'),
51
+ confirm: async () => {
52
+ equipment.rollbackAttributes();
53
+ await this.hostRouter.transitionTo('console.fleet-ops.maintenance.equipment.index.details', equipment);
54
+ },
55
+ ...options,
56
+ });
57
+ }
58
+ }