@fleetbase/fleetops-engine 0.6.53 → 0.6.55

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 (212) hide show
  1. package/addon/components/admin/routing-settings.hbs +2 -1
  2. package/addon/components/cell/attached-vehicle.hbs +10 -0
  3. package/addon/components/cell/attached-vehicle.js +58 -0
  4. package/addon/components/cell/device-identity.hbs +24 -0
  5. package/addon/components/cell/device-identity.js +129 -0
  6. package/addon/components/cell/driver-identity.hbs +33 -0
  7. package/addon/components/cell/driver-identity.js +143 -0
  8. package/addon/components/cell/equipment-identity.hbs +5 -0
  9. package/addon/components/cell/equipment-identity.js +48 -0
  10. package/addon/components/cell/part-identity.hbs +5 -0
  11. package/addon/components/cell/part-identity.js +63 -0
  12. package/addon/components/cell/telematic-device.hbs +38 -0
  13. package/addon/components/cell/telematic-device.js +44 -0
  14. package/addon/components/cell/telematic-provider.hbs +33 -16
  15. package/addon/components/cell/telematic-provider.js +50 -8
  16. package/addon/components/cell/vehicle-identity.hbs +33 -0
  17. package/addon/components/cell/vehicle-identity.js +138 -0
  18. package/addon/components/device/details.hbs +106 -135
  19. package/addon/components/device/details.js +174 -1
  20. package/addon/components/device/form.hbs +2 -2
  21. package/addon/components/device/form.js +7 -0
  22. package/addon/components/device/panel-header.hbs +46 -21
  23. package/addon/components/device/panel-header.js +49 -1
  24. package/addon/components/device/panel-tabs/events.hbs +30 -0
  25. package/addon/components/device/panel-tabs/events.js +128 -0
  26. package/addon/components/device/panel-tabs/sensors.hbs +30 -0
  27. package/addon/components/device/panel-tabs/sensors.js +93 -0
  28. package/addon/components/device/panel-tabs/vehicle.hbs +68 -0
  29. package/addon/components/device/panel-tabs/vehicle.js +90 -0
  30. package/addon/components/equipment/form.js +8 -1
  31. package/addon/components/layout/fleet-ops-sidebar/operations-monitor.js +76 -11
  32. package/addon/components/layout/fleet-ops-sidebar.hbs +1 -1
  33. package/addon/components/layout/fleet-ops-sidebar.js +101 -17
  34. package/addon/components/map/drawer/device-event-listing.js +2 -0
  35. package/addon/components/map/drawer/driver-listing.js +2 -0
  36. package/addon/components/map/drawer/place-listing.js +2 -0
  37. package/addon/components/map/drawer/position-listing.hbs +11 -6
  38. package/addon/components/map/drawer/position-listing.js +17 -4
  39. package/addon/components/map/drawer/vehicle-listing.js +2 -0
  40. package/addon/components/order/form/details.hbs +1 -43
  41. package/addon/components/order/form/details.js +18 -53
  42. package/addon/components/order/form/orchestrator-constraints.hbs +40 -0
  43. package/addon/components/order/form/orchestrator-constraints.js +61 -0
  44. package/addon/components/order/form/payload.js +48 -2
  45. package/addon/components/order/form/route.js +15 -0
  46. package/addon/components/order/form/service-rate.hbs +62 -11
  47. package/addon/components/order/form/service-rate.js +124 -2
  48. package/addon/components/order/form.hbs +2 -0
  49. package/addon/components/sensor/panel-header.hbs +47 -15
  50. package/addon/components/sensor/panel-header.js +59 -1
  51. package/addon/components/table/cell/dropdown/action-item.hbs +31 -0
  52. package/addon/components/table/cell/dropdown/action-item.js +62 -0
  53. package/addon/components/table/cell/dropdown.hbs +28 -0
  54. package/addon/components/table/cell/dropdown.js +91 -0
  55. package/addon/components/telematic/details.hbs +7 -1
  56. package/addon/components/telematic/form.js +16 -8
  57. package/addon/components/vendor/panel-header.hbs +82 -0
  58. package/addon/components/vendor/panel-header.js +48 -0
  59. package/addon/components/work-order/details.hbs +5 -1
  60. package/addon/components/work-order/form.hbs +26 -4
  61. package/addon/components/work-order/form.js +5 -1
  62. package/addon/controllers/connectivity/devices/index/details/events.js +244 -1
  63. package/addon/controllers/connectivity/devices/index/details/sensors.js +199 -0
  64. package/addon/controllers/connectivity/devices/index/details/vehicle.js +122 -0
  65. package/addon/controllers/connectivity/devices/index/details.js +12 -0
  66. package/addon/controllers/connectivity/devices/index.js +144 -129
  67. package/addon/controllers/connectivity/events/details.js +3 -0
  68. package/addon/controllers/connectivity/events/index.js +187 -11
  69. package/addon/controllers/connectivity/sensors/index.js +156 -14
  70. package/addon/controllers/connectivity/telematics/details/attachments.js +220 -54
  71. package/addon/controllers/connectivity/telematics/details/devices.js +170 -129
  72. package/addon/controllers/connectivity/telematics/details/events.js +39 -11
  73. package/addon/controllers/connectivity/telematics/details/sensors.js +39 -19
  74. package/addon/controllers/maintenance/equipment/index.js +1 -2
  75. package/addon/controllers/maintenance/parts/index.js +1 -2
  76. package/addon/controllers/maintenance/work-orders/index.js +18 -1
  77. package/addon/controllers/management/drivers/index.js +82 -42
  78. package/addon/controllers/management/fuel-reports/index.js +63 -4
  79. package/addon/controllers/management/issues/index.js +63 -4
  80. package/addon/controllers/management/vehicles/index.js +33 -6
  81. package/addon/routes/connectivity/devices/index/details/events.js +37 -1
  82. package/addon/routes/connectivity/devices/index/details/sensors.js +35 -0
  83. package/addon/routes/connectivity/devices/index/details/vehicle.js +29 -0
  84. package/addon/routes/connectivity/devices/index.js +7 -0
  85. package/addon/routes/connectivity/events/details.js +3 -0
  86. package/addon/routes/connectivity/events/index.js +6 -2
  87. package/addon/routes/connectivity/sensors/index.js +7 -2
  88. package/addon/routes/connectivity/telematics/details/attachments.js +72 -9
  89. package/addon/routes/connectivity/telematics/details/devices.js +6 -0
  90. package/addon/routes/connectivity/telematics/details/sensors.js +1 -0
  91. package/addon/routes/connectivity/telematics/details.js +1 -1
  92. package/addon/routes/connectivity/telematics/edit.js +1 -1
  93. package/addon/routes/maintenance/work-orders/index.js +1 -0
  94. package/addon/routes.js +2 -0
  95. package/addon/services/device-actions.js +30 -0
  96. package/addon/services/device-event-actions.js +1 -1
  97. package/addon/services/equipment-actions.js +1 -0
  98. package/addon/services/order-creation.js +54 -1
  99. package/addon/services/order-validation.js +3 -2
  100. package/addon/services/sensor-actions.js +3 -0
  101. package/addon/services/service-rate-actions.js +40 -1
  102. package/addon/services/vehicle-actions.js +24 -12
  103. package/addon/services/vendor-actions.js +3 -0
  104. package/addon/styles/fleetops-engine.css +28 -4
  105. package/addon/templates/connectivity/devices/index/details/events.hbs +85 -1
  106. package/addon/templates/connectivity/devices/index/details/sensors.hbs +73 -0
  107. package/addon/templates/connectivity/devices/index/details/vehicle.hbs +147 -0
  108. package/addon/templates/connectivity/telematics/details/attachments.hbs +198 -121
  109. package/addon/templates/connectivity/telematics/details/devices.hbs +4 -1
  110. package/addon/templates/connectivity/telematics/details/events.hbs +4 -1
  111. package/addon/templates/connectivity/telematics/details/sensors.hbs +3 -0
  112. package/addon/templates/management/vehicles/index/edit.hbs +1 -1
  113. package/addon/templates/management/vendors/index/details.hbs +2 -2
  114. package/addon/templates/settings/notifications.hbs +2 -1
  115. package/addon/templates/settings/routing.hbs +1 -0
  116. package/addon/utils/device-table-columns.js +288 -0
  117. package/addon/utils/fleet-ops-options.js +38 -0
  118. package/addon/utils/identity-cell-resource.js +20 -0
  119. package/addon/utils/map-drawer-dropdown-position.js +47 -0
  120. package/addon/utils/trackable-option.js +93 -0
  121. package/app/components/cell/attached-vehicle.js +1 -0
  122. package/app/components/cell/device-identity.js +1 -0
  123. package/app/components/cell/driver-identity.js +1 -0
  124. package/app/components/cell/equipment-identity.js +1 -0
  125. package/app/components/cell/part-identity.js +1 -0
  126. package/app/components/cell/telematic-device.js +1 -0
  127. package/app/components/cell/vehicle-identity.js +1 -0
  128. package/app/components/device/panel-tabs/events.hbs +30 -0
  129. package/app/components/device/panel-tabs/events.js +128 -0
  130. package/app/components/device/panel-tabs/sensors.hbs +30 -0
  131. package/app/components/device/panel-tabs/sensors.js +93 -0
  132. package/app/components/device/panel-tabs/vehicle.hbs +68 -0
  133. package/app/components/device/panel-tabs/vehicle.js +90 -0
  134. package/app/components/order/form/orchestrator-constraints.js +1 -0
  135. package/app/components/table/cell/dropdown/action-item.js +1 -0
  136. package/app/components/table/cell/dropdown.js +1 -0
  137. package/app/components/vendor/panel-header.js +1 -0
  138. package/app/controllers/connectivity/devices/index/details/sensors.js +1 -0
  139. package/app/controllers/connectivity/devices/index/details/vehicle.js +1 -0
  140. package/app/controllers/connectivity/events/{index/details.js → details.js} +1 -1
  141. package/app/routes/connectivity/devices/index/details/sensors.js +1 -0
  142. package/app/routes/connectivity/devices/index/details/vehicle.js +1 -0
  143. package/app/routes/connectivity/events/{index/details.js → details.js} +1 -1
  144. package/app/templates/connectivity/devices/index/details/sensors.js +1 -0
  145. package/app/templates/connectivity/devices/index/details/vehicle.js +1 -0
  146. package/app/templates/connectivity/events/{index/details.js → details.js} +1 -1
  147. package/app/utils/map-drawer-dropdown-position.js +1 -0
  148. package/app/utils/trackable-option.js +1 -0
  149. package/composer.json +1 -1
  150. package/extension.json +1 -1
  151. package/package.json +4 -4
  152. package/server/migrations/2025_08_28_054930_create_work_orders_table.php +1 -0
  153. package/server/migrations/2026_06_18_000001_add_category_to_work_orders_table.php +32 -0
  154. package/server/seeders/Testing/MaintenanceSeeder.php +5 -4
  155. package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +1 -0
  156. package/server/src/Console/Commands/SyncTelematics.php +89 -0
  157. package/server/src/Exceptions/TelematicProviderException.php +13 -2
  158. package/server/src/Http/Controllers/Api/v1/OrderController.php +6 -21
  159. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +55 -1
  160. package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +17 -6
  161. package/server/src/Http/Controllers/Internal/v1/FleetController.php +9 -0
  162. package/server/src/Http/Controllers/Internal/v1/LiveController.php +178 -1
  163. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +1 -0
  164. package/server/src/Http/Controllers/Internal/v1/OrderController.php +4 -32
  165. package/server/src/Http/Controllers/Internal/v1/SearchController.php +2 -2
  166. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +4 -4
  167. package/server/src/Http/Controllers/Internal/v1/ServiceRateController.php +82 -13
  168. package/server/src/Http/Filter/DeviceEventFilter.php +65 -0
  169. package/server/src/Http/Filter/DeviceFilter.php +80 -0
  170. package/server/src/Http/Filter/SensorFilter.php +125 -0
  171. package/server/src/Http/Filter/VehicleFilter.php +13 -0
  172. package/server/src/Http/Requests/CreateDriverRequest.php +14 -13
  173. package/server/src/Http/Requests/Internal/CreateDriverRequest.php +1 -0
  174. package/server/src/Http/Resources/v1/Driver.php +11 -2
  175. package/server/src/Http/Resources/v1/Index/Vehicle.php +19 -0
  176. package/server/src/Http/Resources/v1/WorkOrder.php +1 -0
  177. package/server/src/Jobs/FinalizeApiOrderCreation.php +47 -0
  178. package/server/src/Jobs/FinalizeInternalOrderCreation.php +35 -0
  179. package/server/src/Jobs/NotifyBulkAssignedDriver.php +47 -0
  180. package/server/src/Jobs/SyncTelematicDevicesJob.php +180 -123
  181. package/server/src/Models/Device.php +17 -1
  182. package/server/src/Models/DeviceEvent.php +82 -1
  183. package/server/src/Models/Driver.php +16 -0
  184. package/server/src/Models/Equipment.php +55 -0
  185. package/server/src/Models/Sensor.php +15 -2
  186. package/server/src/Models/Telematic.php +1 -1
  187. package/server/src/Models/Vehicle.php +5 -1
  188. package/server/src/Models/WorkOrder.php +5 -2
  189. package/server/src/Observers/DriverObserver.php +3 -3
  190. package/server/src/Observers/FleetObserver.php +23 -0
  191. package/server/src/Observers/VehicleObserver.php +3 -3
  192. package/server/src/Providers/FleetOpsServiceProvider.php +2 -0
  193. package/server/src/Support/LiveCacheService.php +1 -1
  194. package/server/src/Support/Telematics/Providers/AfaqyProvider.php +143 -20
  195. package/server/src/Support/Telematics/Providers/FlespiProvider.php +89 -15
  196. package/server/src/Support/Telematics/Providers/GeotabProvider.php +123 -35
  197. package/server/src/Support/Telematics/Providers/SafeeProvider.php +70 -5
  198. package/server/src/Support/Telematics/Providers/SamsaraProvider.php +122 -14
  199. package/server/src/Support/Telematics/TelematicService.php +330 -30
  200. package/server/src/routes.php +1 -1
  201. package/server/tests/DeviceFilterTest.php +45 -0
  202. package/server/tests/DriverVehicleStatusDefaultTest.php +19 -2
  203. package/server/tests/EquipmentAssignmentMorphTypeTest.php +35 -0
  204. package/server/tests/OperationsMonitorEndpointTest.php +38 -0
  205. package/server/tests/OrderQueuedClosureRegressionTest.php +36 -0
  206. package/server/tests/ServiceRateRouteValidationTest.php +101 -0
  207. package/server/tests/TelematicsHardeningTest.php +598 -6
  208. package/server/tests/VehicleDriverAssignmentTest.php +27 -0
  209. package/translations/en-us.yaml +1 -0
  210. package/addon/controllers/connectivity/events/index/details.js +0 -3
  211. package/addon/routes/connectivity/events/index/details.js +0 -3
  212. /package/addon/templates/connectivity/events/{index/details.hbs → details.hbs} +0 -0
