@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.
- package/addon/components/admin/routing-settings.hbs +2 -1
- package/addon/components/cell/attached-vehicle.hbs +10 -0
- package/addon/components/cell/attached-vehicle.js +58 -0
- package/addon/components/cell/device-identity.hbs +24 -0
- package/addon/components/cell/device-identity.js +129 -0
- package/addon/components/cell/driver-identity.hbs +33 -0
- package/addon/components/cell/driver-identity.js +143 -0
- package/addon/components/cell/equipment-identity.hbs +5 -0
- package/addon/components/cell/equipment-identity.js +48 -0
- package/addon/components/cell/part-identity.hbs +5 -0
- package/addon/components/cell/part-identity.js +63 -0
- package/addon/components/cell/telematic-device.hbs +38 -0
- package/addon/components/cell/telematic-device.js +44 -0
- package/addon/components/cell/telematic-provider.hbs +33 -16
- package/addon/components/cell/telematic-provider.js +50 -8
- package/addon/components/cell/vehicle-identity.hbs +33 -0
- package/addon/components/cell/vehicle-identity.js +138 -0
- package/addon/components/device/details.hbs +106 -135
- package/addon/components/device/details.js +174 -1
- package/addon/components/device/form.hbs +2 -2
- package/addon/components/device/form.js +7 -0
- package/addon/components/device/panel-header.hbs +46 -21
- package/addon/components/device/panel-header.js +49 -1
- package/addon/components/device/panel-tabs/events.hbs +30 -0
- package/addon/components/device/panel-tabs/events.js +128 -0
- package/addon/components/device/panel-tabs/sensors.hbs +30 -0
- package/addon/components/device/panel-tabs/sensors.js +93 -0
- package/addon/components/device/panel-tabs/vehicle.hbs +68 -0
- package/addon/components/device/panel-tabs/vehicle.js +90 -0
- package/addon/components/equipment/form.js +8 -1
- package/addon/components/layout/fleet-ops-sidebar/operations-monitor.js +76 -11
- package/addon/components/layout/fleet-ops-sidebar.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +101 -17
- package/addon/components/map/drawer/device-event-listing.js +2 -0
- package/addon/components/map/drawer/driver-listing.js +2 -0
- package/addon/components/map/drawer/place-listing.js +2 -0
- package/addon/components/map/drawer/position-listing.hbs +11 -6
- package/addon/components/map/drawer/position-listing.js +17 -4
- package/addon/components/map/drawer/vehicle-listing.js +2 -0
- package/addon/components/order/form/details.hbs +1 -43
- package/addon/components/order/form/details.js +18 -53
- package/addon/components/order/form/orchestrator-constraints.hbs +40 -0
- package/addon/components/order/form/orchestrator-constraints.js +61 -0
- package/addon/components/order/form/payload.js +48 -2
- package/addon/components/order/form/route.js +15 -0
- package/addon/components/order/form/service-rate.hbs +62 -11
- package/addon/components/order/form/service-rate.js +124 -2
- package/addon/components/order/form.hbs +2 -0
- package/addon/components/sensor/panel-header.hbs +47 -15
- package/addon/components/sensor/panel-header.js +59 -1
- package/addon/components/table/cell/dropdown/action-item.hbs +31 -0
- package/addon/components/table/cell/dropdown/action-item.js +62 -0
- package/addon/components/table/cell/dropdown.hbs +28 -0
- package/addon/components/table/cell/dropdown.js +91 -0
- package/addon/components/telematic/details.hbs +7 -1
- package/addon/components/telematic/form.js +16 -8
- package/addon/components/vendor/panel-header.hbs +82 -0
- package/addon/components/vendor/panel-header.js +48 -0
- package/addon/components/work-order/details.hbs +5 -1
- package/addon/components/work-order/form.hbs +26 -4
- package/addon/components/work-order/form.js +5 -1
- package/addon/controllers/connectivity/devices/index/details/events.js +244 -1
- package/addon/controllers/connectivity/devices/index/details/sensors.js +199 -0
- package/addon/controllers/connectivity/devices/index/details/vehicle.js +122 -0
- package/addon/controllers/connectivity/devices/index/details.js +12 -0
- package/addon/controllers/connectivity/devices/index.js +144 -129
- package/addon/controllers/connectivity/events/details.js +3 -0
- package/addon/controllers/connectivity/events/index.js +187 -11
- package/addon/controllers/connectivity/sensors/index.js +156 -14
- package/addon/controllers/connectivity/telematics/details/attachments.js +220 -54
- package/addon/controllers/connectivity/telematics/details/devices.js +170 -129
- package/addon/controllers/connectivity/telematics/details/events.js +39 -11
- package/addon/controllers/connectivity/telematics/details/sensors.js +39 -19
- package/addon/controllers/maintenance/equipment/index.js +1 -2
- package/addon/controllers/maintenance/parts/index.js +1 -2
- package/addon/controllers/maintenance/work-orders/index.js +18 -1
- package/addon/controllers/management/drivers/index.js +82 -42
- package/addon/controllers/management/fuel-reports/index.js +63 -4
- package/addon/controllers/management/issues/index.js +63 -4
- package/addon/controllers/management/vehicles/index.js +33 -6
- package/addon/routes/connectivity/devices/index/details/events.js +37 -1
- package/addon/routes/connectivity/devices/index/details/sensors.js +35 -0
- package/addon/routes/connectivity/devices/index/details/vehicle.js +29 -0
- package/addon/routes/connectivity/devices/index.js +7 -0
- package/addon/routes/connectivity/events/details.js +3 -0
- package/addon/routes/connectivity/events/index.js +6 -2
- package/addon/routes/connectivity/sensors/index.js +7 -2
- package/addon/routes/connectivity/telematics/details/attachments.js +72 -9
- package/addon/routes/connectivity/telematics/details/devices.js +6 -0
- package/addon/routes/connectivity/telematics/details/sensors.js +1 -0
- package/addon/routes/connectivity/telematics/details.js +1 -1
- package/addon/routes/connectivity/telematics/edit.js +1 -1
- package/addon/routes/maintenance/work-orders/index.js +1 -0
- package/addon/routes.js +2 -0
- package/addon/services/device-actions.js +30 -0
- package/addon/services/device-event-actions.js +1 -1
- package/addon/services/equipment-actions.js +1 -0
- package/addon/services/order-creation.js +54 -1
- package/addon/services/order-validation.js +3 -2
- package/addon/services/sensor-actions.js +3 -0
- package/addon/services/service-rate-actions.js +40 -1
- package/addon/services/vehicle-actions.js +24 -12
- package/addon/services/vendor-actions.js +3 -0
- package/addon/styles/fleetops-engine.css +28 -4
- package/addon/templates/connectivity/devices/index/details/events.hbs +85 -1
- package/addon/templates/connectivity/devices/index/details/sensors.hbs +73 -0
- package/addon/templates/connectivity/devices/index/details/vehicle.hbs +147 -0
- package/addon/templates/connectivity/telematics/details/attachments.hbs +198 -121
- package/addon/templates/connectivity/telematics/details/devices.hbs +4 -1
- package/addon/templates/connectivity/telematics/details/events.hbs +4 -1
- package/addon/templates/connectivity/telematics/details/sensors.hbs +3 -0
- package/addon/templates/management/vehicles/index/edit.hbs +1 -1
- package/addon/templates/management/vendors/index/details.hbs +2 -2
- package/addon/templates/settings/notifications.hbs +2 -1
- package/addon/templates/settings/routing.hbs +1 -0
- package/addon/utils/device-table-columns.js +288 -0
- package/addon/utils/fleet-ops-options.js +38 -0
- package/addon/utils/identity-cell-resource.js +20 -0
- package/addon/utils/map-drawer-dropdown-position.js +47 -0
- package/addon/utils/trackable-option.js +93 -0
- package/app/components/cell/attached-vehicle.js +1 -0
- package/app/components/cell/device-identity.js +1 -0
- package/app/components/cell/driver-identity.js +1 -0
- package/app/components/cell/equipment-identity.js +1 -0
- package/app/components/cell/part-identity.js +1 -0
- package/app/components/cell/telematic-device.js +1 -0
- package/app/components/cell/vehicle-identity.js +1 -0
- package/app/components/device/panel-tabs/events.hbs +30 -0
- package/app/components/device/panel-tabs/events.js +128 -0
- package/app/components/device/panel-tabs/sensors.hbs +30 -0
- package/app/components/device/panel-tabs/sensors.js +93 -0
- package/app/components/device/panel-tabs/vehicle.hbs +68 -0
- package/app/components/device/panel-tabs/vehicle.js +90 -0
- package/app/components/order/form/orchestrator-constraints.js +1 -0
- package/app/components/table/cell/dropdown/action-item.js +1 -0
- package/app/components/table/cell/dropdown.js +1 -0
- package/app/components/vendor/panel-header.js +1 -0
- package/app/controllers/connectivity/devices/index/details/sensors.js +1 -0
- package/app/controllers/connectivity/devices/index/details/vehicle.js +1 -0
- package/app/controllers/connectivity/events/{index/details.js → details.js} +1 -1
- package/app/routes/connectivity/devices/index/details/sensors.js +1 -0
- package/app/routes/connectivity/devices/index/details/vehicle.js +1 -0
- package/app/routes/connectivity/events/{index/details.js → details.js} +1 -1
- package/app/templates/connectivity/devices/index/details/sensors.js +1 -0
- package/app/templates/connectivity/devices/index/details/vehicle.js +1 -0
- package/app/templates/connectivity/events/{index/details.js → details.js} +1 -1
- package/app/utils/map-drawer-dropdown-position.js +1 -0
- package/app/utils/trackable-option.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +4 -4
- package/server/migrations/2025_08_28_054930_create_work_orders_table.php +1 -0
- package/server/migrations/2026_06_18_000001_add_category_to_work_orders_table.php +32 -0
- package/server/seeders/Testing/MaintenanceSeeder.php +5 -4
- package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +1 -0
- package/server/src/Console/Commands/SyncTelematics.php +89 -0
- package/server/src/Exceptions/TelematicProviderException.php +13 -2
- package/server/src/Http/Controllers/Api/v1/OrderController.php +6 -21
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +55 -1
- package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +17 -6
- package/server/src/Http/Controllers/Internal/v1/FleetController.php +9 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +178 -1
- package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +1 -0
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +4 -32
- package/server/src/Http/Controllers/Internal/v1/SearchController.php +2 -2
- package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +4 -4
- package/server/src/Http/Controllers/Internal/v1/ServiceRateController.php +82 -13
- package/server/src/Http/Filter/DeviceEventFilter.php +65 -0
- package/server/src/Http/Filter/DeviceFilter.php +80 -0
- package/server/src/Http/Filter/SensorFilter.php +125 -0
- package/server/src/Http/Filter/VehicleFilter.php +13 -0
- package/server/src/Http/Requests/CreateDriverRequest.php +14 -13
- package/server/src/Http/Requests/Internal/CreateDriverRequest.php +1 -0
- package/server/src/Http/Resources/v1/Driver.php +11 -2
- package/server/src/Http/Resources/v1/Index/Vehicle.php +19 -0
- package/server/src/Http/Resources/v1/WorkOrder.php +1 -0
- package/server/src/Jobs/FinalizeApiOrderCreation.php +47 -0
- package/server/src/Jobs/FinalizeInternalOrderCreation.php +35 -0
- package/server/src/Jobs/NotifyBulkAssignedDriver.php +47 -0
- package/server/src/Jobs/SyncTelematicDevicesJob.php +180 -123
- package/server/src/Models/Device.php +17 -1
- package/server/src/Models/DeviceEvent.php +82 -1
- package/server/src/Models/Driver.php +16 -0
- package/server/src/Models/Equipment.php +55 -0
- package/server/src/Models/Sensor.php +15 -2
- package/server/src/Models/Telematic.php +1 -1
- package/server/src/Models/Vehicle.php +5 -1
- package/server/src/Models/WorkOrder.php +5 -2
- package/server/src/Observers/DriverObserver.php +3 -3
- package/server/src/Observers/FleetObserver.php +23 -0
- package/server/src/Observers/VehicleObserver.php +3 -3
- package/server/src/Providers/FleetOpsServiceProvider.php +2 -0
- package/server/src/Support/LiveCacheService.php +1 -1
- package/server/src/Support/Telematics/Providers/AfaqyProvider.php +143 -20
- package/server/src/Support/Telematics/Providers/FlespiProvider.php +89 -15
- package/server/src/Support/Telematics/Providers/GeotabProvider.php +123 -35
- package/server/src/Support/Telematics/Providers/SafeeProvider.php +70 -5
- package/server/src/Support/Telematics/Providers/SamsaraProvider.php +122 -14
- package/server/src/Support/Telematics/TelematicService.php +330 -30
- package/server/src/routes.php +1 -1
- package/server/tests/DeviceFilterTest.php +45 -0
- package/server/tests/DriverVehicleStatusDefaultTest.php +19 -2
- package/server/tests/EquipmentAssignmentMorphTypeTest.php +35 -0
- package/server/tests/OperationsMonitorEndpointTest.php +38 -0
- package/server/tests/OrderQueuedClosureRegressionTest.php +36 -0
- package/server/tests/ServiceRateRouteValidationTest.php +101 -0
- package/server/tests/TelematicsHardeningTest.php +598 -6
- package/server/tests/VehicleDriverAssignmentTest.php +27 -0
- package/translations/en-us.yaml +1 -0
- package/addon/controllers/connectivity/events/index/details.js +0 -3
- package/addon/routes/connectivity/events/index/details.js +0 -3
- /package/addon/templates/connectivity/events/{index/details.hbs → details.hbs} +0 -0
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
<div class="fleetbase-model-select fleetbase-power-select ember-model-select">
|
|
65
65
|
<PowerSelectMultiple
|
|
66
66
|
@searchEnabled={{true}}
|
|
67
|
+
@searchField="label"
|
|
67
68
|
@options={{this.trackingProviderOptions}}
|
|
68
69
|
@selected={{this.selectedTrackingFallbackOptions}}
|
|
69
70
|
@onChange={{this.setTrackingFallbacks}}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
const connectionStatusOptions = [
|
|
2
|
+
{ label: 'Online', value: 'online' },
|
|
3
|
+
{ label: 'Recently Offline', value: 'recently_offline' },
|
|
4
|
+
{ label: 'Offline', value: 'offline' },
|
|
5
|
+
{ label: 'Long Offline', value: 'long_offline' },
|
|
6
|
+
{ label: 'Never Connected', value: 'never_connected' },
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
const attachmentStateOptions = [
|
|
10
|
+
{ label: 'Attached', value: 'attached' },
|
|
11
|
+
{ label: 'Unattached', value: 'unattached' },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export { connectionStatusOptions, attachmentStateOptions };
|
|
15
|
+
|
|
16
|
+
export default function buildDeviceTableColumns(controller, options = {}) {
|
|
17
|
+
const { showProvider = true, showActions = true, deviceActionMode = 'route', showDeviceStatus = true } = options;
|
|
18
|
+
const viewDevice =
|
|
19
|
+
deviceActionMode === 'panel'
|
|
20
|
+
? (controller.deviceActions.panel?.view ?? controller.deviceActions.transition?.view)
|
|
21
|
+
: (controller.deviceActions.transition?.view ?? controller.deviceActions.panel?.view);
|
|
22
|
+
const editDevice =
|
|
23
|
+
deviceActionMode === 'panel'
|
|
24
|
+
? (controller.deviceActions.panel?.edit ?? controller.deviceActions.transition?.edit)
|
|
25
|
+
: (controller.deviceActions.transition?.edit ?? controller.deviceActions.panel?.edit);
|
|
26
|
+
|
|
27
|
+
const columns = [
|
|
28
|
+
{
|
|
29
|
+
sticky: true,
|
|
30
|
+
label: 'Telematic Device',
|
|
31
|
+
valuePath: 'displayName',
|
|
32
|
+
cellComponent: 'cell/device-identity',
|
|
33
|
+
action: viewDevice,
|
|
34
|
+
compact: true,
|
|
35
|
+
permission: 'fleet-ops view device',
|
|
36
|
+
resizable: true,
|
|
37
|
+
sortable: true,
|
|
38
|
+
filterable: true,
|
|
39
|
+
filterParam: 'query',
|
|
40
|
+
filterComponent: 'filter/string',
|
|
41
|
+
showStatus: showDeviceStatus,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: 'Connection',
|
|
45
|
+
valuePath: 'connection_status',
|
|
46
|
+
cellComponent: 'table/cell/status',
|
|
47
|
+
resizable: true,
|
|
48
|
+
sortable: false,
|
|
49
|
+
filterable: true,
|
|
50
|
+
filterParam: 'connection_status',
|
|
51
|
+
filterComponent: 'filter/multi-option',
|
|
52
|
+
filterOptions: connectionStatusOptions,
|
|
53
|
+
filterOptionLabel: 'label',
|
|
54
|
+
filterOptionValue: 'value',
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
const providerIdColumn = {
|
|
58
|
+
label: 'Provider ID / IMEI',
|
|
59
|
+
valuePath: 'device_id',
|
|
60
|
+
resizable: true,
|
|
61
|
+
sortable: true,
|
|
62
|
+
filterable: true,
|
|
63
|
+
filterParam: 'device_id',
|
|
64
|
+
filterComponent: 'filter/string',
|
|
65
|
+
};
|
|
66
|
+
const vehicleColumn = {
|
|
67
|
+
label: 'Vehicle',
|
|
68
|
+
valuePath: 'attached_to_name',
|
|
69
|
+
cellComponent: 'cell/vehicle-identity',
|
|
70
|
+
action: async (vehicle) => {
|
|
71
|
+
const resolvedVehicle = vehicle?.loadResource ? ((await vehicle.loadResource()) ?? vehicle) : vehicle;
|
|
72
|
+
|
|
73
|
+
if (resolvedVehicle?.id && controller.vehicleActions?.panel?.view) {
|
|
74
|
+
return controller.vehicleActions.panel.view(resolvedVehicle);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
compact: true,
|
|
78
|
+
permission: 'fleet-ops view vehicle',
|
|
79
|
+
showStatusBadge: true,
|
|
80
|
+
emptyText: '-',
|
|
81
|
+
resourcePath: (device) => {
|
|
82
|
+
const attachableType = `${device?.attachable_type ?? ''}`.toLowerCase();
|
|
83
|
+
|
|
84
|
+
if (!device?.attachable_uuid || (attachableType && !attachableType.includes('vehicle'))) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
device.attachable ?? {
|
|
90
|
+
id: device.attachable_uuid,
|
|
91
|
+
displayName: device.attached_to_name,
|
|
92
|
+
display_name: device.attached_to_name,
|
|
93
|
+
name: device.attached_to_name,
|
|
94
|
+
public_id: device.attachable_uuid,
|
|
95
|
+
vehicle_number: device.plate_number ?? device.call_sign ?? device.vehicle_number ?? device.attachable_uuid,
|
|
96
|
+
loadResource: () => controller.resolveAttachedVehicle?.(device),
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
},
|
|
100
|
+
resizable: true,
|
|
101
|
+
sortable: false,
|
|
102
|
+
filterable: true,
|
|
103
|
+
filterParam: 'vehicle',
|
|
104
|
+
filterComponent: 'filter/model',
|
|
105
|
+
filterComponentPlaceholder: 'Select vehicle',
|
|
106
|
+
model: 'vehicle',
|
|
107
|
+
modelNamePath: 'displayName',
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
if (showProvider) {
|
|
111
|
+
columns.push({
|
|
112
|
+
label: 'Telematic Provider',
|
|
113
|
+
valuePath: 'telematic_name',
|
|
114
|
+
cellComponent: 'cell/telematic-provider',
|
|
115
|
+
compact: true,
|
|
116
|
+
action: controller.openTelematic,
|
|
117
|
+
permission: 'fleet-ops view telematic',
|
|
118
|
+
resizable: true,
|
|
119
|
+
sortable: false,
|
|
120
|
+
filterable: true,
|
|
121
|
+
filterParam: 'telematic',
|
|
122
|
+
filterComponent: 'filter/model',
|
|
123
|
+
filterComponentPlaceholder: 'Select telematic',
|
|
124
|
+
model: 'telematic',
|
|
125
|
+
});
|
|
126
|
+
columns.push(vehicleColumn, providerIdColumn);
|
|
127
|
+
} else {
|
|
128
|
+
columns.push(providerIdColumn, vehicleColumn);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
columns.push(
|
|
132
|
+
{
|
|
133
|
+
label: 'Sensors',
|
|
134
|
+
valuePath: 'sensors_count',
|
|
135
|
+
resizable: true,
|
|
136
|
+
sortable: false,
|
|
137
|
+
filterable: false,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
label: 'Last Seen',
|
|
141
|
+
valuePath: 'lastOnlineAt',
|
|
142
|
+
sortParam: 'last_online_at',
|
|
143
|
+
resizable: true,
|
|
144
|
+
sortable: true,
|
|
145
|
+
filterable: true,
|
|
146
|
+
filterParam: 'last_online_at',
|
|
147
|
+
filterComponent: 'filter/date',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
label: 'Provider',
|
|
151
|
+
valuePath: 'provider',
|
|
152
|
+
hidden: true,
|
|
153
|
+
resizable: true,
|
|
154
|
+
sortable: true,
|
|
155
|
+
filterable: true,
|
|
156
|
+
filterParam: 'provider',
|
|
157
|
+
filterComponent: 'filter/string',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
label: 'Type',
|
|
161
|
+
valuePath: 'type',
|
|
162
|
+
hidden: true,
|
|
163
|
+
resizable: true,
|
|
164
|
+
sortable: true,
|
|
165
|
+
filterable: true,
|
|
166
|
+
filterParam: 'type',
|
|
167
|
+
filterComponent: 'filter/multi-option',
|
|
168
|
+
filterOptions: controller.deviceTypeOptions,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
label: 'Serial Number',
|
|
172
|
+
valuePath: 'serial_number',
|
|
173
|
+
hidden: true,
|
|
174
|
+
resizable: true,
|
|
175
|
+
sortable: true,
|
|
176
|
+
filterable: true,
|
|
177
|
+
filterParam: 'serial_number',
|
|
178
|
+
filterComponent: 'filter/string',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
label: controller.intl.t('column.status'),
|
|
182
|
+
valuePath: 'status',
|
|
183
|
+
cellComponent: 'table/cell/status',
|
|
184
|
+
hidden: true,
|
|
185
|
+
resizable: true,
|
|
186
|
+
sortable: true,
|
|
187
|
+
filterable: true,
|
|
188
|
+
filterParam: 'status',
|
|
189
|
+
filterComponent: 'filter/multi-option',
|
|
190
|
+
filterOptions: controller.deviceStatusOptions,
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
label: 'Attachment',
|
|
194
|
+
valuePath: 'attachable_uuid',
|
|
195
|
+
hidden: true,
|
|
196
|
+
resizable: true,
|
|
197
|
+
sortable: false,
|
|
198
|
+
filterable: true,
|
|
199
|
+
filterParam: 'attachment_state',
|
|
200
|
+
filterComponent: 'filter/select',
|
|
201
|
+
filterOptions: attachmentStateOptions,
|
|
202
|
+
filterOptionLabel: 'label',
|
|
203
|
+
filterOptionValue: 'value',
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
label: controller.intl.t('column.updated-at'),
|
|
207
|
+
valuePath: 'updatedAt',
|
|
208
|
+
sortParam: 'updated_at',
|
|
209
|
+
resizable: true,
|
|
210
|
+
sortable: true,
|
|
211
|
+
hidden: true,
|
|
212
|
+
filterable: true,
|
|
213
|
+
filterComponent: 'filter/date',
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
if (showActions) {
|
|
218
|
+
columns.push({
|
|
219
|
+
label: '',
|
|
220
|
+
cellComponent: 'table/cell/dropdown',
|
|
221
|
+
ddButtonText: false,
|
|
222
|
+
ddButtonIcon: 'ellipsis-h',
|
|
223
|
+
ddButtonIconPrefix: 'fas',
|
|
224
|
+
ddMenuLabel: controller.intl.t('common.resource-actions', { resource: controller.intl.t('resource.device') }),
|
|
225
|
+
cellClassNames: 'overflow-visible align-middle',
|
|
226
|
+
wrapperClass: 'flex items-center justify-end mx-2',
|
|
227
|
+
sticky: 'right',
|
|
228
|
+
width: 60,
|
|
229
|
+
actions: [
|
|
230
|
+
{
|
|
231
|
+
label: controller.intl.t('common.view-resource', { resource: controller.intl.t('resource.device') }),
|
|
232
|
+
fn: viewDevice,
|
|
233
|
+
permission: 'fleet-ops view device',
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
label: controller.intl.t('common.edit-resource', { resource: controller.intl.t('resource.device') }),
|
|
237
|
+
fn: editDevice,
|
|
238
|
+
permission: 'fleet-ops update device',
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
label: 'Attach or change vehicle',
|
|
242
|
+
fn: controller.openAttachDeviceModal ?? controller.deviceActions.attachToVehicle,
|
|
243
|
+
permission: 'fleet-ops update device',
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
label: controller.intl.t('device.actions.detach-from-vehicle'),
|
|
247
|
+
fn: controller.deviceActions.detachFromVehicle,
|
|
248
|
+
permission: 'fleet-ops update device',
|
|
249
|
+
isVisible: controller.hasAttachedVehicle,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
separator: true,
|
|
253
|
+
isVisible: controller.hasAttachedVehicle,
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
label: 'View attached vehicle',
|
|
257
|
+
fn: controller.viewAttachedVehicle,
|
|
258
|
+
permission: 'fleet-ops view vehicle',
|
|
259
|
+
isVisible: controller.hasAttachedVehicle,
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
label: 'Locate attached vehicle on map',
|
|
263
|
+
fn: controller.locateAttachedVehicle,
|
|
264
|
+
permission: 'fleet-ops view vehicle',
|
|
265
|
+
isVisible: controller.hasAttachedVehicle,
|
|
266
|
+
},
|
|
267
|
+
...(controller.openDeviceEvents
|
|
268
|
+
? [
|
|
269
|
+
{
|
|
270
|
+
separator: true,
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
label: 'Review recent events',
|
|
274
|
+
fn: controller.openDeviceEvents,
|
|
275
|
+
permission: 'fleet-ops view device-event',
|
|
276
|
+
},
|
|
277
|
+
]
|
|
278
|
+
: []),
|
|
279
|
+
],
|
|
280
|
+
sortable: false,
|
|
281
|
+
filterable: false,
|
|
282
|
+
resizable: false,
|
|
283
|
+
searchable: false,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return columns;
|
|
288
|
+
}
|
|
@@ -216,6 +216,42 @@ export const fuelReportStatuses = [
|
|
|
216
216
|
{ label: 'Reimbursed', value: 'reimbursed', description: 'Driver expense reimbursed' },
|
|
217
217
|
];
|
|
218
218
|
|
|
219
|
+
export const workOrderStatuses = [
|
|
220
|
+
{ label: 'Open', value: 'open', description: 'Work order has been created and is awaiting planning or assignment' },
|
|
221
|
+
{ label: 'Scheduled', value: 'scheduled', description: 'Work has been planned for a specific service window' },
|
|
222
|
+
{ label: 'Assigned', value: 'assigned', description: 'A technician, vendor, or team has been assigned' },
|
|
223
|
+
{ label: 'In Progress', value: 'in_progress', description: 'Work is actively being performed' },
|
|
224
|
+
{ label: 'Awaiting Parts', value: 'awaiting_parts', description: 'Work is blocked until required parts are available' },
|
|
225
|
+
{ label: 'Awaiting Vendor', value: 'awaiting_vendor', description: 'Work is waiting on a third-party vendor or repair shop' },
|
|
226
|
+
{ label: 'On Hold', value: 'on_hold', description: 'Work is temporarily paused' },
|
|
227
|
+
{ label: 'Quality Check', value: 'quality_check', description: 'Work is complete and awaiting verification or road-readiness check' },
|
|
228
|
+
{ label: 'Closed', value: 'closed', description: 'Work is complete and recorded in maintenance history' },
|
|
229
|
+
{ label: 'Canceled', value: 'canceled', description: 'Work order was canceled before completion' },
|
|
230
|
+
];
|
|
231
|
+
|
|
232
|
+
export const workOrderCategories = [
|
|
233
|
+
{ label: 'Preventive Maintenance (PM)', value: 'preventive_maintenance', description: 'Scheduled service intended to prevent failures and downtime' },
|
|
234
|
+
{ label: 'Predictive Maintenance', value: 'predictive_maintenance', description: 'Maintenance triggered by forecasts, telematics, diagnostics, or condition trends' },
|
|
235
|
+
{ label: 'Condition-Based Maintenance', value: 'condition_based_maintenance', description: 'Service based on measured asset condition or threshold readings' },
|
|
236
|
+
{ label: 'Inspection Request', value: 'inspection_request', description: 'Technician or compliance inspection requested for the asset' },
|
|
237
|
+
{ label: 'Failed Inspection', value: 'failed_inspection', description: 'Follow-up work created from a failed inspection or DVIR item' },
|
|
238
|
+
{ label: 'Recall', value: 'recall', description: 'Manufacturer, regulatory, or safety recall work' },
|
|
239
|
+
{ label: 'Compliance / Safety', value: 'compliance_safety', description: 'Required safety, regulatory, or roadworthiness work' },
|
|
240
|
+
{ label: 'General Repair', value: 'general_repair', description: 'General corrective repair that does not fit a more specific category' },
|
|
241
|
+
{ label: 'Mechanical Complaint', value: 'mechanical_complaint', description: 'Engine, drivetrain, suspension, steering, or other mechanical concern' },
|
|
242
|
+
{ label: 'Electrical Complaint', value: 'electrical_complaint', description: 'Battery, charging, lighting, wiring, sensor, or electrical system concern' },
|
|
243
|
+
{ label: 'Brake Issue', value: 'brake_issue', description: 'Brake wear, performance, air brake, ABS, or related safety concern' },
|
|
244
|
+
{ label: 'Tire Issue', value: 'tire_issue', description: 'Tire wear, puncture, blowout, alignment, rotation, or replacement' },
|
|
245
|
+
{ label: 'HVAC / Air Conditioning Issue', value: 'hvac_issue', description: 'Heating, ventilation, defrost, or air conditioning concern' },
|
|
246
|
+
{ label: 'AdBlue / DEF', value: 'adblue_def', description: 'Diesel exhaust fluid, SCR, emissions fluid, or dosing system issue' },
|
|
247
|
+
{ label: 'Fluid Leak', value: 'fluid_leak', description: 'Oil, coolant, fuel, hydraulic, brake fluid, or other leak' },
|
|
248
|
+
{ label: 'Body Damage', value: 'body_damage', description: 'Non-accident body, panel, paint, glass, door, or cosmetic damage' },
|
|
249
|
+
{ label: 'Accident Damage', value: 'accident_damage', description: 'Collision or incident-related inspection and repair' },
|
|
250
|
+
{ label: 'Roadside Assistance', value: 'roadside_assistance', description: 'Tow, recovery, jump start, lockout, or field service request' },
|
|
251
|
+
{ label: 'Breakdown', value: 'breakdown', description: 'Unplanned asset failure requiring urgent repair' },
|
|
252
|
+
{ label: 'Other', value: 'other', description: 'Work that does not fit another operational category' },
|
|
253
|
+
];
|
|
254
|
+
|
|
219
255
|
export const issueStatuses = [
|
|
220
256
|
{ label: 'Open', value: 'open', description: 'Issue is open and unresolved' },
|
|
221
257
|
{ label: 'Pending', value: 'pending', description: 'Issue is logged but work has not yet started' },
|
|
@@ -862,6 +898,8 @@ export default function fleetOpsOptions(key) {
|
|
|
862
898
|
contactStatuses,
|
|
863
899
|
fuelReportTypes,
|
|
864
900
|
fuelReportStatuses,
|
|
901
|
+
workOrderStatuses,
|
|
902
|
+
workOrderCategories,
|
|
865
903
|
issueTypes,
|
|
866
904
|
issueStatuses,
|
|
867
905
|
issueCategories,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { get } from '@ember/object';
|
|
2
|
+
|
|
3
|
+
export function resolveIdentityCellResource(args) {
|
|
4
|
+
const column = args.column ?? {};
|
|
5
|
+
const resourcePath = column.resourcePath;
|
|
6
|
+
|
|
7
|
+
if (typeof resourcePath === 'function') {
|
|
8
|
+
return resourcePath(args.row, args.value, column) ?? null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (typeof resourcePath === 'string') {
|
|
12
|
+
return get(args.row, resourcePath) ?? null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (args.value && typeof args.value === 'object') {
|
|
16
|
+
return args.value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return args.row;
|
|
20
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export default function calculateMapDrawerDropdownPosition(trigger, content) {
|
|
2
|
+
const dropdownRoot = trigger?.closest?.('.ember-basic-dropdown');
|
|
3
|
+
const drawerPanel = trigger?.closest?.('.next-drawer-panel');
|
|
4
|
+
|
|
5
|
+
if (!trigger || !dropdownRoot) {
|
|
6
|
+
return { style: {} };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
10
|
+
const rootRect = dropdownRoot.getBoundingClientRect();
|
|
11
|
+
const drawerRect = drawerPanel?.getBoundingClientRect?.();
|
|
12
|
+
const contentRect = content?.getBoundingClientRect?.();
|
|
13
|
+
const contentWidth = contentRect?.width || 224;
|
|
14
|
+
// const contentHeight = contentRect?.height || 240;
|
|
15
|
+
const gap = 6;
|
|
16
|
+
|
|
17
|
+
const viewportRect = {
|
|
18
|
+
top: 0,
|
|
19
|
+
right: window.innerWidth,
|
|
20
|
+
bottom: window.innerHeight,
|
|
21
|
+
left: 0,
|
|
22
|
+
};
|
|
23
|
+
const boundaryRect = drawerRect ?? viewportRect;
|
|
24
|
+
const minLeft = boundaryRect.left - rootRect.left + gap;
|
|
25
|
+
const maxLeft = boundaryRect.right - rootRect.left - contentWidth - gap;
|
|
26
|
+
// const minTop = boundaryRect.top - rootRect.top + gap;
|
|
27
|
+
// const maxTop = boundaryRect.bottom - rootRect.top - contentHeight - gap;
|
|
28
|
+
|
|
29
|
+
const preferredLeft = triggerRect.left - rootRect.left - contentWidth - gap;
|
|
30
|
+
// const preferredTop = triggerRect.top - rootRect.top;
|
|
31
|
+
const left = clamp(preferredLeft, minLeft, Math.max(minLeft, maxLeft));
|
|
32
|
+
const top = 0; //clamp(preferredTop, minTop, Math.max(minTop, maxTop));
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
style: {
|
|
36
|
+
position: 'absolute',
|
|
37
|
+
left: `${left}px`,
|
|
38
|
+
top: `${top}px`,
|
|
39
|
+
marginTop: '0px',
|
|
40
|
+
zIndex: '10000',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function clamp(value, min, max) {
|
|
46
|
+
return Math.min(Math.max(value, min), max);
|
|
47
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import getModelName from '@fleetbase/ember-core/utils/get-model-name';
|
|
2
|
+
import { isArray } from '@ember/array';
|
|
3
|
+
import { get } from '@ember/object';
|
|
4
|
+
|
|
5
|
+
export function buildTrackableOption(resource, modelName = getTrackableModelName(resource)) {
|
|
6
|
+
const deviceLabel = trackableDeviceLabel(resource, modelName);
|
|
7
|
+
const secondaryLabel = trackableSecondaryLabel(resource, modelName);
|
|
8
|
+
const primaryLabel = getValue(resource, 'name') ?? getValue(resource, 'displayName') ?? getValue(resource, 'display_name') ?? getValue(resource, 'public_id');
|
|
9
|
+
const trackableSearchText = [
|
|
10
|
+
primaryLabel,
|
|
11
|
+
secondaryLabel,
|
|
12
|
+
getValue(resource, 'public_id'),
|
|
13
|
+
getValue(resource, 'internal_id'),
|
|
14
|
+
getValue(resource, 'serial_number'),
|
|
15
|
+
getValue(resource, 'plate_number'),
|
|
16
|
+
getValue(resource, 'email'),
|
|
17
|
+
getValue(resource, 'vin'),
|
|
18
|
+
getValue(resource, 'call_sign'),
|
|
19
|
+
deviceLabel,
|
|
20
|
+
]
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.join(' ');
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
resource,
|
|
26
|
+
modelName,
|
|
27
|
+
primaryLabel,
|
|
28
|
+
secondaryLabel,
|
|
29
|
+
deviceLabel,
|
|
30
|
+
trackableSearchText,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function trackableSecondaryLabel(resource, modelName = getTrackableModelName(resource)) {
|
|
35
|
+
if (modelName === 'driver') {
|
|
36
|
+
return getValue(resource, 'email') ?? getValue(resource, 'phone') ?? getValue(resource, 'vehicle_name') ?? getValue(resource, 'internal_id') ?? getValue(resource, 'public_id');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return getValue(resource, 'plate_number') ?? getValue(resource, 'serial_number') ?? getValue(resource, 'internal_id') ?? getValue(resource, 'vin') ?? getValue(resource, 'public_id');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function trackableDeviceLabel(resource, modelName = getTrackableModelName(resource)) {
|
|
43
|
+
const devices = trackableDevices(resource, modelName);
|
|
44
|
+
const labels = devices.map(deviceLabel).filter(Boolean);
|
|
45
|
+
|
|
46
|
+
if (labels.length === 0) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return labels.length === 1 ? `Device: ${labels[0]}` : `Devices: ${labels.join(', ')}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function trackableDevices(resource, modelName = getTrackableModelName(resource)) {
|
|
54
|
+
const devices = modelName === 'driver' ? getValue(resource, 'vehicle.devices') : getValue(resource, 'devices');
|
|
55
|
+
|
|
56
|
+
if (!devices) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isArray(devices)) {
|
|
61
|
+
return devices;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (typeof devices.toArray === 'function') {
|
|
65
|
+
return devices.toArray();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function deviceLabel(device) {
|
|
72
|
+
return (
|
|
73
|
+
getValue(device, 'displayName') ??
|
|
74
|
+
getValue(device, 'display_name') ??
|
|
75
|
+
getValue(device, 'name') ??
|
|
76
|
+
getValue(device, 'device_id') ??
|
|
77
|
+
getValue(device, 'serial_number') ??
|
|
78
|
+
getValue(device, 'imei') ??
|
|
79
|
+
getValue(device, 'public_id')
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getTrackableModelName(resource) {
|
|
84
|
+
return getModelName(resource) ?? getValue(resource, 'modelName') ?? resource?.constructor?.modelName;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getValue(object, path) {
|
|
88
|
+
if (!object) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return get(object, path);
|
|
93
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/cell/attached-vehicle';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/cell/device-identity';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/cell/driver-identity';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/cell/equipment-identity';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/cell/part-identity';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/cell/telematic-device';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/cell/vehicle-identity';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<div class="flex flex-col gap-3 p-3" ...attributes>
|
|
2
|
+
<div class="flex items-start justify-between gap-3">
|
|
3
|
+
<div class="min-w-0">
|
|
4
|
+
<h2 class="text-base font-bold text-gray-900 dark:text-gray-100">Telemetry Events</h2>
|
|
5
|
+
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-300">Recent device events, warning signals, and processing state.</p>
|
|
6
|
+
</div>
|
|
7
|
+
<Button @icon="refresh" @size="xs" @onClick={{this.refreshEvents}} @isLoading={{this.loadEvents.isRunning}} />
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<Layout::Resource::Tabular
|
|
11
|
+
@resource="device-event"
|
|
12
|
+
@title="Telemetry Events"
|
|
13
|
+
@data={{this.events}}
|
|
14
|
+
@columns={{this.columns}}
|
|
15
|
+
@controller={{this}}
|
|
16
|
+
@pagination={{false}}
|
|
17
|
+
@withoutHeader={{true}}
|
|
18
|
+
@tableWrapperClass="no-table-extra-spacing"
|
|
19
|
+
@emptyStateComponent={{component
|
|
20
|
+
"table/empty-state"
|
|
21
|
+
variant="compact"
|
|
22
|
+
icon="bolt"
|
|
23
|
+
title="No telemetry events"
|
|
24
|
+
description="Events appear after this device reports provider activity."
|
|
25
|
+
primaryText="Refresh"
|
|
26
|
+
primaryIcon="refresh"
|
|
27
|
+
primaryAction=this.refreshEvents
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
</div>
|