@fleetbase/fleetops-engine 0.6.52 → 0.6.54

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 (151) hide show
  1. package/addon/components/device/details.hbs +106 -135
  2. package/addon/components/device/details.js +174 -1
  3. package/addon/components/device/panel-header.hbs +2 -2
  4. package/addon/components/layout/fleet-ops-sidebar/operations-monitor.hbs +201 -0
  5. package/addon/components/layout/fleet-ops-sidebar/operations-monitor.js +654 -0
  6. package/addon/components/layout/fleet-ops-sidebar.hbs +19 -233
  7. package/addon/components/layout/fleet-ops-sidebar.js +364 -395
  8. package/addon/components/maintenance-schedule/form.js +1 -0
  9. package/addon/components/order/form/details.hbs +1 -43
  10. package/addon/components/order/form/details.js +18 -53
  11. package/addon/components/order/form/orchestrator-constraints.hbs +40 -0
  12. package/addon/components/order/form/orchestrator-constraints.js +61 -0
  13. package/addon/components/order/form/payload.js +50 -2
  14. package/addon/components/order/form/route.js +15 -0
  15. package/addon/components/order/form/service-rate.hbs +62 -11
  16. package/addon/components/order/form/service-rate.js +124 -2
  17. package/addon/components/order/form.hbs +2 -0
  18. package/addon/components/telematic/details.hbs +7 -1
  19. package/addon/components/telematic/form.js +16 -8
  20. package/addon/components/work-order/details.hbs +5 -1
  21. package/addon/components/work-order/form.hbs +26 -4
  22. package/addon/components/work-order/form.js +5 -1
  23. package/addon/controllers/connectivity/devices/index/details/events.js +244 -1
  24. package/addon/controllers/connectivity/devices/index/details/sensors.js +199 -0
  25. package/addon/controllers/connectivity/devices/index/details/vehicle.js +74 -0
  26. package/addon/controllers/connectivity/devices/index/details.js +12 -0
  27. package/addon/controllers/connectivity/devices/index.js +4 -1
  28. package/addon/controllers/connectivity/telematics/details/attachments.js +220 -54
  29. package/addon/controllers/connectivity/telematics/details/devices.js +90 -41
  30. package/addon/controllers/connectivity/telematics/details/events.js +39 -11
  31. package/addon/controllers/connectivity/telematics/details/sensors.js +39 -19
  32. package/addon/controllers/maintenance/index.js +100 -0
  33. package/addon/controllers/maintenance/work-orders/index.js +18 -1
  34. package/addon/controllers/management/fuel-transactions/index.js +1 -1
  35. package/addon/controllers/management/index.js +88 -0
  36. package/addon/controllers/settings/index.js +142 -0
  37. package/addon/extension.js +21 -0
  38. package/addon/routes/analytics/index.js +3 -0
  39. package/addon/routes/connectivity/devices/index/details/events.js +37 -1
  40. package/addon/routes/connectivity/devices/index/details/sensors.js +35 -0
  41. package/addon/routes/connectivity/devices/index/details/vehicle.js +7 -0
  42. package/addon/routes/connectivity/devices/index.js +3 -0
  43. package/addon/routes/connectivity/telematics/details/attachments.js +72 -9
  44. package/addon/routes/connectivity/telematics/details/devices.js +4 -0
  45. package/addon/routes/connectivity/telematics/details/sensors.js +1 -0
  46. package/addon/routes/connectivity/telematics/details.js +1 -1
  47. package/addon/routes/connectivity/telematics/edit.js +1 -1
  48. package/addon/routes/maintenance/index.js +3 -0
  49. package/addon/routes/maintenance/work-orders/index.js +3 -0
  50. package/addon/routes/settings/index.js +3 -0
  51. package/addon/routes.js +2 -0
  52. package/addon/services/order-creation.js +54 -1
  53. package/addon/services/order-validation.js +3 -2
  54. package/addon/services/service-rate-actions.js +1 -0
  55. package/addon/styles/fleetops-engine.css +1821 -6
  56. package/addon/templates/analytics/index.hbs +14 -0
  57. package/addon/templates/analytics/reports/index.hbs +4 -4
  58. package/addon/templates/connectivity/devices/index/details/events.hbs +85 -1
  59. package/addon/templates/connectivity/devices/index/details/sensors.hbs +73 -0
  60. package/addon/templates/connectivity/devices/index/details/vehicle.hbs +84 -0
  61. package/addon/templates/connectivity/telematics/details/attachments.hbs +198 -121
  62. package/addon/templates/connectivity/telematics/details/devices.hbs +4 -1
  63. package/addon/templates/connectivity/telematics/details/events.hbs +4 -1
  64. package/addon/templates/connectivity/telematics/details/sensors.hbs +3 -0
  65. package/addon/templates/maintenance/index.hbs +113 -0
  66. package/addon/templates/management/fuel-transactions/index/details.hbs +1 -1
  67. package/addon/templates/management/index.hbs +109 -73
  68. package/addon/templates/management/vehicles/index/edit.hbs +1 -1
  69. package/addon/templates/operations/orders/index.hbs +1 -1
  70. package/addon/templates/operations/service-rates/index.hbs +1 -1
  71. package/addon/templates/settings/index.hbs +83 -0
  72. package/addon/templates/settings/routing.hbs +2 -2
  73. package/addon/utils/fleet-ops-options.js +38 -0
  74. package/app/components/order/form/orchestrator-constraints.js +1 -0
  75. package/app/controllers/connectivity/devices/index/details/sensors.js +1 -0
  76. package/app/controllers/connectivity/devices/index/details/vehicle.js +1 -0
  77. package/app/controllers/maintenance/index.js +1 -0
  78. package/app/controllers/management/index.js +1 -0
  79. package/app/controllers/settings/index.js +1 -0
  80. package/app/routes/analytics/index.js +1 -0
  81. package/app/routes/connectivity/devices/index/details/sensors.js +1 -0
  82. package/app/routes/connectivity/devices/index/details/vehicle.js +1 -0
  83. package/app/routes/maintenance/index.js +1 -0
  84. package/app/routes/settings/index.js +1 -0
  85. package/app/templates/analytics/index.js +1 -0
  86. package/app/templates/connectivity/devices/index/details/sensors.js +1 -0
  87. package/app/templates/connectivity/devices/index/details/vehicle.js +1 -0
  88. package/app/templates/maintenance/index.js +1 -0
  89. package/app/templates/management/index.js +1 -0
  90. package/app/templates/settings/index.js +1 -0
  91. package/composer.json +1 -1
  92. package/extension.json +1 -1
  93. package/package.json +3 -3
  94. package/server/migrations/2025_08_28_054930_create_work_orders_table.php +1 -0
  95. package/server/migrations/2026_06_15_000001_normalize_device_attachable_vehicle_morph_types.php +30 -0
  96. package/server/migrations/2026_06_18_000001_add_category_to_work_orders_table.php +32 -0
  97. package/server/seeders/Testing/MaintenanceSeeder.php +5 -4
  98. package/server/src/Console/Commands/FixInvalidPolymorphicRelationTypeNamespaces.php +1 -0
  99. package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +1 -0
  100. package/server/src/Console/Commands/SyncTelematics.php +89 -0
  101. package/server/src/Exceptions/TelematicProviderException.php +13 -2
  102. package/server/src/Http/Controllers/Api/v1/OrderController.php +6 -21
  103. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +112 -11
  104. package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +16 -5
  105. package/server/src/Http/Controllers/Internal/v1/FleetController.php +9 -0
  106. package/server/src/Http/Controllers/Internal/v1/HubController.php +300 -0
  107. package/server/src/Http/Controllers/Internal/v1/LiveController.php +177 -0
  108. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +1 -0
  109. package/server/src/Http/Controllers/Internal/v1/OrderController.php +4 -32
  110. package/server/src/Http/Controllers/Internal/v1/SearchController.php +506 -0
  111. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +4 -4
  112. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +1 -1
  113. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +94 -10
  114. package/server/src/Http/Filter/DeviceEventFilter.php +44 -0
  115. package/server/src/Http/Filter/DeviceFilter.php +131 -0
  116. package/server/src/Http/Filter/DriverFilter.php +6 -0
  117. package/server/src/Http/Filter/SensorFilter.php +125 -0
  118. package/server/src/Http/Filter/VehicleFilter.php +19 -0
  119. package/server/src/Http/Requests/CreateDriverRequest.php +14 -13
  120. package/server/src/Http/Requests/Internal/CreateDriverRequest.php +1 -0
  121. package/server/src/Http/Resources/v1/Driver.php +11 -2
  122. package/server/src/Http/Resources/v1/WorkOrder.php +1 -0
  123. package/server/src/Jobs/FinalizeApiOrderCreation.php +47 -0
  124. package/server/src/Jobs/FinalizeInternalOrderCreation.php +35 -0
  125. package/server/src/Jobs/NotifyBulkAssignedDriver.php +47 -0
  126. package/server/src/Jobs/SyncTelematicDevicesJob.php +181 -66
  127. package/server/src/Models/Device.php +15 -1
  128. package/server/src/Models/DeviceEvent.php +1 -1
  129. package/server/src/Models/Driver.php +17 -1
  130. package/server/src/Models/Sensor.php +15 -2
  131. package/server/src/Models/Telematic.php +1 -1
  132. package/server/src/Models/Vehicle.php +5 -1
  133. package/server/src/Models/WorkOrder.php +5 -2
  134. package/server/src/Observers/DriverObserver.php +3 -3
  135. package/server/src/Observers/FleetObserver.php +23 -0
  136. package/server/src/Observers/VehicleObserver.php +3 -3
  137. package/server/src/Providers/FleetOpsServiceProvider.php +12 -0
  138. package/server/src/Support/LiveCacheService.php +1 -1
  139. package/server/src/Support/Telematics/Providers/AfaqyProvider.php +188 -28
  140. package/server/src/Support/Telematics/Providers/SafeeProvider.php +44 -3
  141. package/server/src/Support/Telematics/TelematicService.php +330 -30
  142. package/server/src/routes.php +10 -0
  143. package/server/tests/DeviceFilterTest.php +36 -0
  144. package/server/tests/HubRoutesTest.php +62 -0
  145. package/server/tests/OperationsMonitorEndpointTest.php +38 -0
  146. package/server/tests/OrderQueuedClosureRegressionTest.php +36 -0
  147. package/server/tests/TelematicsHardeningTest.php +455 -3
  148. package/server/tests/VehicleDriverAssignmentTest.php +27 -0
  149. package/translations/ar-ae.yml +1 -1
  150. package/translations/en-us.yaml +1 -0
  151. package/translations/vi-vn.yaml +1 -1