@@ -3,6 +3,7 @@ import { action } from '@ember/object';
3
3
  import { inject as service } from '@ember/service';
4
4
  import { tracked } from '@glimmer/tracking';
5
5
  import { task } from 'ember-concurrency';
6
+ import buildDeviceTableColumns from '../../../../utils/device-table-columns';
6
7
  import fleetOpsOptions from '../../../../utils/fleet-ops-options';
7
8
 
8
9
  export default class ConnectivityTelematicsDetailsDevicesController extends Controller {
@@ -10,10 +11,28 @@ export default class ConnectivityTelematicsDetailsDevicesController extends Cont
10
11
  @service fetch;
11
12
  @service hostRouter;
12
13
  @service intl;
14
+ @service mapManager;
13
15
  @service modalsManager;
14
16
  @service notifications;
15
-
16
- @tracked queryParams = ['page', 'limit', 'sort', 'query', 'status', 'provider', 'attachment_state', 'device_id'];
17
+ @service store;
18
+ @service vehicleActions;
19
+
20
+ @tracked queryParams = [
21
+ 'page',
22
+ 'limit',
23
+ 'sort',
24
+ 'query',
25
+ 'status',
26
+ 'provider',
27
+ 'attachment_state',
28
+ 'vehicle',
29
+ 'connection_status',
30
+ 'device_id',
31
+ 'type',
32
+ 'serial_number',
33
+ 'last_online_at',
34
+ 'updated_at',
35
+ ];
17
36
  @tracked telematic;
18
37
  @tracked page = 1;
19
38
  @tracked limit;
@@ -22,7 +41,13 @@ export default class ConnectivityTelematicsDetailsDevicesController extends Cont
22
41
  @tracked status;
23
42
  @tracked provider;
24
43
  @tracked attachment_state;
44
+ @tracked vehicle;
45
+ @tracked connection_status;
25
46
  @tracked device_id;
47
+ @tracked type;
48
+ @tracked serial_number;
49
+ @tracked last_online_at;
50
+ @tracked updated_at;
26
51
 
27
52
  get devices() {
28
53
  return Array.from(this.model ?? []);
@@ -45,7 +70,19 @@ export default class ConnectivityTelematicsDetailsDevicesController extends Cont
45
70
  }
46
71
 
47
72
  get hasActiveFilters() {
48
- return Boolean(this.query || this.status || this.provider || this.attachment_state || this.device_id);
73
+ return Boolean(
74
+ this.query ||
75
+ this.status ||
76
+ this.provider ||
77
+ this.attachment_state ||
78
+ this.vehicle ||
79
+ this.connection_status ||
80
+ this.device_id ||
81
+ this.type ||
82
+ this.serial_number ||
83
+ this.last_online_at ||
84
+ this.updated_at
85
+ );
49
86
  }
50
87
 
51
88
  get hasDevices() {
@@ -145,146 +182,60 @@ export default class ConnectivityTelematicsDetailsDevicesController extends Cont
145
182
  ];
146
183
  }
