@fleetbase/fleetops-engine 0.6.51 → 0.6.53

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 (396) hide show
  1. package/README.md +0 -2
  2. package/addon/components/cell/telematic-provider.hbs +16 -0
  3. package/addon/components/cell/telematic-provider.js +36 -0
  4. package/addon/components/cell/telematic-status.hbs +1 -0
  5. package/addon/components/cell/telematic-status.js +39 -0
  6. package/addon/components/device/manager.hbs +5 -6
  7. package/addon/components/device/manager.js +12 -15
  8. package/addon/components/driver/details.hbs +1 -1
  9. package/addon/components/fleet/vehicle-listing.js +1 -0
  10. package/addon/components/fuel-integration/form.hbs +200 -0
  11. package/addon/components/fuel-integration/form.js +242 -0
  12. package/addon/components/fuel-integration/hub.hbs +154 -0
  13. package/addon/components/fuel-integration/hub.js +165 -0
  14. package/addon/components/fuel-integration/matching-priority.hbs +76 -0
  15. package/addon/components/fuel-integration/matching-priority.js +145 -0
  16. package/addon/components/fuel-report/details.hbs +13 -1
  17. package/addon/components/issue/details.hbs +3 -57
  18. package/addon/components/issue/details.js +0 -96
  19. package/addon/components/layout/fleet-ops-sidebar/operations-monitor.hbs +201 -0
  20. package/addon/components/layout/fleet-ops-sidebar/operations-monitor.js +589 -0
  21. package/addon/components/layout/fleet-ops-sidebar.hbs +19 -233
  22. package/addon/components/layout/fleet-ops-sidebar.js +287 -376
  23. package/addon/components/maintenance-schedule/form.js +1 -0
  24. package/addon/components/map/drawer/device-event-listing.hbs +12 -2
  25. package/addon/components/map/drawer/driver-listing.hbs +14 -1
  26. package/addon/components/map/drawer/place-listing.hbs +14 -1
  27. package/addon/components/map/drawer/position-listing.hbs +12 -2
  28. package/addon/components/map/drawer/vehicle-listing.hbs +14 -1
  29. package/addon/components/modals/assigned-orders.hbs +40 -0
  30. package/addon/components/modals/attach-device.hbs +4 -3
  31. package/addon/components/modals/attach-telematic-device.hbs +25 -0
  32. package/addon/components/modals/attach-telematic-device.js +3 -0
  33. package/addon/components/modals/driver-assign-order.hbs +7 -58
  34. package/addon/components/modals/driver-assign-vehicle.hbs +10 -2
  35. package/addon/components/modals/fleet-assign-driver.hbs +18 -0
  36. package/addon/components/modals/fleet-assign-driver.js +3 -0
  37. package/addon/components/modals/fleet-assign-vehicle.hbs +18 -0
  38. package/addon/components/modals/fleet-assign-vehicle.js +3 -0
  39. package/addon/components/modals/telematic-connection-diagnostics.hbs +75 -0
  40. package/addon/components/modals/telematic-connection-diagnostics.js +287 -0
  41. package/addon/components/modals/vehicle-details.hbs +6 -1
  42. package/addon/components/modals/vehicle-form.hbs +8 -1
  43. package/addon/components/order/card.hbs +106 -0
  44. package/addon/components/order/card.js +257 -0
  45. package/addon/components/order/form/payload.js +3 -1
  46. package/addon/components/order/form/service-rate.hbs +2 -0
  47. package/addon/components/service-rate/form.hbs +3 -2
  48. package/addon/components/telematic/details.hbs +98 -87
  49. package/addon/components/telematic/details.js +230 -1
  50. package/addon/components/telematic/form.hbs +303 -72
  51. package/addon/components/telematic/form.js +519 -3
  52. package/addon/components/telematic/hub.hbs +149 -0
  53. package/addon/components/telematic/hub.js +142 -0
  54. package/addon/components/telematic/settings.hbs +152 -0
  55. package/addon/components/telematic/settings.js +45 -0
  56. package/addon/components/telematic/tab-empty-state.hbs +29 -0
  57. package/addon/components/telematic/tab-empty-state.js +33 -0
  58. package/addon/components/vehicle/details.hbs +6 -1
  59. package/addon/components/vehicle/form.hbs +2 -1
  60. package/addon/components/widget/fuel-providers.hbs +43 -0
  61. package/addon/components/widget/fuel-providers.js +27 -0
  62. package/addon/controllers/connectivity/devices/index/details.js +27 -1
  63. package/addon/controllers/connectivity/devices/index.js +18 -1
  64. package/addon/controllers/connectivity/fuel-providers/details/sync.js +18 -0
  65. package/addon/controllers/connectivity/fuel-providers/details/transactions.js +24 -0
  66. package/addon/controllers/connectivity/fuel-providers/details.js +69 -0
  67. package/addon/controllers/connectivity/fuel-providers/edit.js +24 -0
  68. package/addon/controllers/connectivity/fuel-providers/index.js +177 -0
  69. package/addon/controllers/connectivity/fuel-providers/new.js +37 -0
  70. package/addon/controllers/connectivity/telematics/details/attachments.js +247 -0
  71. package/addon/controllers/connectivity/telematics/details/devices.js +368 -0
  72. package/addon/controllers/connectivity/telematics/details/events.js +244 -0
  73. package/addon/controllers/connectivity/telematics/details/index.js +3 -0
  74. package/addon/controllers/connectivity/telematics/details/logs.js +43 -0
  75. package/addon/controllers/connectivity/telematics/details/sensors.js +270 -0
  76. package/addon/controllers/connectivity/telematics/details.js +149 -0
  77. package/addon/controllers/connectivity/telematics/{index/edit.js → edit.js} +15 -4
  78. package/addon/controllers/connectivity/telematics/index.js +25 -5
  79. package/addon/controllers/connectivity/telematics/{index/new.js → new.js} +8 -2
  80. package/addon/controllers/maintenance/index.js +100 -0
  81. package/addon/controllers/management/drivers/index/details.js +78 -1
  82. package/addon/controllers/management/drivers/index.js +39 -0
  83. package/addon/controllers/management/fleets/index/details.js +23 -1
  84. package/addon/controllers/management/fleets/index.js +6 -1
  85. package/addon/controllers/management/fuel-reports/index.js +37 -1
  86. package/addon/controllers/management/fuel-transactions/index/details.js +70 -0
  87. package/addon/controllers/management/fuel-transactions/index.js +240 -0
  88. package/addon/controllers/management/index.js +88 -0
  89. package/addon/controllers/management/vehicles/index/details.js +32 -0
  90. package/addon/controllers/management/vehicles/index.js +26 -0
  91. package/addon/controllers/operations/orders/index.js +4 -0
  92. package/addon/controllers/settings/index.js +142 -0
  93. package/addon/controllers/settings/payments/index.js +5 -0
  94. package/addon/extension.js +31 -0
  95. package/addon/routes/analytics/index.js +3 -0
  96. package/addon/routes/connectivity/devices/index.js +3 -0
  97. package/addon/routes/connectivity/fuel-providers/details/index.js +7 -0
  98. package/addon/routes/connectivity/fuel-providers/details/matching.js +7 -0
  99. package/addon/routes/connectivity/fuel-providers/details/settings.js +7 -0
  100. package/addon/routes/connectivity/fuel-providers/details/sync.js +18 -0
  101. package/addon/routes/connectivity/fuel-providers/details/transactions.js +14 -0
  102. package/addon/routes/connectivity/fuel-providers/details.js +18 -0
  103. package/addon/routes/connectivity/fuel-providers/edit.js +18 -0
  104. package/addon/routes/connectivity/fuel-providers/index.js +20 -0
  105. package/addon/routes/connectivity/fuel-providers/new.js +3 -0
  106. package/addon/routes/connectivity/fuel-providers.js +3 -0
  107. package/addon/routes/connectivity/telematics/details/attachments.js +28 -0
  108. package/addon/routes/connectivity/telematics/details/devices.js +30 -0
  109. package/addon/routes/connectivity/telematics/details/events.js +33 -0
  110. package/addon/routes/connectivity/telematics/details/index.js +3 -0
  111. package/addon/routes/connectivity/telematics/details/logs.js +17 -0
  112. package/addon/routes/connectivity/telematics/details/sensors.js +29 -0
  113. package/addon/routes/connectivity/telematics/{index/details.js → details.js} +1 -1
  114. package/addon/routes/connectivity/telematics/{index/edit.js → edit.js} +1 -1
  115. package/addon/routes/connectivity/telematics/new.js +3 -0
  116. package/addon/routes/maintenance/index.js +3 -0
  117. package/addon/routes/maintenance/work-orders/index.js +2 -0
  118. package/addon/routes/management/drivers/index/details/activity.js +3 -0
  119. package/addon/routes/management/fuel-reports/index.js +2 -0
  120. package/addon/routes/management/fuel-transactions/index/details.js +18 -0
  121. package/addon/routes/management/fuel-transactions/index.js +21 -0
  122. package/addon/routes/management/fuel-transactions.js +3 -0
  123. package/addon/routes/settings/index.js +3 -0
  124. package/addon/routes.js +28 -9
  125. package/addon/services/device-actions.js +64 -1
  126. package/addon/services/device-event-actions.js +12 -1
  127. package/addon/services/driver-actions.js +147 -11
  128. package/addon/services/fleet-actions.js +66 -1
  129. package/addon/services/fuel-integration-actions.js +31 -0
  130. package/addon/services/issue-actions.js +1 -1
  131. package/addon/services/telematic-actions.js +9 -3
  132. package/addon/services/vehicle-actions.js +125 -0
  133. package/addon/styles/fleetops-engine.css +2237 -162
  134. package/addon/templates/analytics/index.hbs +14 -0
  135. package/addon/templates/analytics/reports/index.hbs +19 -1
  136. package/addon/templates/connectivity/devices/index.hbs +19 -1
  137. package/addon/templates/connectivity/events/index.hbs +16 -1
  138. package/addon/templates/connectivity/fuel-providers/details/index.hbs +38 -0
  139. package/addon/templates/connectivity/fuel-providers/details/matching.hbs +13 -0
  140. package/addon/templates/connectivity/fuel-providers/details/settings.hbs +11 -0
  141. package/addon/templates/connectivity/fuel-providers/details/sync.hbs +48 -0
  142. package/addon/templates/connectivity/fuel-providers/details/transactions.hbs +21 -0
  143. package/addon/templates/connectivity/fuel-providers/details.hbs +51 -0
  144. package/addon/templates/connectivity/fuel-providers/edit.hbs +24 -0
  145. package/addon/templates/connectivity/fuel-providers/index.hbs +12 -0
  146. package/addon/templates/connectivity/fuel-providers/new.hbs +22 -0
  147. package/addon/templates/connectivity/fuel-providers.hbs +1 -0
  148. package/addon/templates/connectivity/sensors/index.hbs +19 -1
  149. package/addon/templates/connectivity/telematics/details/attachments.hbs +163 -0
  150. package/addon/templates/connectivity/telematics/details/devices.hbs +88 -0
  151. package/addon/templates/connectivity/telematics/details/events.hbs +101 -0
  152. package/addon/templates/connectivity/telematics/{index/details → details}/index.hbs +0 -1
  153. package/addon/templates/connectivity/telematics/details/logs.hbs +69 -0
  154. package/addon/templates/connectivity/telematics/details/sensors.hbs +88 -0
  155. package/addon/templates/connectivity/telematics/details.hbs +53 -0
  156. package/addon/templates/connectivity/telematics/edit.hbs +27 -0
  157. package/addon/templates/connectivity/telematics/index.hbs +6 -8
  158. package/addon/templates/connectivity/telematics/new.hbs +24 -0
  159. package/addon/templates/maintenance/equipment/index.hbs +19 -1
  160. package/addon/templates/maintenance/index.hbs +113 -0
  161. package/addon/templates/maintenance/maintenances/index.hbs +15 -1
  162. package/addon/templates/maintenance/parts/index.hbs +19 -1
  163. package/addon/templates/maintenance/schedules/index.hbs +19 -1
  164. package/addon/templates/maintenance/work-orders/index.hbs +19 -1
  165. package/addon/templates/management/contacts/customers.hbs +15 -1
  166. package/addon/templates/management/contacts/index.hbs +19 -1
  167. package/addon/templates/management/drivers/index/details/activity.hbs +1 -0
  168. package/addon/templates/management/drivers/index.hbs +19 -1
  169. package/addon/templates/management/fleets/index.hbs +19 -1
  170. package/addon/templates/management/fuel-reports/index.hbs +19 -1
  171. package/addon/templates/management/fuel-transactions/index/details.hbs +73 -0
  172. package/addon/templates/management/fuel-transactions/index.hbs +58 -0
  173. package/addon/templates/management/fuel-transactions.hbs +1 -0
  174. package/addon/templates/management/index.hbs +109 -73
  175. package/addon/templates/management/issues/index.hbs +19 -1
  176. package/addon/templates/management/places/index.hbs +19 -1
  177. package/addon/templates/management/vehicles/index.hbs +19 -1
  178. package/addon/templates/management/vendors/index.hbs +19 -1
  179. package/addon/templates/management/vendors/integrated.hbs +13 -1
  180. package/addon/templates/operations/orders/index.hbs +19 -1
  181. package/addon/templates/operations/service-rates/index.hbs +19 -1
  182. package/addon/templates/settings/index.hbs +83 -0
  183. package/addon/templates/settings/payments/index.hbs +15 -1
  184. package/addon/templates/settings/routing.hbs +2 -2
  185. package/addon/utils/fleet-ops-options.js +3 -0
  186. package/app/components/cell/telematic-provider.js +1 -0
  187. package/app/components/cell/telematic-status.js +1 -0
  188. package/app/components/fuel-integration/form.js +1 -0
  189. package/app/components/fuel-integration/hub.js +1 -0
  190. package/app/components/fuel-integration/matching-priority.js +1 -0
  191. package/app/components/modals/assigned-orders.js +1 -0
  192. package/app/components/modals/attach-telematic-device.js +1 -0
  193. package/app/components/modals/fleet-assign-driver.js +1 -0
  194. package/app/components/modals/fleet-assign-vehicle.js +1 -0
  195. package/app/components/modals/telematic-connection-diagnostics.js +1 -0
  196. package/app/components/order/card.js +1 -0
  197. package/app/components/telematic/hub.js +1 -0
  198. package/app/components/telematic/settings.js +1 -0
  199. package/app/components/telematic/tab-empty-state.js +1 -0
  200. package/app/components/widget/fuel-providers.js +1 -0
  201. package/app/controllers/connectivity/fuel-providers/details/sync.js +1 -0
  202. package/app/controllers/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
  203. package/app/controllers/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
  204. package/app/controllers/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
  205. package/app/controllers/connectivity/{telematics/index/details → fuel-providers}/index.js +1 -1
  206. package/app/controllers/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
  207. package/app/controllers/connectivity/telematics/details/attachments.js +1 -0
  208. package/app/controllers/connectivity/telematics/details/devices.js +1 -0
  209. package/app/controllers/connectivity/telematics/details/events.js +1 -0
  210. package/app/controllers/connectivity/telematics/details/index.js +1 -0
  211. package/app/controllers/connectivity/telematics/details/logs.js +1 -0
  212. package/app/controllers/connectivity/telematics/details/sensors.js +1 -0
  213. package/app/controllers/connectivity/telematics/details.js +1 -0
  214. package/app/controllers/connectivity/telematics/edit.js +1 -0
  215. package/app/controllers/connectivity/telematics/new.js +1 -0
  216. package/app/controllers/maintenance/index.js +1 -0
  217. package/app/controllers/management/fuel-transactions/index/details.js +1 -0
  218. package/app/controllers/management/fuel-transactions/index.js +1 -0
  219. package/app/controllers/management/index.js +1 -0
  220. package/app/controllers/settings/index.js +1 -0
  221. package/app/routes/analytics/index.js +1 -0
  222. package/app/routes/connectivity/{telematics/index → fuel-providers}/details/index.js +1 -1
  223. package/app/routes/connectivity/{telematics/index/details/events.js → fuel-providers/details/matching.js} +1 -1
  224. package/app/routes/connectivity/fuel-providers/details/settings.js +1 -0
  225. package/app/routes/connectivity/fuel-providers/details/sync.js +1 -0
  226. package/app/routes/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
  227. package/app/routes/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
  228. package/app/routes/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
  229. package/app/routes/connectivity/fuel-providers/index.js +1 -0
  230. package/app/routes/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
  231. package/app/routes/connectivity/fuel-providers.js +1 -0
  232. package/app/routes/connectivity/telematics/details/attachments.js +1 -0
  233. package/app/routes/connectivity/telematics/details/devices.js +1 -0
  234. package/app/routes/connectivity/telematics/details/events.js +1 -0
  235. package/app/routes/connectivity/telematics/details/index.js +1 -0
  236. package/app/routes/connectivity/telematics/details/logs.js +1 -0
  237. package/app/routes/connectivity/telematics/details/sensors.js +1 -0
  238. package/app/routes/connectivity/telematics/details.js +1 -0
  239. package/app/routes/connectivity/telematics/edit.js +1 -0
  240. package/app/routes/connectivity/telematics/new.js +1 -0
  241. package/app/routes/maintenance/index.js +1 -0
  242. package/app/routes/management/drivers/index/details/activity.js +1 -0
  243. package/app/routes/management/fuel-transactions/index/details.js +1 -0
  244. package/app/routes/management/fuel-transactions/index.js +1 -0
  245. package/app/routes/management/fuel-transactions.js +1 -0
  246. package/app/routes/settings/index.js +1 -0
  247. package/app/services/fuel-integration-actions.js +1 -0
  248. package/app/templates/analytics/index.js +1 -0
  249. package/app/templates/connectivity/{telematics/index → fuel-providers}/details/index.js +1 -1
  250. package/app/templates/connectivity/{telematics/index/details/events.js → fuel-providers/details/matching.js} +1 -1
  251. package/app/templates/connectivity/fuel-providers/details/settings.js +1 -0
  252. package/app/templates/connectivity/fuel-providers/details/sync.js +1 -0
  253. package/app/templates/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
  254. package/app/templates/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
  255. package/app/templates/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
  256. package/app/templates/connectivity/fuel-providers/index.js +1 -0
  257. package/app/templates/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
  258. package/app/templates/connectivity/fuel-providers.js +1 -0
  259. package/app/templates/connectivity/telematics/details/attachments.js +1 -0
  260. package/app/templates/connectivity/telematics/details/devices.js +1 -0
  261. package/app/templates/connectivity/telematics/details/events.js +1 -0
  262. package/app/templates/connectivity/telematics/details/index.js +1 -0
  263. package/app/templates/connectivity/telematics/details/logs.js +1 -0
  264. package/app/templates/connectivity/telematics/details/sensors.js +1 -0
  265. package/app/templates/connectivity/telematics/details.js +1 -0
  266. package/app/templates/connectivity/telematics/edit.js +1 -0
  267. package/app/templates/connectivity/telematics/new.js +1 -0
  268. package/app/templates/maintenance/index.js +1 -0
  269. package/app/templates/management/drivers/index/details/activity.js +1 -0
  270. package/app/templates/management/fuel-transactions/index/details.js +1 -0
  271. package/app/templates/management/fuel-transactions/index.js +1 -0
  272. package/app/templates/management/fuel-transactions.js +1 -0
  273. package/app/templates/management/index.js +1 -0
  274. package/app/templates/settings/index.js +1 -0
  275. package/assets/images/telematics/providers/afaqy.webp +0 -0
  276. package/assets/images/telematics/providers/default.webp +0 -0
  277. package/assets/images/telematics/providers/flespi.webp +0 -0
  278. package/assets/images/telematics/providers/geotab.webp +0 -0
  279. package/assets/images/telematics/providers/safee.webp +0 -0
  280. package/assets/images/telematics/providers/samsara.webp +0 -0
  281. package/composer.json +1 -1
  282. package/extension.json +1 -1
  283. package/package.json +4 -4
  284. package/server/config/fuel-providers.php +42 -0
  285. package/server/config/telematics.php +139 -130
  286. package/server/migrations/2026_06_06_000001_harden_device_events_telematics_contract.php +59 -0
  287. package/server/migrations/2026_06_08_000001_create_fuel_provider_connections_table.php +37 -0
  288. package/server/migrations/2026_06_08_000002_create_fuel_provider_transactions_table.php +53 -0
  289. package/server/migrations/2026_06_08_000003_create_fuel_provider_sync_runs_table.php +40 -0
  290. package/server/migrations/2026_06_10_000001_add_fuel_card_number_to_vehicles_table.php +25 -0
  291. package/server/migrations/2026_06_10_000002_add_vehicle_identity_columns_to_fuel_provider_transactions_table.php +39 -0
  292. package/server/migrations/2026_06_15_000001_normalize_device_attachable_vehicle_morph_types.php +30 -0
  293. package/server/src/Console/Commands/FixInvalidPolymorphicRelationTypeNamespaces.php +1 -0
  294. package/server/src/Contracts/FuelProvider.php +30 -0
  295. package/server/src/Contracts/TelematicProviderDescriptor.php +3 -1
  296. package/server/src/Events/FuelProviderTransactionImported.php +17 -0
  297. package/server/src/Events/FuelProviderTransactionMatched.php +17 -0
  298. package/server/src/Events/FuelProviderTransactionUnmatched.php +17 -0
  299. package/server/src/Events/FuelReportCreatedFromProvider.php +18 -0
  300. package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +6 -0
  301. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +140 -2
  302. package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +44 -0
  303. package/server/src/Http/Controllers/Internal/v1/DriverController.php +158 -7
  304. package/server/src/Http/Controllers/Internal/v1/FuelProviderConnectionController.php +124 -0
  305. package/server/src/Http/Controllers/Internal/v1/FuelProviderSyncRunController.php +10 -0
  306. package/server/src/Http/Controllers/Internal/v1/FuelProviderTransactionController.php +76 -0
  307. package/server/src/Http/Controllers/Internal/v1/HubController.php +300 -0
  308. package/server/src/Http/Controllers/Internal/v1/SearchController.php +506 -0
  309. package/server/src/Http/Controllers/Internal/v1/SensorController.php +1 -1
  310. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +179 -16
  311. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +249 -0
  312. package/server/src/Http/Controllers/TelematicWebhookController.php +103 -19
  313. package/server/src/Http/Filter/DeviceFilter.php +74 -0
  314. package/server/src/Http/Filter/DriverFilter.php +6 -0
  315. package/server/src/Http/Filter/FuelProviderConnectionFilter.php +33 -0
  316. package/server/src/Http/Filter/FuelProviderSyncRunFilter.php +28 -0
  317. package/server/src/Http/Filter/FuelProviderTransactionFilter.php +59 -0
  318. package/server/src/Http/Filter/FuelReportFilter.php +10 -0
  319. package/server/src/Http/Filter/VehicleFilter.php +6 -0
  320. package/server/src/Http/Resources/v1/Driver.php +15 -0
  321. package/server/src/Http/Resources/v1/FuelProviderConnection.php +30 -0
  322. package/server/src/Http/Resources/v1/FuelProviderSyncRun.php +36 -0
  323. package/server/src/Http/Resources/v1/FuelProviderTransaction.php +54 -0
  324. package/server/src/Http/Resources/v1/FuelReport.php +28 -22
  325. package/server/src/Http/Resources/v1/Index/Driver.php +26 -20
  326. package/server/src/Http/Resources/v1/Index/Vehicle.php +29 -22
  327. package/server/src/Http/Resources/v1/Vehicle.php +17 -0
  328. package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +2 -0
  329. package/server/src/Jobs/SyncFuelProviderTransactionsJob.php +57 -0
  330. package/server/src/Jobs/SyncTelematicDevicesJob.php +105 -17
  331. package/server/src/Jobs/TestTelematicConnectionJob.php +9 -22
  332. package/server/src/Models/Asset.php +2 -1
  333. package/server/src/Models/Contact.php +2 -1
  334. package/server/src/Models/Device.php +27 -4
  335. package/server/src/Models/DeviceEvent.php +40 -3
  336. package/server/src/Models/Driver.php +3 -2
  337. package/server/src/Models/Equipment.php +2 -1
  338. package/server/src/Models/Fleet.php +2 -1
  339. package/server/src/Models/FuelProviderConnection.php +60 -0
  340. package/server/src/Models/FuelProviderSyncRun.php +58 -0
  341. package/server/src/Models/FuelProviderTransaction.php +119 -0
  342. package/server/src/Models/FuelReport.php +16 -1
  343. package/server/src/Models/Part.php +2 -1
  344. package/server/src/Models/Sensor.php +21 -4
  345. package/server/src/Models/ServiceRate.php +39 -2
  346. package/server/src/Models/Vehicle.php +14 -2
  347. package/server/src/Models/Vendor.php +2 -1
  348. package/server/src/Providers/FleetOpsServiceProvider.php +20 -0
  349. package/server/src/Support/Analytics/FuelProviderSummary.php +42 -0
  350. package/server/src/Support/FuelProviders/FuelProviderDescriptor.php +55 -0
  351. package/server/src/Support/FuelProviders/FuelProviderRegistry.php +75 -0
  352. package/server/src/Support/FuelProviders/FuelProviderService.php +447 -0
  353. package/server/src/Support/FuelProviders/Providers/AbstractFuelProvider.php +98 -0
  354. package/server/src/Support/FuelProviders/Providers/PetroAppFuelProvider.php +167 -0
  355. package/server/src/Support/Telematics/Providers/AbstractProvider.php +27 -6
  356. package/server/src/Support/Telematics/Providers/AfaqyProvider.php +105 -38
  357. package/server/src/Support/Telematics/Providers/FlespiProvider.php +1 -0
  358. package/server/src/Support/Telematics/Providers/GeotabProvider.php +1 -0
  359. package/server/src/Support/Telematics/Providers/SafeeProvider.php +32 -22
  360. package/server/src/Support/Telematics/Providers/SamsaraProvider.php +3 -1
  361. package/server/src/Support/Telematics/TelematicService.php +340 -21
  362. package/server/src/routes.php +50 -4
  363. package/server/tests/FuelProviderRegistryTest.php +416 -0
  364. package/server/tests/HubRoutesTest.php +62 -0
  365. package/server/tests/ServiceRateAlgorithmWeightVariablesTest.php +44 -0
  366. package/server/tests/TelematicsHardeningTest.php +359 -0
  367. package/server/tests/VehicleDriverAssignmentTest.php +51 -0
  368. package/translations/ar-ae.yml +23 -1
  369. package/translations/bg-bg.yaml +72 -0
  370. package/translations/en-us.yaml +83 -0
  371. package/translations/es-pa.yaml +72 -0
  372. package/translations/fr-fr.yaml +72 -0
  373. package/translations/mn-mn.yaml +72 -0
  374. package/translations/pt-br.yaml +72 -0
  375. package/translations/ru-ru.yaml +72 -0
  376. package/translations/vi-vn.yaml +98 -1
  377. package/addon/controllers/connectivity/telematics/index/details/devices.js +0 -3
  378. package/addon/controllers/connectivity/telematics/index/details/events.js +0 -3
  379. package/addon/controllers/connectivity/telematics/index/details/index.js +0 -3
  380. package/addon/controllers/connectivity/telematics/index/details/sensors.js +0 -3
  381. package/addon/controllers/connectivity/telematics/index/details.js +0 -24
  382. package/addon/routes/connectivity/telematics/index/details/devices.js +0 -3
  383. package/addon/routes/connectivity/telematics/index/details/events.js +0 -3
  384. package/addon/routes/connectivity/telematics/index/details/index.js +0 -3
  385. package/addon/routes/connectivity/telematics/index/details/sensors.js +0 -3
  386. package/addon/routes/connectivity/telematics/index/new.js +0 -3
  387. package/addon/templates/connectivity/telematics/index/details/devices.hbs +0 -1
  388. package/addon/templates/connectivity/telematics/index/details/events.hbs +0 -1
  389. package/addon/templates/connectivity/telematics/index/details/sensors.hbs +0 -1
  390. package/addon/templates/connectivity/telematics/index/details.hbs +0 -14
  391. package/addon/templates/connectivity/telematics/index/edit.hbs +0 -12
  392. package/addon/templates/connectivity/telematics/index/new.hbs +0 -12
  393. package/app/controllers/connectivity/telematics/index/details/events.js +0 -1
  394. package/app/controllers/connectivity/telematics/index/details/sensors.js +0 -1
  395. package/app/routes/connectivity/telematics/index/details/sensors.js +0 -1
  396. package/app/templates/connectivity/telematics/index/details/sensors.js +0 -1