@@ -0,0 +1,199 @@
1
+ import Controller from '@ember/controller';
2
+ import { action } from '@ember/object';
3
+ import { inject as service } from '@ember/service';
4
+ import { tracked } from '@glimmer/tracking';
5
+ import { task, timeout } from 'ember-concurrency';
6
+ import fleetOpsOptions from '../../../../../utils/fleet-ops-options';
7
+
8
+ export default class ConnectivityDevicesIndexDetailsSensorsController extends Controller {
9
+ @service sensorActions;
10
+ @service hostRouter;
11
+ @service intl;
12
+
13
+ @tracked queryParams = ['sensors_page', 'sensors_limit', 'sensors_sort', 'sensors_query', 'sensors_status', 'sensors_type', 'sensors_last_reading_at'];
14
+ @tracked device;
15
+ @tracked sensors_page = 1;
16
+ @tracked sensors_limit;
17
+ @tracked sensors_sort = '-updated_at';
18
+ @tracked sensors_query;
19
+ @tracked sensors_status;
20
+ @tracked sensors_type;
21
+ @tracked sensors_last_reading_at;
22
+
23
+ @tracked bulkActions = [];
24
+
25
+ get sensors() {
26
+ return Array.from(this.model ?? []);
27
+ }
28
+
29
+ get totalSensors() {
30
+ return this.model?.meta?.total ?? this.sensors.length;
31
+ }
32
+
33
+ get activeSensorsCount() {
34
+ return this.sensors.filter((sensor) => sensor.is_active || sensor.status === 'active' || sensor.status === 'online').length;
35
+ }
36
+
37
+ get reportingSensorsCount() {
38
+ return this.sensors.filter((sensor) => sensor.last_value || sensor.last_reading_at).length;
39
+ }
40
+
41
+ get outOfRangeSensorsCount() {
42
+ return this.sensors.filter((sensor) => ['out_of_range', 'above_maximum', 'below_minimum'].includes(sensor.threshold_status)).length;
43
+ }
44
+
45
+ get hasActiveFilters() {
46
+ return Boolean(this.sensors_query || this.sensors_status || this.sensors_type || this.sensors_last_reading_at);
47
+ }
48
+
49
+ get metrics() {
50
+ return [
51
+ { label: 'Sensors', value: this.totalSensors, icon: 'gauge-high', accentClass: 'fleetops-connectivity-kpi-accent-blue' },
52
+ { label: 'Active', value: this.activeSensorsCount, icon: 'signal', accentClass: 'fleetops-connectivity-kpi-accent-green' },
53
+ { label: 'Reporting', value: this.reportingSensorsCount, icon: 'chart-line', accentClass: 'fleetops-connectivity-kpi-accent-amber' },
54
+ {
55
+ label: 'Out of range',
56
+ value: this.outOfRangeSensorsCount,
57
+ icon: 'triangle-exclamation',
58
+ accentClass: this.outOfRangeSensorsCount ? 'fleetops-connectivity-kpi-accent-rose' : 'fleetops-connectivity-kpi-accent-green',
59
+ },
60
+ ];
61
+ }
62
+
63
+ get actionButtons() {
64
+ return [
65
+ {
66
+ icon: 'refresh',
67
+ size: 'sm',
68
+ onClick: this.refresh,
69
+ helpText: this.intl.t('common.refresh'),
70
+ wrapperClass: 'fleetops-telematics-action-button',
71
+ isLoading: this.refreshTask.isRunning,
72
+ disabled: this.refreshTask.isRunning,
73
+ },
74
+ ];
75
+ }
76
+
77
+ get columns() {
78
+ return [
79
+ {
80
+ sticky: true,
81
+ label: this.intl.t('column.name'),
82
+ valuePath: 'name',
83
+ cellComponent: 'table/cell/anchor',
84
+ action: this.sensorActions.transition.view,
85
+ permission: 'fleet-ops view sensor',
86
+ resizable: true,
87
+ sortable: true,
88
+ filterable: true,
89
+ filterParam: 'sensors_query',
90
+ filterComponent: 'filter/string',
91
+ },
92
+ {
93
+ label: 'Type',
94
+ valuePath: 'type',
95
+ resizable: true,
96
+ sortable: true,
97
+ filterable: true,
98
+ filterParam: 'sensors_type',
99
+ filterComponent: 'filter/multi-option',
100
+ filterOptions: fleetOpsOptions('sensorTypes'),
101
+ },
102
+ {
103
+ label: 'Value',
104
+ valuePath: 'last_value',
105
+ resizable: true,
106
+ sortable: true,
107
+ },
108
+ {
109
+ label: 'Unit',
110
+ valuePath: 'unit',
111
+ resizable: true,
112
+ sortable: true,
113
+ },
114
+ {
115
+ label: 'Threshold',
116
+ valuePath: 'threshold_status',
117
+ cellComponent: 'table/cell/status',
118
+ resizable: true,
119
+ sortable: true,
120
+ },
121
+ {
122
+ label: this.intl.t('column.status'),
123
+ valuePath: 'status',
124
+ cellComponent: 'table/cell/status',
125
+ resizable: true,
126
+ sortable: true,
127
+ filterable: true,
128
+ filterParam: 'sensors_status',
129
+ filterComponent: 'filter/multi-option',
130
+ filterOptions: fleetOpsOptions('sensorStatuses'),
131
+ },
132
+ {
133
+ label: 'Last Reading',
134
+ valuePath: 'lastReadingAt',
135
+ sortParam: 'last_reading_at',
136
+ resizable: true,
137
+ sortable: true,
138
+ filterable: true,
139
+ filterParam: 'sensors_last_reading_at',
140
+ filterComponent: 'filter/date',
141
+ },
142
+ {
143
+ label: '',
144
+ cellComponent: 'table/cell/dropdown',
145
+ ddButtonText: false,
146
+ ddButtonIcon: 'ellipsis-h',
147
+ ddButtonIconPrefix: 'fas',
148
+ ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.sensor') }),
149
+ cellClassNames: 'overflow-visible align-middle',
150
+ wrapperClass: 'flex items-center justify-end mx-2',
151
+ sticky: 'right',
152
+ width: 60,
153
+ actions: [
154
+ {
155
+ label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.sensor') }),
156
+ fn: this.sensorActions.transition.view,
157
+ permission: 'fleet-ops view sensor',
158
+ },
159
+ {
160
+ label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.sensor') }),
161
+ fn: this.sensorActions.transition.edit,
162
+ permission: 'fleet-ops update sensor',
163
+ },
164
+ ],
165
+ sortable: false,
166
+ filterable: false,
167
+ resizable: false,
168
+ searchable: false,
169
+ },
170
+ ];
171
+ }
172
+
173
+ @action refresh() {
174
+ if (this.refreshTask.isRunning) {
175
+ return;
176
+ }
177
+
178
+ return this.refreshTask.perform();
179
+ }
180
+
181
+ @task *refreshTask() {
182
+ yield this.hostRouter.refresh();
183
+ }
184
+
185
+ @task({ restartable: true }) *searchTask(event) {
186
+ const {
187
+ target: { value },
188
+ } = event;
189
+
190
+ if (!value) {
191
+ this.sensors_query = null;
192
+ return;
193
+ }
194
+
195
+ yield timeout(250);
196
+ if (this.sensors_page > 1) this.sensors_page = 1;
197
+ this.sensors_query = value;
198
+ }
199
+ }
@@ -0,0 +1,74 @@
1
+ import Controller from '@ember/controller';
2
+ import { action } from '@ember/object';
3
+ import { inject as service } from '@ember/service';
4
+ import { tracked } from '@glimmer/tracking';
5
+
6
+ export default class ConnectivityDevicesIndexDetailsVehicleController extends Controller {
7
+ @service deviceActions;
8
+ @service hostRouter;
9
+ @service intl;
10
+
11
+ @tracked queryParams = [];
12
+
13
+ get device() {
14
+ return this.model;
15
+ }
16
+
17
+ get vehicle() {
18
+ return this.device?.attachable;
19
+ }
20
+
21
+ get vehicleName() {
22
+ return this.device?.attached_to_name ?? this.vehicle?.displayName ?? this.vehicle?.display_name ?? this.vehicle?.name;
23
+ }
24
+
25
+ get vehicleSubtitle() {
26
+ return this.vehicle?.plate_number ?? this.vehicle?.vin ?? this.vehicle?.public_id ?? this.device?.attachable_uuid;
27
+ }
28
+
29
+ get vehiclePhotoUrl() {
30
+ return this.vehicle?.photo_url ?? this.vehicle?.avatar_url;
31
+ }
32
+
33
+ get vehicleStatus() {
34
+ return this.vehicle?.status ?? (this.vehicle?.online ? 'online' : null);
35
+ }
36
+
37
+ get vehicleDriverName() {
38
+ return this.vehicle?.driver?.name ?? this.vehicle?.driver_name;
39
+ }
40
+
41
+ get plateNumber() {
42
+ return this.vehicle?.plate_number;
43
+ }
44
+
45
+ get vin() {
46
+ return this.vehicle?.vin;
47
+ }
48
+
49
+ get callSign() {
50
+ return this.vehicle?.call_sign;
51
+ }
52
+
53
+ get yearMakeModel() {
54
+ return this.vehicle?.yearMakeModel ?? [this.vehicle?.year, this.vehicle?.make, this.vehicle?.model].filter(Boolean).join(' ');
55
+ }
56
+
57
+ get hasVehicle() {
58
+ return Boolean(this.vehicleName || this.device?.attachable_uuid);
59
+ }
60
+
61
+ @action attachToVehicle() {
62
+ return this.deviceActions.attachToVehicle(this.device, { callback: () => this.hostRouter.refresh() });
63
+ }
64
+
65
+ @action detachFromVehicle() {
66
+ return this.deviceActions.detachFromVehicle(this.device, { callback: () => this.hostRouter.refresh() });
67
+ }
68
+
69
+ @action openVehicle() {
70
+ if (this.vehicle?.id) {
71
+ return this.hostRouter.transitionTo('console.fleet-ops.management.vehicles.index.details', this.vehicle);
72
+ }
73
+ }
74
+ }
@@ -15,6 +15,18 @@ export default class ConnectivityDevicesIndexDetailsController extends Controlle
15
15
  route: 'connectivity.devices.index.details.index',