147
184
 
148
- @tracked actionButtons = [
149
- {
150
- icon: 'refresh',
151
- size: 'xs',
152
- onClick: this.refresh,
153
- helpText: this.intl.t('common.refresh'),
154
- wrapperClass: 'fleetops-telematics-action-button',
155
- },
156
- {
157
- icon: 'ellipsis-h',
158
- prefix: 'fas',
159
- text: 'Actions',
160
- type: 'primary',
161
- size: 'xs',
162
- triggerClass: 'fleetops-telematics-action-button',
163
- items: [
164
- {
165
- icon: 'satellite-dish',
166
- text: 'Sync Devices',
167
- onClick: this.startDeviceSync,
168
- },
169
- {
170
- icon: 'link',
171
- text: 'Attach Unassigned',
172
- onClick: this.openAttachmentsForUnassigned,
173
- },
174
- ],
175
- },
176
- ];
177
-
178
- @tracked bulkActions = [];
179
-
180
- get columns() {
185
+ get actionButtons() {
181
186
  return [
182
187
  {
183
- sticky: true,
184
- label: this.intl.t('column.name'),
185
- valuePath: 'displayName',
186
- cellComponent: 'table/cell/anchor',
187
- action: this.deviceActions.transition.view,
188
- permission: 'fleet-ops view device',
189
- resizable: true,
190
- sortable: true,
191
- filterable: true,
192
- filterParam: 'query',
193
- filterComponent: 'filter/string',
194
- },
195
- {
196
- label: 'Provider ID',
197
- valuePath: 'device_id',
198
- resizable: true,
199
- sortable: true,
200
- filterable: true,
201
- filterParam: 'device_id',
202
- filterComponent: 'filter/string',
188
+ icon: 'refresh',
189
+ size: 'sm',
190
+ onClick: this.refresh,
191
+ helpText: this.intl.t('common.refresh'),
192
+ wrapperClass: 'fleetops-telematics-action-button',
193
+ isLoading: this.refreshTask.isRunning,
194
+ disabled: this.refreshTask.isRunning,
203
195
  },
204
196
  {
205
- label: 'Vehicle',
206
- valuePath: 'attached_to_name',
207
- resizable: true,
208
- sortable: true,
209
- filterable: true,
210
- filterParam: 'attachment_state',
211
- filterComponent: 'filter/multi-option',
212
- filterOptions: [
213
- { label: 'Attached', value: 'attached' },
214
- { label: 'Unattached', value: 'unattached' },
215
- ],
216
- },
217
- {
218
- label: 'Connection',
219
- valuePath: 'connection_status',
220
- cellComponent: 'table/cell/status',
221
- resizable: true,
222
- sortable: true,
223
- filterable: true,
224
- filterParam: 'status',
225
- filterComponent: 'filter/multi-option',
226
- filterOptions: fleetOpsOptions('deviceStatuses'),
227
- },
228
- {
229
- label: 'Last Seen',
230
- valuePath: 'lastOnlineAt',
231
- sortParam: 'last_online_at',
232
- resizable: true,
233
- sortable: true,
234
- },
235
- {
236
- label: this.intl.t('column.updated-at'),
237
- valuePath: 'updatedAt',
238
- sortParam: 'updated_at',
239
- resizable: true,
240
- sortable: true,
241
- hidden: true,
242
- filterable: true,
243
- filterComponent: 'filter/date',
244
- },
245
- {
246
- label: '',
247
- cellComponent: 'table/cell/dropdown',
248
- ddButtonText: false,
249
- ddButtonIcon: 'ellipsis-h',
250
- ddButtonIconPrefix: 'fas',
251
- ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.device') }),
252
- cellClassNames: 'overflow-visible align-middle',
253
- wrapperClass: 'flex items-center justify-end mx-2',
254
- sticky: 'right',
255
- width: 60,
256
- actions: [
257
- {
258
- label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.device') }),
259
- fn: this.deviceActions.transition.view,
260
- permission: 'fleet-ops view device',
261
- },
262
- {
263
- label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.device') }),
264
- fn: this.deviceActions.transition.edit,
265
- permission: 'fleet-ops update device',
266
- },
197
+ icon: 'ellipsis-h',
198
+ prefix: 'fas',
199
+ helpText: 'Actions',
200
+ type: 'primary',
201
+ size: 'sm',
202
+ triggerClass: 'fleetops-telematics-action-button',
203
+ items: [
267
204
  {
268
- label: 'Attach or change vehicle',
269
- fn: this.openAttachDeviceModal,
270
- permission: 'fleet-ops update device',
205
+ icon: 'satellite-dish',
206
+ text: 'Sync Devices',
207
+ onClick: this.startDeviceSync,
271
208
  },
272
209
  {
273
- label: 'Review recent events',
274
- fn: this.openDeviceEvents,
275
- permission: 'fleet-ops view device-event',
210
+ icon: 'link',
211
+ text: 'Attach Unassigned',
212
+ onClick: this.openAttachmentsForUnassigned,
276
213
  },
277
214
  ],
278
- sortable: false,
279
- filterable: false,
280
- resizable: false,
281
- searchable: false,
282
215
  },
283
216
  ];
284
217
  }
285
218
 
219
+ @tracked bulkActions = [];
220
+
221
+ get deviceTypeOptions() {
222
+ return fleetOpsOptions('deviceTypes');
223
+ }
224
+
225
+ get deviceStatusOptions() {
226
+ return fleetOpsOptions('deviceStatuses');
227
+ }
228
+
229
+ get columns() {
230
+ return buildDeviceTableColumns(this, { showProvider: false, deviceActionMode: 'panel', showDeviceStatus: false });
231
+ }
232
+
286
233
  @action refresh() {
287
- return this.hostRouter.refresh();
234
+ if (this.refreshTask.isRunning) {
235
+ return;
236
+ }
237
+
238
+ return this.refreshTask.perform();
288
239
  }
289
240
 
290
241
  @action clearFilters() {
@@ -292,7 +243,13 @@ export default class ConnectivityTelematicsDetailsDevicesController extends Cont
292
243
  this.status = null;
293
244
  this.provider = null;
294
245
  this.attachment_state = null;
246
+ this.vehicle = null;
247
+ this.connection_status = null;
295
248
  this.device_id = null;
249
+ this.type = null;
250
+ this.serial_number = null;
251
+ this.last_online_at = null;
252
+ this.updated_at = null;
296
253
  this.page = 1;
297
254
  }
298
255
 
@@ -313,6 +270,86 @@ export default class ConnectivityTelematicsDetailsDevicesController extends Cont
313
270
  });