@@ -0,0 +1,145 @@
1
+ import Component from '@glimmer/component';
2
+ import { action } from '@ember/object';
3
+
4
+ const MATCHING_FIELDS = [
5
+ {
6
+ key: 'plate_number',
7
+ label: 'Plate number',
8
+ source: 'Provider plate number',
9
+ target: 'Vehicle plate number',
10
+ description: 'Best default for fuel card imports. Matches license plates with normalized spacing and casing.',
11
+ },
12
+ {
13
+ key: 'internal_id',
14
+ label: 'Internal ID',
15
+ source: 'Provider internal fleet number',
16
+ target: 'Vehicle internal ID',
17
+ description: 'Use when the provider fleet number is the same identifier operators maintain on the vehicle.',
18
+ },
19
+ {
20
+ key: 'vin',
21
+ label: 'VIN',
22
+ source: 'Provider VIN',
23
+ target: 'Vehicle VIN',
24
+ description: 'Matches the vehicle identification number when the provider sends it with the transaction.',
25
+ },
26
+ {
27
+ key: 'serial_number',
28
+ label: 'Serial number',
29
+ source: 'Provider serial number',
30
+ target: 'Vehicle serial number',
31
+ description: 'Matches manufacturer or fleet serial numbers recorded on the vehicle.',
32
+ },
33
+ {
34
+ key: 'call_sign',
35
+ label: 'Call sign',
36
+ source: 'Provider call sign',
37
+ target: 'Vehicle call sign',
38
+ description: 'Matches operational call signs when those are shared with the fuel provider.',
39
+ },
40
+ {
41
+ key: 'fuel_card_number',
42
+ label: 'Fuel card number',
43
+ source: 'Provider fuel card number',
44
+ target: 'Vehicle fuel card number',
45
+ description: 'Use when each vehicle has a dedicated fuel card number saved on the vehicle record.',
46
+ },
47
+ {
48
+ key: 'trip_number',
49
+ label: 'Trip number / order reference',
50
+ source: 'Provider trip/order reference',
51
+ target: 'Order public ID, internal ID, or tracking number',
52
+ description: 'Links the transaction to an order when the provider sends a trip or order reference. It does not identify the vehicle by itself.',
53
+ },
54
+ {
55
+ key: 'provider_vehicle_id',
56
+ label: 'Provider vehicle ID',
57
+ source: 'Provider-specific vehicle ID',
58
+ target: 'Vehicle provider metadata',
59
+ description: 'Advanced fallback only. Use it when provider vehicle IDs have been intentionally stored on vehicle metadata.',
60
+ },
61
+ ];
62
+
63
+ const DEFAULT_MATCHING_ORDER = ['plate_number', 'internal_id', 'vin', 'serial_number', 'call_sign', 'fuel_card_number', 'trip_number'];
64
+ const LEGACY_DEFAULT_MATCHING_ORDER = ['provider_vehicle_id', 'internal_number', 'structure_number', 'plate_number', 'vehicle_card_id', 'trip_number'];
65
+ const LEGACY_FIELD_ALIASES = {
66
+ internal_number: 'internal_id',
67
+ vehicle_card_id: 'fuel_card_number',
68
+ };
69
+
70
+ export default class FuelIntegrationMatchingPriorityComponent extends Component {
71
+ fields = MATCHING_FIELDS;
72
+
73
+ get order() {
74
+ if (Array.isArray(this.args.order)) {
75
+ if (this.args.order.join('|') === LEGACY_DEFAULT_MATCHING_ORDER.join('|')) {
76
+ return DEFAULT_MATCHING_ORDER;
77
+ }
78
+
79
+ return Array.from(this.args.order)
80
+ .map((key) => LEGACY_FIELD_ALIASES[key] ?? key)
81
+ .filter((key, index, order) => key && order.indexOf(key) === index);
82
+ }
83
+
84
+ return DEFAULT_MATCHING_ORDER;
85
+ }
86
+
87
+ get selectedFields() {
88
+ const lastIndex = this.order.length - 1;
89
+
90
+ return this.order
91
+ .map((key, index) => {
92
+ const field = this.fields.find((option) => option.key === key);
93
+ if (!field) {
94
+ return null;
95
+ }
96
+
97
+ return {
98
+ ...field,
99
+ index,
100
+ priority: index + 1,
101
+ canMoveUp: index > 0,
102
+ canMoveDown: index < lastIndex,
103
+ };
104
+ })
105
+ .filter(Boolean);
106
+ }
107
+
108
+ get availableFields() {
109
+ const selected = new Set(this.order);
110
+ return this.fields.filter((field) => !selected.has(field.key));
111
+ }
112
+
113
+ get hasSelectedFields() {
114
+ return this.selectedFields.length > 0;
115
+ }
116
+
117
+ updateOrder(order) {
118
+ this.args.onChange?.(order);
119
+ }
120
+
121
+ @action addField(field) {
122
+ if (this.order.includes(field.key)) {
123
+ return;
124
+ }
125
+
126
+ this.updateOrder([...this.order, field.key]);
127
+ }
128
+
129
+ @action removeField(field) {
130
+ this.updateOrder(this.order.filter((key) => key !== field.key));
131
+ }
132
+
133
+ @action moveField(field, direction) {
134
+ const currentIndex = this.order.indexOf(field.key);
135
+ const nextIndex = currentIndex + direction;
136
+
137
+ if (currentIndex < 0 || nextIndex < 0 || nextIndex >= this.order.length) {
138
+ return;
139
+ }
140
+
141
+ const nextOrder = [...this.order];
142
+ [nextOrder[currentIndex], nextOrder[nextIndex]] = [nextOrder[nextIndex], nextOrder[currentIndex]];
143
+ this.updateOrder(nextOrder);
144
+ }
145
+ }
@@ -9,6 +9,18 @@
9
9
  <div class="field-name">{{t "common.status"}}</div>
