@fleetbase/fleetops-engine 0.6.63 → 0.6.65
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/RELEASE.md +7 -6
- package/addon/components/attachment-list.hbs +65 -0
- package/addon/components/attachment-list.js +8 -0
- package/addon/components/cell/attached-vehicle.hbs +1 -1
- package/addon/components/cell/attached-vehicle.js +3 -3
- package/addon/components/cell/driver-identity.js +4 -4
- package/addon/components/cell/driver-name.hbs +1 -1
- package/addon/components/cell/translated-value.hbs +9 -0
- package/addon/components/cell/translated-value.js +57 -0
- package/addon/components/contact/card.hbs +58 -0
- package/addon/components/contact/card.js +19 -0
- package/addon/components/contact/form.hbs +1 -1
- package/addon/components/contact/panel-header.hbs +1 -1
- package/addon/components/customer/form.hbs +2 -2
- package/addon/components/device/manager.hbs +26 -28
- package/addon/components/device/manager.js +28 -2
- package/addon/components/device/panel-tabs/vehicle.hbs +13 -13
- package/addon/components/device/panel-tabs/vehicle.js +8 -0
- package/addon/components/driver/card.hbs +24 -13
- package/addon/components/driver/card.js +20 -6
- package/addon/components/driver/form.hbs +3 -3
- package/addon/components/driver/panel-header.hbs +2 -2
- package/addon/components/driver/pill.hbs +2 -2
- package/addon/components/equipment/form.js +11 -4
- package/addon/components/equipment/pill.hbs +20 -0
- package/addon/components/equipment/pill.js +3 -0
- package/addon/components/filter/multi-model.hbs +19 -0
- package/addon/components/filter/multi-model.js +90 -0
- package/addon/components/fleet/driver-listing.hbs +1 -1
- package/addon/components/fleet/vehicle-listing.hbs +1 -1
- package/addon/components/fleet-panel/driver-listing.hbs +1 -1
- package/addon/components/fleet-panel/vehicle-listing.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +9 -7
- package/addon/components/maintenance/form.js +12 -4
- package/addon/components/maintenance-schedule/form.js +13 -7
- package/addon/components/map/leaflet-live-map.hbs +52 -0
- package/addon/components/map/order-list-overlay/order.hbs +4 -4
- package/addon/components/modals/attach-equipment.hbs +22 -0
- package/addon/components/modals/attach-equipment.js +3 -0
- package/addon/components/modals/attach-telematic-device.hbs +13 -8
- package/addon/components/modals/attach-telematic-device.js +11 -1
- package/addon/components/modals/attach-trailer.hbs +30 -0
- package/addon/components/modals/attach-trailer.js +3 -0
- package/addon/components/modals/contact-form.hbs +2 -2
- package/addon/components/modals/convert-customer-to-vendor.hbs +1 -1
- package/addon/components/modals/driver-form.hbs +2 -2
- package/addon/components/modals/select-trailer.hbs +35 -0
- package/addon/components/modals/select-trailer.js +3 -0
- package/addon/components/modals/vehicle-form.hbs +2 -2
- package/addon/components/orchestrator/resource-panel.hbs +2 -2
- package/addon/components/order/customer-avatar-stack.hbs +2 -2
- package/addon/components/order/details/detail.hbs +4 -4
- package/addon/components/order/details/payload.hbs +2 -2
- package/addon/components/order/kanban-card.hbs +4 -4
- package/addon/components/order-list-overlay/order.hbs +4 -4
- package/addon/components/trailer/card.hbs +68 -0
- package/addon/components/trailer/card.js +22 -0
- package/addon/components/trailer/details/connections.hbs +57 -0
- package/addon/components/trailer/details/connections.js +59 -0
- package/addon/components/trailer/details/equipment.hbs +25 -0
- package/addon/components/trailer/details/equipment.js +52 -0
- package/addon/components/trailer/details/maintenance-history.hbs +47 -0
- package/addon/components/trailer/details/maintenance-history.js +40 -0
- package/addon/components/trailer/details/schedules.hbs +45 -0
- package/addon/components/trailer/details/schedules.js +40 -0
- package/addon/components/trailer/details/work-orders.hbs +47 -0
- package/addon/components/trailer/details/work-orders.js +40 -0
- package/addon/components/trailer/details.hbs +399 -0
- package/addon/components/trailer/details.js +118 -0
- package/addon/components/trailer/form.hbs +447 -0
- package/addon/components/trailer/form.js +165 -0
- package/addon/components/trailer/panel-header.hbs +45 -0
- package/addon/components/trailer/panel-header.js +3 -0
- package/addon/components/trailer/pill.hbs +21 -0
- package/addon/components/trailer/pill.js +3 -0
- package/addon/components/vehicle/card.hbs +42 -11
- package/addon/components/vehicle/card.js +31 -0
- package/addon/components/vehicle/details/equipment.hbs +25 -0
- package/addon/components/vehicle/details/equipment.js +55 -0
- package/addon/components/vehicle/details/trailers.hbs +35 -0
- package/addon/components/vehicle/details/trailers.js +55 -0
- package/addon/components/vehicle/form.hbs +2 -2
- package/addon/components/vehicle/panel-header.hbs +2 -2
- package/addon/components/vehicle/pill.hbs +2 -2
- package/addon/components/vendor/card.hbs +58 -0
- package/addon/components/vendor/card.js +6 -0
- package/addon/components/vendor/panel-header.hbs +2 -2
- package/addon/components/vendor/personnel-manager.hbs +2 -2
- package/addon/components/work-order/form.js +12 -4
- package/addon/controllers/connectivity/devices/index/details/vehicle.js +11 -0
- package/addon/controllers/connectivity/devices/index/details.js +3 -3
- package/addon/controllers/connectivity/devices/index.js +1 -0
- package/addon/controllers/connectivity/telematics/details/attachments.js +28 -47
- package/addon/controllers/connectivity/telematics/details/devices.js +1 -0
- package/addon/controllers/management/contacts/customers.js +4 -0
- package/addon/controllers/management/contacts/index.js +32 -0
- package/addon/controllers/management/trailers/index/details.js +119 -0
- package/addon/controllers/management/trailers/index/edit.js +67 -0
- package/addon/controllers/management/trailers/index/new.js +43 -0
- package/addon/controllers/management/trailers/index.js +599 -0
- package/addon/controllers/management/vehicles/index/details.js +16 -0
- package/addon/controllers/management/vehicles/index.js +78 -4
- package/addon/controllers/management/vendors/index.js +32 -0
- package/addon/controllers/operations/orders/index.js +3 -1
- package/addon/controllers/settings/custom-fields.js +8 -0
- package/addon/extension.js +7 -0
- package/addon/helpers/placeholder-image.js +6 -0
- package/addon/helpers/resource-image.js +10 -0
- package/addon/helpers/trailer-placeholder-image.js +6 -0
- package/addon/routes/management/trailers/index/details/connections.js +2 -0
- package/addon/routes/management/trailers/index/details/devices.js +2 -0
- package/addon/routes/management/trailers/index/details/equipment.js +2 -0
- package/addon/routes/management/trailers/index/details/index.js +2 -0
- package/addon/routes/management/trailers/index/details/maintenance-history.js +2 -0
- package/addon/routes/management/trailers/index/details/positions.js +2 -0
- package/addon/routes/management/trailers/index/details/schedules.js +2 -0
- package/addon/routes/management/trailers/index/details/work-orders.js +2 -0
- package/addon/routes/management/trailers/index/details.js +30 -0
- package/addon/routes/management/trailers/index/edit.js +23 -0
- package/addon/routes/management/trailers/index/new.js +14 -0
- package/addon/routes/management/trailers/index.js +42 -0
- package/addon/routes/management/vehicles/index/details/trailers.js +2 -0
- package/addon/routes/management/vehicles/index.js +7 -1
- package/addon/routes.js +17 -0
- package/addon/services/device-actions.js +26 -16
- package/addon/services/trailer-actions.js +394 -0
- package/addon/services/vehicle-actions.js +111 -0
- package/addon/styles/fleetops-engine.css +349 -0
- package/addon/templates/connectivity/devices/index/details/vehicle.hbs +19 -19
- package/addon/templates/connectivity/telematics/details/attachments.hbs +15 -15
- package/addon/templates/management/contacts/customers.hbs +48 -29
- package/addon/templates/management/contacts/index.hbs +52 -33
- package/addon/templates/management/trailers/index/details/connections.hbs +1 -0
- package/addon/templates/management/trailers/index/details/devices.hbs +1 -0
- package/addon/templates/management/trailers/index/details/equipment.hbs +1 -0
- package/addon/templates/management/trailers/index/details/index.hbs +1 -0
- package/addon/templates/management/trailers/index/details/maintenance-history.hbs +1 -0
- package/addon/templates/management/trailers/index/details/positions.hbs +1 -0
- package/addon/templates/management/trailers/index/details/schedules.hbs +1 -0
- package/addon/templates/management/trailers/index/details/work-orders.hbs +1 -0
- package/addon/templates/management/trailers/index/details.hbs +15 -0
- package/addon/templates/management/trailers/index/edit.hbs +12 -0
- package/addon/templates/management/trailers/index/new.hbs +11 -0
- package/addon/templates/management/trailers/index.hbs +67 -0
- package/addon/templates/management/vehicles/index/details/equipment.hbs +1 -1
- package/addon/templates/management/vehicles/index/details/trailers.hbs +1 -0
- package/addon/templates/management/vehicles/index/details.hbs +1 -1
- package/addon/templates/management/vendors/index.hbs +66 -32
- package/addon/utils/device-table-columns.js +10 -6
- package/addon/utils/live-map-card-content.js +56 -0
- package/addon/utils/placeholder-images.js +71 -0
- package/addon/utils/trailer-placeholder-image.js +11 -0
- package/app/components/attachment-list.js +1 -0
- package/app/components/cell/translated-value.js +1 -0
- package/app/components/contact/card.js +1 -0
- package/app/components/equipment/pill.js +1 -0
- package/app/components/filter/multi-model.js +1 -0
- package/app/components/modals/attach-equipment.js +1 -0
- package/app/components/modals/attach-trailer.js +1 -0
- package/app/components/modals/select-trailer.js +1 -0
- package/app/components/trailer/card.js +1 -0
- package/app/components/trailer/details/connections.js +1 -0
- package/app/components/trailer/details/equipment.js +1 -0
- package/app/components/trailer/details/maintenance-history.js +1 -0
- package/app/components/trailer/details/schedules.js +1 -0
- package/app/components/trailer/details/work-orders.js +1 -0
- package/app/components/trailer/details.js +1 -0
- package/app/components/trailer/form.js +1 -0
- package/app/components/trailer/panel-header.js +1 -0
- package/app/components/trailer/pill.js +1 -0
- package/app/components/vehicle/details/equipment.js +1 -0
- package/app/components/vehicle/details/trailers.js +1 -0
- package/app/components/vendor/card.js +1 -0
- package/app/controllers/management/trailers/index/details.js +1 -0
- package/app/controllers/management/trailers/index/edit.js +1 -0
- package/app/controllers/management/trailers/index/new.js +1 -0
- package/app/controllers/management/trailers/index.js +1 -0
- package/app/helpers/placeholder-image.js +1 -0
- package/app/helpers/resource-image.js +1 -0
- package/app/helpers/trailer-placeholder-image.js +1 -0
- package/app/routes/management/trailers/index/details/connections.js +1 -0
- package/app/routes/management/trailers/index/details/devices.js +1 -0
- package/app/routes/management/trailers/index/details/equipment.js +1 -0
- package/app/routes/management/trailers/index/details/index.js +1 -0
- package/app/routes/management/trailers/index/details/maintenance-history.js +1 -0
- package/app/routes/management/trailers/index/details/positions.js +1 -0
- package/app/routes/management/trailers/index/details/schedules.js +1 -0
- package/app/routes/management/trailers/index/details/work-orders.js +1 -0
- package/app/routes/management/trailers/index/details.js +1 -0
- package/app/routes/management/trailers/index/edit.js +1 -0
- package/app/routes/management/trailers/index/new.js +1 -0
- package/app/routes/management/trailers/index.js +1 -0
- package/app/routes/management/vehicles/index/details/trailers.js +1 -0
- package/app/services/trailer-actions.js +1 -0
- package/app/templates/management/trailers/index/details/connections.js +1 -0
- package/app/templates/management/trailers/index/details/devices.js +1 -0
- package/app/templates/management/trailers/index/details/equipment.js +1 -0
- package/app/templates/management/trailers/index/details/index.js +1 -0
- package/app/templates/management/trailers/index/details/maintenance-history.js +1 -0
- package/app/templates/management/trailers/index/details/positions.js +1 -0
- package/app/templates/management/trailers/index/details/schedules.js +1 -0
- package/app/templates/management/trailers/index/details/work-orders.js +1 -0
- package/app/templates/management/trailers/index/details.js +1 -0
- package/app/templates/management/trailers/index/edit.js +1 -0
- package/app/templates/management/trailers/index/new.js +1 -0
- package/app/templates/management/trailers/index.js +1 -0
- package/app/templates/management/vehicles/index/details/trailers.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/migrations/2026_09_03_000001_add_first_class_trailer_columns_to_assets_table.php +58 -0
- package/server/migrations/2026_09_03_000002_create_asset_connections_table.php +43 -0
- package/server/migrations/2026_09_03_000003_create_device_installations_table.php +33 -0
- package/server/src/Auth/Schemas/FleetOps.php +7 -0
- package/server/src/Events/TrailerLocationChanged.php +70 -0
- package/server/src/Exceptions/DeviceAlreadyAttachedException.php +18 -0
- package/server/src/Exports/TrailerExport.php +31 -0
- package/server/src/Http/Controllers/Api/v1/Concerns/ResolvesFleetOpsApiResources.php +8 -2
- package/server/src/Http/Controllers/Api/v1/DeviceController.php +22 -15
- package/server/src/Http/Controllers/Api/v1/EquipmentController.php +47 -0
- package/server/src/Http/Controllers/Api/v1/TrailerController.php +362 -0
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +1 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +3 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/SearchController.php +16 -0
- package/server/src/Http/Controllers/Internal/v1/TrailerController.php +360 -0
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +74 -0
- package/server/src/Http/Filter/EquipmentFilter.php +51 -0
- package/server/src/Http/Filter/OrderFilter.php +15 -0
- package/server/src/Http/Filter/TrailerFilter.php +269 -0
- package/server/src/Http/Filter/VehicleFilter.php +70 -3
- package/server/src/Http/Requests/CreateDeviceRequest.php +1 -1
- package/server/src/Http/Requests/CreateEquipmentRequest.php +1 -1
- package/server/src/Http/Requests/CreateTrailerRequest.php +54 -0
- package/server/src/Http/Requests/UpdateTrailerRequest.php +7 -0
- package/server/src/Http/Resources/v1/AssetConnection.php +90 -0
- package/server/src/Http/Resources/v1/Concerns/ResolvesPublicRelationFields.php +29 -3
- package/server/src/Http/Resources/v1/Device.php +3 -1
- package/server/src/Http/Resources/v1/Equipment.php +3 -1
- package/server/src/Http/Resources/v1/Fleet.php +3 -1
- package/server/src/Http/Resources/v1/Index/Vehicle.php +10 -0
- package/server/src/Http/Resources/v1/Trailer.php +199 -0
- package/server/src/Http/Resources/v1/Vehicle.php +2 -0
- package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +3 -0
- package/server/src/Imports/TrailerImport.php +33 -0
- package/server/src/Models/Asset.php +39 -10
- package/server/src/Models/AssetConnection.php +43 -0
- package/server/src/Models/Device.php +39 -8
- package/server/src/Models/DeviceInstallation.php +27 -0
- package/server/src/Models/Equipment.php +2 -0
- package/server/src/Models/Trailer.php +181 -0
- package/server/src/Models/Vehicle.php +13 -0
- package/server/src/Providers/FleetOpsServiceProvider.php +4 -2
- package/server/src/Support/Ai/FleetOpsAiQueryResources.php +22 -0
- package/server/src/Support/Reporting/FleetOpsReportSchema.php +38 -0
- package/server/src/Support/Telematics/TelematicService.php +35 -0
- package/server/src/Support/TrailerSummary.php +35 -0
- package/server/src/routes.php +29 -0
- package/server/tests/CompactResourceSerializationTest.php +36 -0
- package/server/tests/ControllerFilterContractsTest.php +29 -0
- package/server/tests/Feature/Http/Api/DeviceControllerContractsTest.php +30 -13
- package/server/tests/Feature/Http/Api/TrailerControllerLifecycleTest.php +640 -0
- package/server/tests/Feature/Http/Api/VehiclePublicContractTest.php +23 -0
- package/server/tests/Feature/Http/Internal/DeviceControllerContractsTest.php +20 -5
- package/server/tests/Feature/Http/Internal/LiveControllerEndpointsTest.php +19 -0
- package/server/tests/ModelAccessorContractsTest.php +10 -0
- package/server/tests/OrderFilterExecutionTest.php +5 -0
- package/server/tests/PublicApiControllerInputContractsTest.php +11 -0
- package/server/tests/PublicFleetOpsRestEndpointsTest.php +15 -3
- package/server/tests/ReportSchemaContractsTest.php +4 -0
- package/server/tests/TelematicsHardeningTest.php +4 -2
- package/server/tests/TrailerSupportCoverageTest.php +524 -0
- package/server/tests/Unit/Http/Resources/FleetResourceTest.php +17 -0
- package/server/tests/Unit/Http/Resources/IndexVehicleResourceTest.php +35 -0
- package/server/tests/Unit/Models/EquipmentTest.php +22 -0
- package/server/tests/Unit/Models/ModelLookupFallbackSeamsTest.php +7 -3
- package/server/tests/Unit/Models/TrailerTest.php +204 -0
- package/server/tests/Unit/Support/Telematics/TelematicServiceTelemetryTest.php +93 -0
- package/server/tests/VehicleControllerHelperContractsTest.php +14 -0
- package/server/tests/VehicleResourceContractsTest.php +39 -0
- package/translations/ar-ae.yml +396 -0
- package/translations/bg-bg.yaml +424 -0
- package/translations/en-us.yaml +423 -0
- package/translations/es-pa.yaml +425 -0
- package/translations/fr-fr.yaml +424 -0
- package/translations/mn-mn.yaml +424 -0
- package/translations/pt-br.yaml +424 -0
- package/translations/ru-ru.yaml +424 -0
- package/translations/vi-vn.yaml +435 -0
|
@@ -29,6 +29,11 @@ export default class ManagementVehiclesIndexController extends Controller {
|
|
|
29
29
|
'vehicle_make',
|
|
30
30
|
'vehicle_model',
|
|
31
31
|
'display_name',
|
|
32
|
+
'trailer',
|
|
33
|
+
'device',
|
|
34
|
+
'has_trailer',
|
|
35
|
+
'has_driver',
|
|
36
|
+
'has_device',
|
|
32
37
|
];
|
|
33
38
|
@tracked query = null;
|
|
34
39
|
@tracked page = 1;
|
|
@@ -45,6 +50,11 @@ export default class ManagementVehiclesIndexController extends Controller {
|
|
|
45
50
|
@tracked fleet;
|
|
46
51
|
@tracked vendor;
|
|
47
52
|
@tracked driver;
|
|
53
|
+
@tracked trailer;
|
|
54
|
+
@tracked device;
|
|
55
|
+
@tracked has_trailer;
|
|
56
|
+
@tracked has_driver;
|
|
57
|
+
@tracked has_device;
|
|
48
58
|
@tracked display_name;
|
|
49
59
|
@tracked table;
|
|
50
60
|
@tracked layout = this.appCache.get('fleetops:vehicles:layout', 'table');
|
|
@@ -118,6 +128,17 @@ export default class ManagementVehiclesIndexController extends Controller {
|
|
|
118
128
|
];
|
|
119
129
|
}
|
|
120
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Yes/no choices for the "has trailer / driver / device" filters. `kind` picks the
|
|
133
|
+
* wording: assets are attached, drivers are assigned.
|
|
134
|
+
*/
|
|
135
|
+
presenceOptions(kind) {
|
|
136
|
+
return [
|
|
137
|
+
{ value: 'true', label: this.intl.t(`vehicle.filters.${kind}`) },
|
|
138
|
+
{ value: 'false', label: this.intl.t(`vehicle.filters.not-${kind}`) },
|
|
139
|
+
];
|
|
140
|
+
}
|
|
141
|
+
|
|
121
142
|
/** columns */
|
|
122
143
|
get columns() {
|
|
123
144
|
return [
|
|
@@ -157,7 +178,8 @@ export default class ManagementVehiclesIndexController extends Controller {
|
|
|
157
178
|
sortable: true,
|
|
158
179
|
filterable: true,
|
|
159
180
|
hidden: true,
|
|
160
|
-
filterComponent: 'filter/
|
|
181
|
+
filterComponent: 'filter/multi-input',
|
|
182
|
+
filterComponentPlaceholder: this.intl.t('vehicle.placeholders.filter-internal-id'),
|
|
161
183
|
filterParam: 'internal_id',
|
|
162
184
|
},
|
|
163
185
|
{
|
|
@@ -197,11 +219,63 @@ export default class ManagementVehiclesIndexController extends Controller {
|
|
|
197
219
|
},
|
|
198
220
|
resizable: true,
|
|
199
221
|
filterable: true,
|
|
200
|
-
filterComponent: 'filter/model',
|
|
201
|
-
filterComponentPlaceholder: '
|
|
222
|
+
filterComponent: 'filter/multi-model',
|
|
223
|
+
filterComponentPlaceholder: this.intl.t('common.select-resource-filter-by', { resource: this.intl.t('resource.driver') }),
|
|
202
224
|
filterParam: 'driver',
|
|
203
225
|
model: 'driver',
|
|
204
226
|
},
|
|
227
|
+
{
|
|
228
|
+
label: this.intl.t('resource.trailers'),
|
|
229
|
+
valuePath: 'trailers',
|
|
230
|
+
hidden: true,
|
|
231
|
+
filterable: true,
|
|
232
|
+
filterComponent: 'filter/multi-model',
|
|
233
|
+
filterComponentPlaceholder: this.intl.t('common.select-resource-filter-by', { resource: this.intl.t('resource.trailer') }),
|
|
234
|
+
filterParam: 'trailer',
|
|
235
|
+
model: 'trailer',
|
|
236
|
+
modelNamePath: 'displayName',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
label: this.intl.t('resource.devices'),
|
|
240
|
+
valuePath: 'devices',
|
|
241
|
+
hidden: true,
|
|
242
|
+
filterable: true,
|
|
243
|
+
filterComponent: 'filter/multi-model',
|
|
244
|
+
filterComponentPlaceholder: this.intl.t('common.select-resource-filter-by', { resource: this.intl.t('resource.device') }),
|
|
245
|
+
filterParam: 'device',
|
|
246
|
+
model: 'device',
|
|
247
|
+
modelNamePath: 'displayName',
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
label: this.intl.t('vehicle.filters.has-trailer'),
|
|
251
|
+
valuePath: 'has_trailer',
|
|
252
|
+
hidden: true,
|
|
253
|
+
filterable: true,
|
|
254
|
+
filterComponent: 'filter/select',
|
|
255
|
+
filterComponentPlaceholder: this.intl.t('vehicle.filters.any'),
|
|
256
|
+
filterOptions: this.presenceOptions('attached'),
|
|
257
|
+
filterParam: 'has_trailer',
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
label: this.intl.t('vehicle.filters.has-driver'),
|
|
261
|
+
valuePath: 'has_driver',
|
|
262
|
+
hidden: true,
|
|
263
|
+
filterable: true,
|
|
264
|
+
filterComponent: 'filter/select',
|
|
265
|
+
filterComponentPlaceholder: this.intl.t('vehicle.filters.any'),
|
|
266
|
+
filterOptions: this.presenceOptions('assigned'),
|
|
267
|
+
filterParam: 'has_driver',
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
label: this.intl.t('vehicle.filters.has-device'),
|
|
271
|
+
valuePath: 'has_device',
|
|
272
|
+
hidden: true,
|
|
273
|
+
filterable: true,
|
|
274
|
+
filterComponent: 'filter/select',
|
|
275
|
+
filterComponentPlaceholder: this.intl.t('vehicle.filters.any'),
|
|
276
|
+
filterOptions: this.presenceOptions('attached'),
|
|
277
|
+
filterParam: 'has_device',
|
|
278
|
+
},
|
|
205
279
|
{
|
|
206
280
|
label: this.intl.t('column.id'),
|
|
207
281
|
valuePath: 'public_id',
|
|
@@ -257,7 +331,7 @@ export default class ManagementVehiclesIndexController extends Controller {
|
|
|
257
331
|
resizable: true,
|
|
258
332
|
filterable: true,
|
|
259
333
|
filterComponent: 'filter/model',
|
|
260
|
-
filterComponentPlaceholder: this.intl.t('select-resource-filter-by', { resource: this.intl.t('resource.vendor') }),
|
|
334
|
+
filterComponentPlaceholder: this.intl.t('common.select-resource-filter-by', { resource: this.intl.t('resource.vendor') }),
|
|
261
335
|
filterParam: 'vendor',
|
|
262
336
|
model: 'vendor',
|
|
263
337
|
},
|
|
@@ -1,12 +1,14 @@
|
|
|
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 { action } from '@ember/object';
|
|
4
5
|
import fleetOpsOptions from '../../../utils/fleet-ops-options';
|
|
5
6
|
|
|
6
7
|
export default class ManagementVendorsIndexController extends Controller {
|
|
7
8
|
@service vendorActions;
|
|
8
9
|
@service tableContext;
|
|
9
10
|
@service intl;
|
|
11
|
+
@service appCache;
|
|
10
12
|
|
|
11
13
|
/** query params */
|
|
12
14
|
@tracked queryParams = [
|
|
@@ -40,10 +42,35 @@ export default class ManagementVendorsIndexController extends Controller {
|
|
|
40
42
|
@tracked email;
|
|
41
43
|
@tracked country;
|
|
42
44
|
@tracked table;
|
|
45
|
+
@tracked layout = this.appCache.get(this.layoutCacheKey, 'table');
|
|
46
|
+
|
|
47
|
+
/** cache key that remembers the chosen layout per listing */
|
|
48
|
+
get layoutCacheKey() {
|
|
49
|
+
return 'fleetops:vendors:layout';
|
|
50
|
+
}
|
|
43
51
|
|
|
44
52
|
/** action buttons */
|
|
45
53
|
get actionButtons() {
|
|
46
54
|
return [
|
|
55
|
+
{
|
|
56
|
+
component: 'dropdown-button',
|
|
57
|
+
icon: 'display',
|
|
58
|
+
size: 'xs',
|
|
59
|
+
items: [
|
|
60
|
+
{
|
|
61
|
+
label: this.intl.t('common.table-view'),
|
|
62
|
+
icon: 'table-list',
|
|
63
|
+
onClick: () => this.setLayout('table'),
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
label: this.intl.t('common.grid-view'),
|
|
67
|
+
icon: 'grip',
|
|
68
|
+
onClick: () => this.setLayout('grid'),
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
renderInPlace: true,
|
|
72
|
+
helpText: this.intl.t('common.change-layout'),
|
|
73
|
+
},
|
|
47
74
|
{
|
|
48
75
|
icon: 'refresh',
|
|
49
76
|
onClick: this.vendorActions.refresh,
|
|
@@ -250,4 +277,9 @@ export default class ManagementVendorsIndexController extends Controller {
|
|
|
250
277
|
},
|
|
251
278
|
];
|
|
252
279
|
}
|
|
280
|
+
|
|
281
|
+
@action setLayout(layout) {
|
|
282
|
+
this.layout = layout;
|
|
283
|
+
this.appCache.set(this.layoutCacheKey, layout);
|
|
284
|
+
}
|
|
253
285
|
}
|
|
@@ -157,7 +157,9 @@ export default class OperationsOrdersIndexController extends Controller {
|
|
|
157
157
|
resizable: true,
|
|
158
158
|
sortable: true,
|
|
159
159
|
filterable: true,
|
|
160
|
-
|
|
160
|
+
// Batch scanning: each scanned or pasted id becomes a chip and all of them match.
|
|
161
|
+
filterComponent: 'filter/multi-input',
|
|
162
|
+
filterComponentPlaceholder: this.intl.t('order.placeholders.filter-internal-id'),
|
|
161
163
|
},
|
|
162
164
|
{
|
|
163
165
|
label: this.intl.t('column.payload'),
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import Controller from '@ember/controller';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
4
|
export default class SettingsCustomFieldsController extends Controller {
|
|
5
|
+
@service intl;
|
|
4
6
|
get subjects() {
|
|
5
7
|
return [
|
|
6
8
|
{
|
|
@@ -15,6 +17,12 @@ export default class SettingsCustomFieldsController extends Controller {
|
|
|
15
17
|
label: 'Vehicle',
|
|
16
18
|
groups: [],
|
|
17
19
|
},
|
|
20
|
+
{
|
|
21
|
+
model: 'trailer',
|
|
22
|
+
type: 'fleet-ops:trailer',
|
|
23
|
+
label: this.intl.t('resource.trailer'),
|
|
24
|
+
groups: [],
|
|
25
|
+
},
|
|
18
26
|
{
|
|
19
27
|
model: 'contact',
|
|
20
28
|
type: 'fleet-ops:contact',
|
package/addon/extension.js
CHANGED
|
@@ -5,6 +5,7 @@ export default {
|
|
|
5
5
|
const menuService = universe.getService('menu');
|
|
6
6
|
const registryService = universe.getService('registry');
|
|
7
7
|
const widgetService = universe.getService('widget');
|
|
8
|
+
const intlService = app.lookup('service:intl');
|
|
8
9
|
|
|
9
10
|
// Register header navigation
|
|
10
11
|
menuService.registerHeaderMenuItem('Fleet-Ops', 'console.fleet-ops', {
|
|
@@ -36,6 +37,12 @@ export default {
|
|
|
36
37
|
icon: 'truck',
|
|
37
38
|
route: 'console.fleet-ops.management.vehicles',
|
|
38
39
|
},
|
|
40
|
+
{
|
|
41
|
+
title: intlService.t('menu.trailers'),
|
|
42
|
+
description: intlService.t('trailer.navigation-description'),
|
|
43
|
+
icon: 'trailer',
|
|
44
|
+
route: 'console.fleet-ops.management.trailers',
|
|
45
|
+
},
|
|
39
46
|
{
|
|
40
47
|
title: 'Fleets',
|
|
41
48
|
description: 'Organise drivers and vehicles into operational fleets.',
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { helper } from '@ember/component/helper';
|
|
2
|
+
import { resolveResourceImage } from '../utils/placeholder-images';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `{{resource-image @resource.photo_url "driver"}}` — the record's photo, or the styled
|
|
6
|
+
* placeholder for its resource type when the photo is missing or a legacy default.
|
|
7
|
+
*/
|
|
8
|
+
export default helper(function resourceImage([url, type]) {
|
|
9
|
+
return resolveResourceImage(url, type);
|
|
10
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
|
|
5
|
+
export default class ManagementTrailersIndexDetailsRoute extends Route {
|
|
6
|
+
@service store;
|
|
7
|
+
@service notifications;
|
|
8
|
+
@service hostRouter;
|
|
9
|
+
@service abilities;
|
|
10
|
+
@service intl;
|
|
11
|
+
|
|
12
|
+
@action error(error) {
|
|
13
|
+
this.notifications.serverError(error);
|
|
14
|
+
if (typeof error?.message === 'string' && error.message.endsWith('not found')) {
|
|
15
|
+
return this.hostRouter.transitionTo('console.fleet-ops.management.trailers.index');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
beforeModel() {
|
|
20
|
+
if (this.abilities.cannot('fleet-ops view trailer')) {
|
|
21
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
22
|
+
return this.hostRouter.transitionTo('console.fleet-ops.management.trailers.index');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
model({ public_id }) {
|
|
27
|
+
// The details panel needs the towing state, so load the connection eagerly.
|
|
28
|
+
return this.store.queryRecord('trailer', { public_id, single: true, with: ['currentConnection.vehicle', 'category', 'vendor', 'warranty'] });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
export default class ManagementTrailersIndexEditRoute extends Route {
|
|
5
|
+
@service store;
|
|
6
|
+
@service notifications;
|
|
7
|
+
@service hostRouter;
|
|
8
|
+
@service abilities;
|
|
9
|
+
@service intl;
|
|
10
|
+
@action error(error) {
|
|
11
|
+
this.notifications.serverError(error);
|
|
12
|
+
return this.hostRouter.transitionTo('console.fleet-ops.management.trailers.index');
|
|
13
|
+
}
|
|
14
|
+
beforeModel() {
|
|
15
|
+
if (this.abilities.cannot('fleet-ops update trailer')) {
|
|
16
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
17
|
+
return this.hostRouter.transitionTo('console.fleet-ops.management.trailers.index');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
model({ public_id }) {
|
|
21
|
+
return this.store.findRecord('trailer', public_id);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
export default class ManagementTrailersIndexNewRoute extends Route {
|
|
4
|
+
@service notifications;
|
|
5
|
+
@service hostRouter;
|
|
6
|
+
@service abilities;
|
|
7
|
+
@service intl;
|
|
8
|
+
beforeModel() {
|
|
9
|
+
if (this.abilities.cannot('fleet-ops create trailer')) {
|
|
10
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
11
|
+
return this.hostRouter.transitionTo('console.fleet-ops.management.trailers.index');
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
|
|
4
|
+
export default class ManagementTrailersIndexRoute extends Route {
|
|
5
|
+
@service store;
|
|
6
|
+
|
|
7
|
+
queryParams = {
|
|
8
|
+
page: { refreshModel: true },
|
|
9
|
+
limit: { refreshModel: true },
|
|
10
|
+
sort: { refreshModel: true },
|
|
11
|
+
query: { refreshModel: true },
|
|
12
|
+
public_id: { refreshModel: true },
|
|
13
|
+
name: { refreshModel: true },
|
|
14
|
+
code: { refreshModel: true },
|
|
15
|
+
trailer_type: { refreshModel: true },
|
|
16
|
+
status: { refreshModel: true },
|
|
17
|
+
attachment_state: { refreshModel: true },
|
|
18
|
+
vehicle: { refreshModel: true },
|
|
19
|
+
connectivity_status: { refreshModel: true },
|
|
20
|
+
trailer_make: { refreshModel: true },
|
|
21
|
+
trailer_model: { refreshModel: true },
|
|
22
|
+
trailer_year: { refreshModel: true },
|
|
23
|
+
plate_number: { refreshModel: true },
|
|
24
|
+
vin: { refreshModel: true },
|
|
25
|
+
serial_number: { refreshModel: true },
|
|
26
|
+
vendor: { refreshModel: true },
|
|
27
|
+
ownership_type: { refreshModel: true },
|
|
28
|
+
refrigerated: { refreshModel: true },
|
|
29
|
+
device: { refreshModel: true },
|
|
30
|
+
last_online_at: { refreshModel: true },
|
|
31
|
+
created_at: { refreshModel: true },
|
|
32
|
+
updated_at: { refreshModel: true },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
model(params) {
|
|
36
|
+
// Only forward meaningful filters; blank query params would otherwise be sent as
|
|
37
|
+
// empty strings and coerced into no-op or mismatching backend filters.
|
|
38
|
+
const query = Object.fromEntries(Object.entries(params).filter(([, value]) => value !== undefined && value !== null && value !== ''));
|
|
39
|
+
|
|
40
|
+
return this.store.query('trailer', query);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -21,6 +21,11 @@ export default class ManagementVehiclesIndexRoute extends Route {
|
|
|
21
21
|
fleet: { refreshModel: true },
|
|
22
22
|
vendor: { refreshModel: true },
|
|
23
23
|
driver: { refreshModel: true },
|
|
24
|
+
trailer: { refreshModel: true },
|
|
25
|
+
device: { refreshModel: true },
|
|
26
|
+
has_trailer: { refreshModel: true },
|
|
27
|
+
has_driver: { refreshModel: true },
|
|
28
|
+
has_device: { refreshModel: true },
|
|
24
29
|
created_at: { refreshModel: true },
|
|
25
30
|
updated_at: { refreshModel: true },
|
|
26
31
|
'within[latitude]': { refreshModel: true, replace: true },
|
|
@@ -30,6 +35,7 @@ export default class ManagementVehiclesIndexRoute extends Route {
|
|
|
30
35
|
};
|
|
31
36
|
|
|
32
37
|
model(params) {
|
|
33
|
-
|
|
38
|
+
// Current trailers back the card view's towing line; the internal API camelizes `with`.
|
|
39
|
+
return this.store.query('vehicle', { ...params, with: ['currentTrailers'] });
|
|
34
40
|
}
|
|
35
41
|
}
|
package/addon/routes.js
CHANGED
|
@@ -86,6 +86,7 @@ export default buildRoutes(function () {
|
|
|
86
86
|
this.route('positions');
|
|
87
87
|
this.route('devices');
|
|
88
88
|
this.route('equipment');
|
|
89
|
+
this.route('trailers');
|
|
89
90
|
this.route('schedules');
|
|
90
91
|
this.route('work-orders');
|
|
91
92
|
this.route('maintenance-history');
|
|
@@ -94,6 +95,22 @@ export default buildRoutes(function () {
|
|
|
94
95
|
this.route('edit', { path: '/edit/:public_id' });
|
|
95
96
|
});
|
|
96
97
|
});
|
|
98
|
+
this.route('trailers', function () {
|
|
99
|
+
this.route('index', { path: '/' }, function () {
|
|
100
|
+
this.route('new');
|
|
101
|
+
this.route('details', { path: '/:public_id' }, function () {
|
|
102
|
+
this.route('index', { path: '/' });
|
|
103
|
+
this.route('positions');
|
|
104
|
+
this.route('devices');
|
|
105
|
+
this.route('equipment');
|
|
106
|
+
this.route('connections');
|
|
107
|
+
this.route('schedules');
|
|
108
|
+
this.route('work-orders');
|
|
109
|
+
this.route('maintenance-history');
|
|
110
|
+
});
|
|
111
|
+
this.route('edit', { path: '/edit/:public_id' });
|
|
112
|
+
});
|
|
113
|
+
});
|
|
97
114
|
this.route('places', function () {
|
|
98
115
|
this.route('index', { path: '/' }, function () {
|
|
99
116
|
this.route('new');
|
|
@@ -58,7 +58,7 @@ export default class DeviceActionsService extends ResourceActionService {
|
|
|
58
58
|
{
|
|
59
59
|
key: 'vehicle',
|
|
60
60
|
id: 'vehicle',
|
|
61
|
-
label: this.intl.t('
|
|
61
|
+
label: this.intl.t('device.attachment.asset'),
|
|
62
62
|
component: 'device/panel-tabs/vehicle',
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -112,26 +112,28 @@ export default class DeviceActionsService extends ResourceActionService {
|
|
|
112
112
|
},
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
-
@action
|
|
115
|
+
@action attachToAsset(device, options = {}) {
|
|
116
116
|
this.modalsManager.show('modals/attach-telematic-device', {
|
|
117
|
-
title: this.intl.t('device.prompts.attach-to-
|
|
118
|
-
acceptButtonText: this.intl.t('device.actions.attach-to-
|
|
117
|
+
title: this.intl.t('device.prompts.attach-to-asset-title'),
|
|
118
|
+
acceptButtonText: this.intl.t('device.actions.attach-to-asset'),
|
|
119
119
|
acceptButtonIcon: 'link',
|
|
120
120
|
device,
|
|
121
|
-
|
|
121
|
+
selectedAssetType: null,
|
|
122
|
+
selectedAsset: null,
|
|
122
123
|
confirm: async (modal) => {
|
|
123
|
-
const
|
|
124
|
+
const selectedAssetType = modal.getOption('selectedAssetType');
|
|
125
|
+
const selectedAsset = modal.getOption('selectedAsset');
|
|
124
126
|
|
|
125
|
-
if (!
|
|
126
|
-
return this.notifications.warning(this.intl.t('device.prompts.select-
|
|
127
|
+
if (!selectedAssetType || !selectedAsset) {
|
|
128
|
+
return this.notifications.warning(this.intl.t('device.prompts.select-asset-warning'));
|
|
127
129
|
}
|
|
128
130
|
|
|
129
131
|
modal.startLoading();
|
|
130
132
|
|
|
131
133
|
try {
|
|
132
|
-
await this.fetch.post(`devices/${device.id}/attach`, {
|
|
134
|
+
await this.fetch.post(`devices/${device.id}/attach`, { attachable_type: selectedAssetType.value, attachable: selectedAsset.id });
|
|
133
135
|
await device.reload?.();
|
|
134
|
-
this.notifications.success(this.intl.t('device.prompts.attach-to-
|
|
136
|
+
this.notifications.success(this.intl.t('device.prompts.attach-to-asset-success'));
|
|
135
137
|
modal.done();
|
|
136
138
|
this.refresh();
|
|
137
139
|
} catch (error) {
|
|
@@ -143,24 +145,28 @@ export default class DeviceActionsService extends ResourceActionService {
|
|
|
143
145
|
});
|
|
144
146
|
}
|
|
145
147
|
|
|
146
|
-
@action
|
|
148
|
+
@action attachToVehicle(device, options = {}) {
|
|
149
|
+
return this.attachToAsset(device, options);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@action detachFromAsset(device, options = {}) {
|
|
147
153
|
const deviceName = device.displayName ?? device.name ?? this.intl.t('resource.device');
|
|
148
|
-
const
|
|
154
|
+
const assetName = device.attached_to_name ?? device.attachable?.display_name ?? device.attachable?.name;
|
|
149
155
|
|
|
150
|
-
if (!device.attachable_uuid && !
|
|
156
|
+
if (!device.attachable_uuid && !assetName) {
|
|
151
157
|
return this.notifications.warning(this.intl.t('device.prompts.not-attached-warning', { deviceName }));
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
this.modalsManager.confirm({
|
|
155
|
-
title: this.intl.t('device.prompts.detach-from-
|
|
156
|
-
body: this.intl.t('device.prompts.detach-from-
|
|
161
|
+
title: this.intl.t('device.prompts.detach-from-asset-title', { deviceName }),
|
|
162
|
+
body: this.intl.t('device.prompts.detach-from-asset-body', { deviceName, assetName: assetName ?? this.intl.t('device.attachment.asset') }),
|
|
157
163
|
confirm: async (modal) => {
|
|
158
164
|
modal.startLoading();
|
|
159
165
|
|
|
160
166
|
try {
|
|
161
167
|
await this.fetch.post(`devices/${device.id}/detach`);
|
|
162
168
|
await device.reload?.();
|
|
163
|
-
this.notifications.success(this.intl.t('device.prompts.detach-from-
|
|
169
|
+
this.notifications.success(this.intl.t('device.prompts.detach-from-asset-success'));
|
|
164
170
|
modal.done();
|
|
165
171
|
this.refresh();
|
|
166
172
|
} catch (error) {
|
|
@@ -171,4 +177,8 @@ export default class DeviceActionsService extends ResourceActionService {
|
|
|
171
177
|
...options,
|
|
172
178
|
});
|
|
173
179
|
}
|
|
180
|
+
|
|
181
|
+
@action detachFromVehicle(device, options = {}) {
|
|
182
|
+
return this.detachFromAsset(device, options);
|
|
183
|
+
}
|
|
174
184
|
}
|