314
271
  }
315
272
 
273
+ @action hasAttachedVehicle(device) {
274
+ return Boolean(device?.attachable_uuid && this.isVehicleAttachment(device));
275
+ }
276
+
277
+ @action async viewAttachedVehicle(device) {
278
+ const vehicle = await this.resolveAttachedVehicle(device);
279
+
280
+ if (!vehicle) {
281
+ return;
282
+ }
283
+
284
+ return this.vehicleActions.panel.view(vehicle);
285
+ }
286
+
287
+ @action async locateAttachedVehicle(device) {
288
+ const vehicle = await this.resolveAttachedVehicle(device);
289
+
290
+ if (!vehicle) {
291
+ return;
292
+ }
293
+
294
+ await this.transitionToLiveMap();
295
+ await this.mapManager.waitForMap({ timeoutMs: 8000 });
296
+
297
+ this.mapManager.focusResource(vehicle, 16, {
298
+ paddingBottomRight: [300, 200],
299
+ moveend: () => {
300
+ this.vehicleActions.panel.view(vehicle, { closeOnTransition: true });
301
+ },
302
+ });
303
+ }
304
+
305
+ async transitionToLiveMap() {
306
+ try {
307
+ await this.hostRouter.transitionTo('console.fleet-ops.operations.orders.index', { queryParams: { layout: 'map' } });
308
+ } catch (_) {
309
+ // Keep locate actions usable even if the current transition is already in-flight.
310
+ }
311
+ }
312
+
313
+ isVehicleAttachment(device) {
314
+ const attachableType = `${device?.attachable_type ?? ''}`.toLowerCase();
315
+
316
+ return !attachableType || attachableType.includes('vehicle');
317
+ }
318
+
319
+ async resolveAttachedVehicle(device) {
320
+ if (!device?.attachable_uuid) {
321
+ return null;
322
+ }
323
+
324
+ if (!this.isVehicleAttachment(device)) {
325
+ return null;
326
+ }
327
+
328
+ const attachable = device.attachable;
329
+
330
+ if (attachable && typeof attachable.then !== 'function') {
331
+ return attachable;
332
+ }
333
+
334
+ if (attachable && typeof attachable.then === 'function') {
335
+ return await attachable;
336
+ }
337
+
338
+ const cachedVehicle = this.store.peekRecord('vehicle', device.attachable_uuid);
339
+
340
+ if (cachedVehicle) {
341
+ return cachedVehicle;
342
+ }
343
+
344
+ try {
345
+ return await this.store.findRecord('vehicle', device.attachable_uuid);
346
+ } catch (error) {
347
+ this.notifications.serverError(error);
348
+ }
349
+
350
+ return null;
351
+ }
352
+
316
353
  @action openDeviceEvents(device) {
317
354
  return this.hostRouter.transitionTo('console.fleet-ops.connectivity.telematics.details.events', this.telematic, {
318
355
  queryParams: { device_uuid: device.id },
@@ -356,6 +393,10 @@ export default class ConnectivityTelematicsDetailsDevicesController extends Cont
356
393
  return this.syncDevices.perform();
357
394
  }
358
395
 
396
+ @task *refreshTask() {
397
+ yield this.hostRouter.refresh();
398
+ }
399
+
359
400
  @task *syncDevices() {
360
401
  try {
361
402
  yield this.fetch.post(`telematics/${this.telematic.id}/discover`);
@@ -2,6 +2,15 @@ import Controller from '@ember/controller';
2
2
  import { action } from '@ember/object';
3
3
  import { inject as service } from '@ember/service';
4
4
  import { tracked } from '@glimmer/tracking';
5
+ import { task } from 'ember-concurrency';
6
+
7
+ const severityOptions = [
8
+ { label: 'Info', value: 'info' },
9
+ { label: 'Warning', value: 'warning' },
10
+ { label: 'Error', value: 'error' },
11
+ { label: 'Critical', value: 'critical' },
12
+ { label: 'High', value: 'high' },
13
+ ];
5
14
 
6
15
  export default class ConnectivityTelematicsDetailsEventsController extends Controller {
7
16
  @service deviceEventActions;
@@ -99,15 +108,19 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
99
108
  ];
100
109
  }
101
110
 
102
- @tracked actionButtons = [
103
- {
104
- icon: 'refresh',
105
- size: 'xs',
106
- onClick: this.refresh,
107
- helpText: this.intl.t('common.refresh'),
108
- wrapperClass: 'fleetops-telematics-action-button',
109
- },
110
- ];
111
+ get actionButtons() {
112
+ return [
113
+ {
114
+ icon: 'refresh',
115
+ size: 'sm',
116
+ onClick: this.refresh,
117
+ helpText: this.intl.t('common.refresh'),
118
+ wrapperClass: 'fleetops-telematics-action-button',
119
+ isLoading: this.refreshTask.isRunning,
120
+ disabled: this.refreshTask.isRunning,
121
+ },
122
+ ];
123
+ }
111
124
 
112
125
  @tracked bulkActions = [];
113
126
 
@@ -136,6 +149,8 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
136
149
  filterComponentPlaceholder: 'Select device',
137
150
  filterParam: 'device_uuid',
138
151
  model: 'device',
152
+ modelNamePath: 'displayName',
153
+ query: { telematic_uuid: this.telematic?.id },
139
154
  },
140
155
  {
141
156
  label: 'Provider',
@@ -155,7 +170,10 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
155
170
  sortable: true,
156
171
  filterable: true,
157
172
  filterParam: 'severity',
158
- filterComponent: 'filter/string',
173
+ filterComponent: 'filter/multi-option',
174
+ filterOptions: severityOptions,
175
+ filterOptionLabel: 'label',
176
+ filterOptionValue: 'value',
159
177
  },
160
178
  {
161
179
  label: 'Processed',
@@ -170,6 +188,8 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
170
188
  { label: 'Processed', value: 'processed' },
171
189
  { label: 'Unprocessed', value: 'unprocessed' },
172
190
  ],
191
+ filterOptionLabel: 'label',
192
+ filterOptionValue: 'value',
173
193
  },
174
194
  {
175
195
  label: 'Occurred',
@@ -222,7 +242,11 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
222
242
  }
223
243
 
224
244
  @action refresh() {
225
- return this.hostRouter.refresh();
245
+ if (this.refreshTask.isRunning) {
246
+ return;
247
+ }
248
+
249
+ return this.refreshTask.perform();
226
250
  }
227
251
 
228
252
  @action clearFilters() {
@@ -241,4 +265,8 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
241
265
  await this.deviceEventActions.markProcessed(deviceEvent);
242
266
  await this.hostRouter.refresh();
243
267
  }
268
+
269
+ @task *refreshTask() {
270
+ yield this.hostRouter.refresh();
271
+ }
244
272
  }