16
16
  label: this.intl.t('common.overview'),
17
17
  },
18
+ {
19
+ route: 'connectivity.devices.index.details.vehicle',
20
+ label: this.intl.t('resource.vehicle'),
21
+ },
22
+ {
23
+ route: 'connectivity.devices.index.details.sensors',
24
+ label: this.intl.t('resource.sensors'),
25
+ },
26
+ {
27
+ route: 'connectivity.devices.index.details.events',
28
+ label: this.intl.t('resource.device-events'),
29
+ },
18
30
  ...(isArray(registeredTabs) ? registeredTabs : []),
19
31
  ];
20
32
  }
@@ -9,12 +9,15 @@ export default class ConnectivityDevicesIndexController extends Controller {
9
9
  @service intl;
10
10
 
11
11
  /** query params */
12
- @tracked queryParams = ['name', 'page', 'limit', 'sort', 'query', 'public_id', 'created_at', 'updated_at'];
12
+ @tracked queryParams = ['name', 'status', 'attachment_state', 'telematic', 'page', 'limit', 'sort', 'query', 'public_id', 'created_at', 'updated_at'];
13
13
  @tracked page = 1;
14
14
  @tracked limit;
15
15
  @tracked sort = '-created_at';
16
16
  @tracked public_id;
17
17
  @tracked name;
18
+ @tracked status;
19
+ @tracked attachment_state;
20
+ @tracked telematic;
18
21
 
19
22
  /** action buttons */
20
23
  @tracked actionButtons = [