10
10
  <div class="field-value"><Badge @status={{@resource.status}} /></div>
11
11
  </div>
12
+ {{#if @resource.source}}
13
+ <div class="field-info-container">
14
+ <div class="field-name">Source</div>
15
+ <div class="field-value"><Badge @status={{@resource.source}} /></div>
16
+ </div>
17
+ {{/if}}
18
+ {{#if @resource.provider}}
19
+ <div class="field-info-container">
20
+ <div class="field-name">Provider</div>
21
+ <div class="field-value uppercase">{{@resource.provider}}</div>
22
+ </div>
23
+ {{/if}}
12
24
  <div class="field-info-container">
13
25
  <div class="field-name">{{t "fuel-report.fields.reporter"}}</div>
14
26
  <div class="field-value">{{n-a @resource.reporter_name}}</div>
@@ -45,4 +57,4 @@
45
57
  </ContentPanel>
46
58
 
47
59
  <CustomField::Yield @subject={{@resource}} @viewMode={{true}} @wrapperClass="bordered-top" />
48
- </div>
60
+ </div>
@@ -139,67 +139,13 @@
139
139
  </section>
140
140
 
141
141
  <section class="issue-detail-side-card">
142
- <div class="issue-detail-section-title">Linked Order</div>
142
+ <div class="issue-detail-section-title">{{t "order.card.linked-order"}}</div>
143
143
  {{#if this.order}}
144
- <button type="button" class="issue-detail-order-card" {{on "click" this.viewOrder}}>
145
- <div class="issue-detail-order-topline">
146
- <div class="issue-detail-order-title-block">
147
- <div class="issue-detail-order-title">{{this.orderLabel}}</div>
148
- <div class="issue-detail-order-subtitle">{{n-a (smart-humanize this.order.type)}}</div>
149
- </div>
150
- <Badge @status={{this.order.status}} />
151
- </div>
152
- <div class="issue-detail-order-progress {{this.orderProgressClass}}">
153
- <span></span>
154
- </div>
155
- {{#if this.hasOrderStops}}
156
- <div class="issue-detail-order-route">
157
- <div class="issue-detail-order-stop">
158
- <div class="issue-detail-order-stop-marker pickup">1</div>
159
- <div class="min-w-0">
160
- <div class="issue-detail-order-stop-label">Pickup</div>
161
- <div class="issue-detail-order-stop-address">{{n-a this.orderOriginAddress "No pickup address"}}</div>
162
- </div>
163
- </div>
164
- {{#if this.isMultiStopOrder}}
165
- <div class="issue-detail-order-stop compact">
166
- <div class="issue-detail-order-stop-marker middle">+</div>
167
- <div class="min-w-0">
168
- <div class="issue-detail-order-stop-label">Waypoints</div>
169
- <div class="issue-detail-order-stop-address">{{this.middleStopCount}} additional {{if (eq this.middleStopCount 1) "stop" "stops"}}</div>
170
- </div>
171
- </div>
172
- {{/if}}
173
- <div class="issue-detail-order-stop">
174
- <div class="issue-detail-order-stop-marker dropoff">{{this.orderStopCount}}</div>
175
- <div class="min-w-0">
176
- <div class="issue-detail-order-stop-label">{{if (eq this.orderDestination.type "return") "Return" "Dropoff"}}</div>
177
- <div class="issue-detail-order-stop-address">{{n-a this.orderDestinationAddress "No dropoff address"}}</div>
178
- </div>
179
- </div>
180
- </div>
181
- {{else}}
182
- <div class="issue-detail-empty issue-detail-empty-compact">
183
- <FaIcon @icon="route" />
184
- <span>No route details available.</span>
185
- </div>
186
- {{/if}}
187
- <div class="issue-detail-order-meta">
188
- {{#if this.orderScheduledAt}}
189
- <span><FaIcon @icon="calendar" /> {{format-date-fns this.orderScheduledAt "MMM d, HH:mm"}}</span>
190
- {{/if}}
191
- {{#if this.orderDriverLabel}}
192
- <span><FaIcon @icon="id-card" /> {{this.orderDriverLabel}}</span>
193
- {{/if}}
194
- {{#if this.orderVehicleLabel}}
195
- <span><FaIcon @icon="truck" /> {{this.orderVehicleLabel}}</span>
196
- {{/if}}
197
- </div>
198
- </button>
144
+ <Order::Card @order={{this.order}} @variant="default" @interactive={{true}} @onClick={{this.viewOrder}} />
199
145
  {{else}}
200
146
  <div class="issue-detail-empty">
201
147
  <FaIcon @icon="route" />
202
- <span>No order is linked to this issue.</span>
148
+ <span>{{t "order.card.no-order-linked"}}</span>
203
149
  </div>
204
150
  {{/if}}
205
151
  </section>
@@ -3,9 +3,6 @@ import { inject as service } from '@ember/service';
3
3
  import { action } from '@ember/object';
4
4
  import { formatDistanceStrict, isValid } from 'date-fns';
5
5
 
6
- const COMPLETE_ORDER_STATUSES = ['completed', 'delivered'];
7
- const ACTIVE_ORDER_STATUSES = ['dispatched', 'started', 'in_progress', 'driver_enroute', 'driver_nearby'];
8
-
9
6
  export default class IssueDetailsComponent extends Component {
10
7
  @service hostRouter;
11
8
  @service issueActions;
@@ -121,104 +118,11 @@ export default class IssueDetailsComponent extends Component {
121
118
  return formatDistanceStrict(createdAt, resolvedAt);
122
119
  }
123
120
 
124
- get orderLabel() {
125
- return this.order?.tracking_number?.tracking_number || this.order?.tracking_number || this.order?.tracking || this.order?.public_id || this.order?.id;
126
- }
127
-
128
- get orderStops() {
129
- const payload = this.order?.payload ?? {};
130
- const stops = [];
131
-
132
- if (payload.pickup) {
133
- stops.push({ type: 'pickup', place: payload.pickup });
134
- }
135
-
136
- (payload.waypoints ?? []).forEach((waypoint, index) => {
137
- stops.push({
138
- type: waypoint.type ?? 'waypoint',
139
- place: waypoint.place ?? waypoint,
140
- index: index + 1,
141
- });
142
- });
143
-
144
- if (payload.dropoff) {
145
- stops.push({ type: 'dropoff', place: payload.dropoff });
146
- }
147
-
148
- if (payload.return) {
149
- stops.push({ type: 'return', place: payload.return });
150
- }
151
-
152
- return stops.filter((stop) => this.addressForPlace(stop.place));
153
- }
154
-
155
- get orderOrigin() {
156
- return this.orderStops[0];
157
- }
158
-
159
- get orderDestination() {
160
- return this.orderStops[this.orderStops.length - 1];
161
- }
162
-
163
- get orderOriginAddress() {
164
- return this.addressForPlace(this.orderOrigin?.place);
165
- }
166
-
167
- get orderDestinationAddress() {
168
- return this.addressForPlace(this.orderDestination?.place);
169
- }
170
-
171
- get orderStopCount() {
172
- return this.orderStops.length;
173
- }
174
-
175
- get middleStopCount() {
176
- return Math.max(this.orderStopCount - 2, 0);
177
- }
178
-
179
- get isMultiStopOrder() {
180
- return this.orderStopCount > 2;
181
- }
182
-
183
- get hasOrderStops() {
184
- return this.orderStopCount > 0;
185
- }
186
-
187
- get orderProgressClass() {
188
- const status = this.order?.status;
189
-
190
- if (COMPLETE_ORDER_STATUSES.includes(status)) {
191
- return 'is-complete';
192
- }
193
-
194
- if (ACTIVE_ORDER_STATUSES.includes(status)) {
195
- return 'is-active';
196
- }
197
-
198
- return 'is-pending';
199
- }
200
-
201
- get orderScheduledAt() {
202
- return this.order?.scheduled_at || this.order?.created_at || this.order?.createdAt;
203
- }
204
-
205
- get orderDriverLabel() {
206
- return this.order?.driver_assigned?.name || this.order?.driver_name || this.order?.driver?.name;
207
- }
208
-
209
- get orderVehicleLabel() {
210
- return this.order?.vehicle_assigned?.displayName || this.order?.vehicle_assigned?.display_name || this.order?.vehicle_name || this.order?.vehicle?.displayName;
211
- }
212
-
213
121
  get hasLocation() {
214
122
  const location = this.resource?.location;
215
123
  return Boolean(location?.latitude || location?.longitude || location?.coordinates);
216
124
  }
217
125
 
218
- addressForPlace(place) {
219
- return place?.address ?? place?.address_html ?? place?.street1 ?? place?.name;
220
- }
221
-
222
126
  dateFromValue(value) {
223
127
  if (!value) {
224
128
  return null;
@@ -0,0 +1,201 @@
1
+ <div class="fleet-ops-operations-monitor" {{did-insert this.registerMonitor}}>
2
+ <div class="fleet-ops-operations-monitor-divider"></div>
3
+
4
+ <div class="mb-2 flex items-center justify-between px-1">
5
+ <div class="min-w-0">
6
+ <div class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Live Operations</div>
7
+ <div class="mt-1 flex flex-col gap-0.5 text-xs text-gray-500 dark:text-gray-400">
8
+ <span class="flex items-center gap-1"><span class="h-1.5 w-1.5 rounded-full bg-green-500"></span>{{this.driverOnlineSummary}}</span>
9
+ <span class="flex items-center gap-1"><span class="h-1.5 w-1.5 rounded-full bg-blue-500"></span>{{this.vehicleOnlineSummary}}</span>
10
+ </div>
11
+ </div>
12
+ </div>
13
+
14
+ <div class="mb-2 grid grid-cols-3 gap-1 rounded-md bg-gray-100 p-1 dark:bg-gray-800">
15
+ {{#each this.tabs as |tab|}}
16
+ <button
17
+ type="button"
18
+ class="rounded px-1.5 py-1 text-xs font-medium {{if (eq this.activeTab tab.id) 'bg-white text-gray-900 shadow-sm dark:bg-gray-700 dark:text-white' 'text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white'}}"
19
+ data-test-operations-monitor-tab={{tab.id}}
20
+ {{on "click" (fn this.setActiveTab tab.id)}}
21
+ >
22
+ <span>{{tab.label}}</span>
23
+ </button>
24
+ {{/each}}
25
+ </div>
26
+
27
+ <div class="mb-2 flex items-center gap-1.5 rounded-md bg-gray-50 px-2 py-1 text-gray-400 dark:bg-gray-800">
28
+ <FaIcon @icon="magnifying-glass" @size="xs" />
29
+ <input
30
+ type="search"
31
+ value={{this.query}}
32
+ placeholder="Filter resources..."
33
+ class="min-w-0 flex-1 appearance-none border-0 bg-transparent p-0 text-xs leading-5 text-gray-700 outline-none shadow-none ring-0 focus:border-transparent focus:outline-none focus:ring-0 dark:text-gray-100"
34
+ data-test-operations-monitor-filter
35
+ {{on "input" this.updateQuery}}
36
+ />
37
+ </div>
38
+
39
+ <div class="fleet-ops-operations-monitor-list space-y-1" data-test-operations-monitor-list {{did-insert this.registerList}}>
40
+ {{#if (eq this.activeTab "drivers")}}
41
+ {{#each this.drivers as |driver|}}
42
+ <div class="fleet-ops-operations-monitor-row group flex items-start gap-2 rounded-md px-2 py-1.5 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-800" data-test-operations-monitor-row>
43
+ <button type="button" class="flex min-w-0 flex-1 items-center gap-2 text-left" {{on "click" (fn this.locateDriver driver)}}>
44
+ <span class="h-2 w-2 shrink-0 rounded-full {{if driver.online 'bg-green-500' 'bg-yellow-300'}}"></span>
45
+ <span class="min-w-0 flex-1">
46
+ <span class="block truncate leading-5">{{or driver.displayName driver.display_name driver.name driver.public_id}}</span>
47
+ <span class="block truncate text-xs leading-4 text-gray-400">{{if driver.online "Online" "Offline"}} - {{or driver.vehicle_name driver.public_id driver.status}}</span>
48
+ </span>
49
+ </button>
50
+ <div class="fleet-ops-operations-monitor-row-actions">
51
+ <DropdownButton
52
+ @icon="ellipsis-h"
53
+ @iconPrefix="fas"
54
+ @size="xs"
55
+ @buttonClass="fleetops-btn-xxs"
56
+ @contentClass="dropdown-menu fleet-ops-operations-monitor-dropdown"
57
+ @horizontalPosition="right"
58
+ @calculatePosition={{this.calculateDropdownPosition}}
59
+ as |dd|
60
+ >
61
+ <div class="next-dd-menu mx-0 mt-1" role="menu">
62
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.viewDriver driver)}}>View details</a>
63
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.editDriver driver)}}>Edit details</a>
64
+ <div class="next-dd-menu-seperator"></div>
65
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.assignOrderToDriver driver)}}>Assign order</a>
66
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.assignVehicleToDriver driver)}}>Assign vehicle</a>
67
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.locateDriver driver)}}>Locate on map</a>
68
+ <div class="next-dd-menu-seperator"></div>
69
+ <a href="javascript:;" class="next-dd-item text-danger" {{on "click" (dropdown-fn dd this.deleteDriver driver)}}>Delete driver</a>
70
+ </div>
71
+ </DropdownButton>
72
+ </div>
73
+ </div>
74
+ {{else}}
75
+ {{#let this.emptyState as |emptyState|}}
76
+ <div class="fleet-ops-operations-monitor-empty" data-test-operations-monitor-empty-state>
77
+ <span class="fleet-ops-operations-monitor-empty-icon"><FaIcon @icon={{emptyState.icon}} @size="xs" /></span>
78
+ <span class="fleet-ops-operations-monitor-empty-title">{{emptyState.title}}</span>
79
+ <span class="fleet-ops-operations-monitor-empty-description">{{emptyState.description}}</span>
80
+ <button type="button" class="fleet-ops-operations-monitor-empty-action" {{on "click" this.performEmptyStateAction}}>{{emptyState.action}}</button>
81
+ </div>
82
+ {{/let}}
83
+ {{/each}}
84
+ {{else if (eq this.activeTab "vehicles")}}
85
+ {{#each this.vehicles as |vehicle|}}
86
+ <div class="fleet-ops-operations-monitor-row group flex items-start gap-2 rounded-md px-2 py-1.5 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-800" data-test-operations-monitor-row>
87
+ <button type="button" class="flex min-w-0 flex-1 items-center gap-2 text-left" {{on "click" (fn this.locateVehicle vehicle)}}>
88
+ <span class="h-2 w-2 shrink-0 rounded-full {{if vehicle.online 'bg-green-500' 'bg-yellow-300'}}"></span>
89
+ <span class="min-w-0 flex-1">
90
+ <span class="block truncate leading-5">{{or vehicle.displayName vehicle.display_name vehicle.name vehicle.public_id}}</span>
91
+ <span class="block truncate text-xs leading-4 text-gray-400">{{if vehicle.online "Online" "Offline"}} - {{or vehicle.driver_name vehicle.public_id vehicle.status}}</span>
92
+ </span>
93
+ </button>
94
+ <div class="fleet-ops-operations-monitor-row-actions">
95
+ <DropdownButton
96
+ @icon="ellipsis-h"
97
+ @iconPrefix="fas"
98
+ @size="xs"
99
+ @buttonClass="fleetops-btn-xxs"
100
+ @contentClass="dropdown-menu fleet-ops-operations-monitor-dropdown"
101
+ @horizontalPosition="right"
102
+ @calculatePosition={{this.calculateDropdownPosition}}
103
+ as |dd|
104
+ >
105
+ <div class="next-dd-menu mx-0 mt-1" role="menu">
106
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.viewVehicle vehicle)}}>View details</a>
107
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.editVehicle vehicle)}}>Edit details</a>
108
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.locateVehicle vehicle)}}>Locate on map</a>
109
+ <div class="next-dd-menu-seperator"></div>
110
+ <a href="javascript:;" class="next-dd-item text-danger" {{on "click" (dropdown-fn dd this.deleteVehicle vehicle)}}>Delete vehicle</a>
111
+ </div>
112
+ </DropdownButton>
113
+ </div>
114
+ </div>
115
+ {{else}}
116
+ {{#let this.emptyState as |emptyState|}}
117
+ <div class="fleet-ops-operations-monitor-empty" data-test-operations-monitor-empty-state>
118
+ <span class="fleet-ops-operations-monitor-empty-icon"><FaIcon @icon={{emptyState.icon}} @size="xs" /></span>
119
+ <span class="fleet-ops-operations-monitor-empty-title">{{emptyState.title}}</span>
120
+ <span class="fleet-ops-operations-monitor-empty-description">{{emptyState.description}}</span>
121
+ <button type="button" class="fleet-ops-operations-monitor-empty-action" {{on "click" this.performEmptyStateAction}}>{{emptyState.action}}</button>
122
+ </div>
123
+ {{/let}}
124
+ {{/each}}
125
+ {{else}}
126
+ {{#each this.fleetRows as |row|}}
127
+ {{#if (eq row.type "fleet")}}
128
+ <div class="fleet-ops-operations-monitor-row fleet-ops-operations-monitor-row-depth-{{row.depth}} group flex items-start gap-2 rounded-md px-2 py-1.5 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-800" data-test-operations-monitor-row>
129
+ <button type="button" class="flex min-w-0 flex-1 items-start gap-2 text-left" {{on "click" (fn this.toggleFleet row.fleet)}}>
130
+ <span class="mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded bg-gray-100 text-gray-400 dark:bg-gray-800">
131
+ {{#if (this.fleetHasChildren row.fleet)}}
132
+ <FaIcon @icon={{if (this.isFleetExpanded row.fleet) "chevron-down" "chevron-right"}} @size="xs" />
133
+ {{else}}
134
+ <FaIcon @icon="user-group" @size="xs" />
135
+ {{/if}}
136
+ </span>
137
+ <span class="min-w-0 flex-1">
138
+ <span class="block truncate leading-5">{{or row.fleet.displayName row.fleet.display_name row.fleet.name row.fleet.public_id}}</span>
139
+ <span class="block truncate text-xs leading-4 text-gray-400">{{this.fleetSubtitle row.fleet}}</span>
140
+ </span>
141
+ </button>
142
+ <div class="fleet-ops-operations-monitor-row-actions">
143
+ <DropdownButton
144
+ @icon="ellipsis-h"
145
+ @iconPrefix="fas"
146
+ @size="xs"
147
+ @buttonClass="fleetops-btn-xxs"
148
+ @contentClass="dropdown-menu fleet-ops-operations-monitor-dropdown"
149
+ @horizontalPosition="right"
150
+ @calculatePosition={{this.calculateDropdownPosition}}
151
+ as |dd|
152
+ >
153
+ <div class="next-dd-menu mx-0 mt-1" role="menu">
154
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.viewFleet row.fleet)}}>View details</a>
155
+ <div class="next-dd-menu-seperator"></div>
156
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.assignDriverToFleet row.fleet)}}>Assign driver</a>
157
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.assignVehicleToFleet row.fleet)}}>Assign vehicle</a>
158
+ </div>
159
+ </DropdownButton>
160
+ </div>
161
+ </div>
162
+ {{else if (eq row.type "driver")}}
163
+ <button
164
+ type="button"
165
+ class="fleet-ops-operations-monitor-child-row fleet-ops-operations-monitor-row-depth-{{row.depth}} flex w-full min-w-0 items-start gap-2 rounded-md px-2 py-1 text-left text-xs text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800"
166
+ data-test-operations-monitor-row
167
+ {{on "click" (fn this.locateDriver row.driver)}}
168
+ >
169
+ <span class="mt-1 h-1.5 w-1.5 shrink-0 rounded-full {{if row.driver.online 'bg-green-500' 'bg-yellow-300'}}"></span>
170
+ <span class="min-w-0 flex-1">
171
+ <span class="block truncate leading-4">{{or row.driver.displayName row.driver.display_name row.driver.name row.driver.public_id}}</span>
172
+ <span class="block truncate text-xs leading-4 text-gray-400">Driver - {{if row.driver.online "Online" "Offline"}}</span>
173
+ </span>
174
+ </button>
175
+ {{else}}
176
+ <button
177
+ type="button"
178
+ class="fleet-ops-operations-monitor-child-row fleet-ops-operations-monitor-row-depth-{{row.depth}} flex w-full min-w-0 items-start gap-2 rounded-md px-2 py-1 text-left text-xs text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800"
179
+ data-test-operations-monitor-row
180
+ {{on "click" (fn this.locateVehicle row.vehicle)}}
181
+ >
182
+ <span class="mt-1 h-1.5 w-1.5 shrink-0 rounded-full {{if row.vehicle.online 'bg-green-500' 'bg-yellow-300'}}"></span>
183
+ <span class="min-w-0 flex-1">
184
+ <span class="block truncate leading-4">{{or row.vehicle.displayName row.vehicle.display_name row.vehicle.name row.vehicle.public_id}}</span>
185
+ <span class="block truncate text-xs leading-4 text-gray-400">Vehicle - {{if row.vehicle.online "Online" "Offline"}}</span>
186
+ </span>
187
+ </button>
188
+ {{/if}}
189
+ {{else}}
190
+ {{#let this.emptyState as |emptyState|}}
191
+ <div class="fleet-ops-operations-monitor-empty" data-test-operations-monitor-empty-state>
192
+ <span class="fleet-ops-operations-monitor-empty-icon"><FaIcon @icon={{emptyState.icon}} @size="xs" /></span>
193
+ <span class="fleet-ops-operations-monitor-empty-title">{{emptyState.title}}</span>
194
+ <span class="fleet-ops-operations-monitor-empty-description">{{emptyState.description}}</span>
195
+ <button type="button" class="fleet-ops-operations-monitor-empty-action" {{on "click" this.performEmptyStateAction}}>{{emptyState.action}}</button>
196
+ </div>
197
+ {{/let}}
198
+ {{/each}}
199
+ {{/if}}
200
+ </div>
201
+ </div>