@@ -2,6 +2,7 @@ import Controller from '@ember/controller';
2
2
  import { action } from '@ember/object';
3
3
  import { inject as service } from '@ember/service';
4
4
  import { tracked } from '@glimmer/tracking';
5
+ import { task } from 'ember-concurrency';
5
6
  import fleetOpsOptions from '../../../../utils/fleet-ops-options';
6
7
 
7
8
  export default class ConnectivityTelematicsDetailsSensorsController extends Controller {
@@ -10,7 +11,7 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
10
11
  @service hostRouter;
11
12
  @service intl;
12
13
 
13
- @tracked queryParams = ['page', 'limit', 'sort', 'query', 'status', 'type', 'device_uuid'];
14
+ @tracked queryParams = ['page', 'limit', 'sort', 'query', 'status', 'type', 'device_uuid', 'last_reading_at'];
14
15
  @tracked telematic;
15
16
  @tracked page = 1;
16
17
  @tracked limit;
@@ -19,6 +20,7 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
19
20
  @tracked status;
20
21
  @tracked type;
21
22
  @tracked device_uuid;
23
+ @tracked last_reading_at;
22
24
 
23
25
  get sensors() {
24
26
  return Array.from(this.model ?? []);
@@ -37,7 +39,7 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
37
39
  }
38
40
 
39
41
  get hasActiveFilters() {
40
- return Boolean(this.query || this.status || this.type || this.device_uuid);
42
+ return Boolean(this.query || this.status || this.type || this.device_uuid || this.last_reading_at);
41
43
  }
42
44
 
43
45
  get hasSensors() {
@@ -122,22 +124,26 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
122
124
  ];
123
125
  }
124
126
 
125
- @tracked actionButtons = [
126
- {
127
- icon: 'refresh',
128
- size: 'xs',
129
- onClick: this.refresh,
130
- helpText: this.intl.t('common.refresh'),
131
- wrapperClass: 'fleetops-telematics-action-button',
132
- },
133
- {
134
- icon: 'microchip',
135
- text: 'View Devices',
136
- size: 'xs',
137
- onClick: this.goToDevices,
138
- wrapperClass: 'fleetops-telematics-action-button',
139
- },
140
- ];
127
+ get actionButtons() {
128
+ return [
129
+ {
130
+ icon: 'refresh',
131
+ size: 'sm',
132
+ onClick: this.refresh,
133
+ helpText: this.intl.t('common.refresh'),
134
+ wrapperClass: 'fleetops-telematics-action-button',
135
+ isLoading: this.refreshTask.isRunning,
136
+ disabled: this.refreshTask.isRunning,
137
+ },
138
+ {
139
+ icon: 'microchip',
140
+ text: 'View Devices',
141
+ size: 'sm',
142
+ onClick: this.goToDevices,
143
+ wrapperClass: 'fleetops-telematics-action-button',
144
+ },
145
+ ];
146
+ }
141
147
 
142
148
  @tracked bulkActions = [];
143
149
 
@@ -179,6 +185,8 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
179
185
  filterComponentPlaceholder: 'Select device',
180
186
  filterParam: 'device_uuid',
181
187
  model: 'device',
188
+ modelNamePath: 'displayName',
189
+ query: { telematic_uuid: this.telematic?.id },
182
190
  },
183
191
  {
184
192
  label: 'Value',
@@ -208,6 +216,9 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
208
216
  sortParam: 'last_reading_at',
209
217
  resizable: true,
210
218
  sortable: true,
219
+ filterable: true,
220
+ filterParam: 'last_reading_at',
221
+ filterComponent: 'filter/date',
211
222
  },
212
223
  {
213
224
  label: '',
@@ -241,7 +252,11 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
241
252
  }
242
253
 
243
254
  @action refresh() {
244
- return this.hostRouter.refresh();
255
+ if (this.refreshTask.isRunning) {
256
+ return;
257
+ }
258
+
259
+ return this.refreshTask.perform();
245
260
  }
246
261
 
247
262
  @action clearFilters() {
@@ -249,6 +264,7 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
249
264
  this.status = null;
250
265
  this.type = null;
251
266
  this.device_uuid = null;
267
+ this.last_reading_at = null;
252
268
  this.page = 1;
253
269
  }
254
270
 
@@ -267,4 +283,8 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
267
283
  queryParams: { device_id: sensor.device_uuid },
268
284
  });
269
285
  }
286
+
287
+ @task *refreshTask() {
288
+ yield this.hostRouter.refresh();
289
+ }
270
290
  }
@@ -61,8 +61,7 @@ export default class MaintenanceEquipmentIndexController extends Controller {
61
61
  {
62
62
  label: this.intl.t('column.name'),
63
63
  valuePath: 'name',
64
- cellComponent: 'table/cell/anchor',
65
- cellClassNames: 'uppercase',
64
+ cellComponent: 'cell/equipment-identity',
66
65
  action: this.equipmentActions.transition.view,
67
66
  permission: 'fleet-ops view equipment',
68
67
  resizable: true,
@@ -61,8 +61,7 @@ export default class MaintenancePartsIndexController extends Controller {
61
61
  {
62
62
  label: this.intl.t('column.name'),
63
63
  valuePath: 'name',
64
- cellComponent: 'table/cell/anchor',
65
- cellClassNames: 'uppercase',
64
+ cellComponent: 'cell/part-identity',
66
65
  action: this.partActions.transition.view,
67
66
  permission: 'fleet-ops view part',
68
67
  resizable: true,
@@ -1,16 +1,18 @@
1
1
  import Controller from '@ember/controller';
2
2
  import { inject as service } from '@ember/service';
3
3
  import { tracked } from '@glimmer/tracking';
4
+ import fleetOpsOptions from '../../../utils/fleet-ops-options';
4
5
 
5
6
  export default class MaintenanceWorkOrdersIndexController extends Controller {
6
7
  @service workOrderActions;
7
8
  @service intl;
8
9
 
9
- @tracked queryParams = ['status', 'priority', 'page', 'limit', 'sort', 'query', 'public_id', 'created_at', 'updated_at'];
10
+ @tracked queryParams = ['category', 'status', 'priority', 'page', 'limit', 'sort', 'query', 'public_id', 'created_at', 'updated_at'];
10
11
  @tracked page = 1;
11
12
  @tracked limit;
12
13
  @tracked sort = '-created_at';
13
14
  @tracked public_id;
15
+ @tracked category;
14
16
  @tracked status;
15
17
  @tracked priority;
16
18
 
@@ -43,6 +45,21 @@ export default class MaintenanceWorkOrdersIndexController extends Controller {
43
45
  filterComponent: 'filter/string',
44
46
  },
45
47
  { label: this.intl.t('column.subject'), valuePath: 'subject', resizable: true, sortable: true, filterable: true, filterParam: 'subject', filterComponent: 'filter/string' },
48
+ {
49
+ label: this.intl.t('column.category'),
50
+ valuePath: 'category',
51
+ cellComponent: 'table/cell/base',
52
+ humanize: true,
53
+ resizable: true,
54
+ sortable: true,
55
+ filterable: true,
56
+ filterParam: 'category',
57
+ filterComponent: 'filter/select',
58
+ filterOptionLabel: 'label',
59
+ filterOptionValue: 'value',
60
+ filterOptions: fleetOpsOptions('workOrderCategories'),
61
+ placeholder: 'Select work order category',
62
+ },
46
63
  {
47
64
  label: this.intl.t('column.status'),
48
65
  valuePath: 'status',