@fleetbase/fleetops-engine 0.6.54 → 0.6.56
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/map-settings.hbs +1 -1
- 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.js +1 -1
- package/addon/components/device/form.hbs +2 -2
- package/addon/components/device/form.js +7 -0
- package/addon/components/device/panel-header.hbs +45 -20
- 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/device-event/details.hbs +192 -0
- package/addon/components/device-event/details.js +151 -0
- package/addon/components/driver/schedule.js +1 -1
- package/addon/components/equipment/form.js +8 -1
- package/addon/components/layout/fleet-ops-sidebar.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +20 -6
- 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/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 +1 -1
- package/addon/components/telematic/form.hbs +2 -2
- package/addon/components/telematic/settings.hbs +1 -1
- package/addon/components/vendor/panel-header.hbs +82 -0
- package/addon/components/vendor/panel-header.js +48 -0
- package/addon/controllers/connectivity/devices/index/details/events.js +1 -1
- package/addon/controllers/connectivity/devices/index/details/vehicle.js +50 -2
- package/addon/controllers/connectivity/devices/index.js +144 -129
- package/addon/controllers/connectivity/events/details.js +70 -0
- package/addon/controllers/connectivity/events/index.js +187 -11
- package/addon/controllers/connectivity/sensors/index.js +160 -14
- package/addon/controllers/connectivity/telematics/details/devices.js +126 -134
- package/addon/controllers/connectivity/telematics/details/events.js +1 -1
- package/addon/controllers/connectivity/telematics/details/sensors.js +4 -0
- package/addon/controllers/maintenance/equipment/index.js +1 -2
- package/addon/controllers/maintenance/parts/index.js +1 -2
- 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/controllers/settings/map.js +15 -0
- package/addon/instance-initializers/register-vroom-allocation.js +1 -1
- package/addon/routes/connectivity/devices/index/details/vehicle.js +24 -2
- package/addon/routes/connectivity/devices/index.js +7 -0
- package/addon/routes/connectivity/events/details.js +28 -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/devices.js +2 -0
- package/addon/routes/management/vehicles/index/details.js +3 -1
- 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/map-adapter/google.js +25 -0
- package/addon/services/map-adapter/leaflet.js +1 -1
- package/addon/services/map-adapter-interface.js +1 -1
- package/addon/services/map-manager.js +4 -1
- package/addon/services/map-settings.js +15 -0
- package/addon/services/sensor-actions.js +3 -0
- package/addon/services/service-rate-actions.js +39 -1
- package/addon/services/vehicle-actions.js +24 -12
- package/addon/services/vendor-actions.js +3 -0
- package/addon/styles/fleetops-engine.css +9 -1
- package/addon/templates/connectivity/devices/index/details/vehicle.hbs +66 -2
- package/addon/templates/connectivity/events/details.hbs +40 -0
- package/addon/templates/management/vendors/index/details.hbs +2 -2
- package/addon/templates/settings/map.hbs +38 -9
- 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/identity-cell-resource.js +20 -0
- package/addon/utils/leaflet-plugin-loader.js +5 -5
- package/addon/utils/map-drawer-dropdown-position.js +47 -0
- package/addon/utils/route-colors.js +1 -1
- 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/device-event/details.hbs +192 -0
- package/app/components/device-event/details.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/events/{index/details.js → details.js} +1 -1
- package/app/routes/connectivity/events/{index/details.js → details.js} +1 -1
- 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/2026_06_23_000001_delete_bad_afaqy_telematics_sensors.php +34 -0
- package/server/src/Console/Commands/SyncTelematics.php +4 -4
- package/server/src/Exports/ContactExport.php +12 -5
- package/server/src/Exports/DeviceExport.php +92 -0
- package/server/src/Exports/DriverExport.php +28 -3
- package/server/src/Exports/EquipmentExport.php +94 -0
- package/server/src/Exports/FleetExport.php +22 -7
- package/server/src/Exports/FuelReportExport.php +16 -1
- package/server/src/Exports/IssueExport.php +25 -3
- package/server/src/Exports/MaintenanceExport.php +106 -0
- package/server/src/Exports/MaintenanceScheduleExport.php +99 -0
- package/server/src/Exports/OrderExport.php +24 -5
- package/server/src/Exports/PartExport.php +99 -0
- package/server/src/Exports/PlaceExport.php +33 -7
- package/server/src/Exports/SensorExport.php +94 -0
- package/server/src/Exports/ServiceAreaExport.php +31 -7
- package/server/src/Exports/ServiceRateExport.php +41 -1
- package/server/src/Exports/TelematicExport.php +90 -0
- package/server/src/Exports/VehicleExport.php +274 -8
- package/server/src/Exports/VendorExport.php +15 -2
- package/server/src/Exports/WorkOrderExport.php +92 -0
- package/server/src/Http/Controllers/Api/v1/Concerns/ResolvesFleetOpsApiResources.php +176 -0
- package/server/src/Http/Controllers/Api/v1/DeviceController.php +225 -0
- package/server/src/Http/Controllers/Api/v1/EquipmentController.php +114 -0
- package/server/src/Http/Controllers/Api/v1/FuelTransactionController.php +185 -0
- package/server/src/Http/Controllers/Api/v1/PartController.php +120 -0
- package/server/src/Http/Controllers/Api/v1/SensorController.php +132 -0
- package/server/src/Http/Controllers/Api/v1/WorkOrderController.php +161 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +36 -1
- package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +17 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +17 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +17 -0
- package/server/src/Http/Controllers/Internal/v1/PartController.php +17 -0
- package/server/src/Http/Controllers/Internal/v1/SensorController.php +18 -0
- package/server/src/Http/Controllers/Internal/v1/ServiceRateController.php +82 -13
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +29 -5
- package/server/src/Http/Controllers/Internal/v1/TelematicController.php +18 -0
- package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +17 -0
- package/server/src/Http/Filter/DeviceEventFilter.php +21 -0
- package/server/src/Http/Filter/DeviceFilter.php +50 -4
- package/server/src/Http/Filter/EquipmentFilter.php +23 -0
- package/server/src/Http/Filter/FuelProviderTransactionFilter.php +57 -2
- package/server/src/Http/Filter/PartFilter.php +47 -0
- package/server/src/Http/Filter/SensorFilter.php +34 -6
- package/server/src/Http/Filter/WorkOrderFilter.php +23 -0
- package/server/src/Http/Requests/CreateDeviceRequest.php +51 -0
- package/server/src/Http/Requests/CreateEquipmentRequest.php +35 -0
- package/server/src/Http/Requests/CreateFuelTransactionRequest.php +50 -0
- package/server/src/Http/Requests/CreatePartRequest.php +40 -0
- package/server/src/Http/Requests/CreateSensorRequest.php +47 -0
- package/server/src/Http/Requests/CreateWorkOrderRequest.php +42 -0
- package/server/src/Http/Requests/UpdateDeviceRequest.php +7 -0
- package/server/src/Http/Requests/UpdateEquipmentRequest.php +7 -0
- package/server/src/Http/Requests/UpdateFuelTransactionRequest.php +7 -0
- package/server/src/Http/Requests/UpdatePartRequest.php +7 -0
- package/server/src/Http/Requests/UpdateSensorRequest.php +7 -0
- package/server/src/Http/Requests/UpdateWorkOrderRequest.php +7 -0
- package/server/src/Http/Resources/v1/Device.php +72 -0
- package/server/src/Http/Resources/v1/Equipment.php +57 -0
- package/server/src/Http/Resources/v1/FuelTransaction.php +69 -0
- package/server/src/Http/Resources/v1/Index/Vehicle.php +19 -0
- package/server/src/Http/Resources/v1/Part.php +64 -0
- package/server/src/Http/Resources/v1/Sensor.php +68 -0
- package/server/src/Jobs/SyncTelematicDevicesJob.php +194 -38
- package/server/src/Models/Device.php +2 -0
- package/server/src/Models/DeviceEvent.php +81 -0
- package/server/src/Models/Equipment.php +55 -0
- package/server/src/Models/Order.php +2 -1
- package/server/src/Observers/PurchaseRateObserver.php +2 -1
- package/server/src/Support/Analytics/RevenueTrend.php +3 -8
- package/server/src/Support/Metrics/ActiveRevenueQuery.php +121 -0
- package/server/src/Support/Metrics/AvgOrderValueMetric.php +1 -7
- package/server/src/Support/Metrics/EarningsMetric.php +1 -10
- package/server/src/Support/Telematics/Providers/AfaqyProvider.php +105 -5
- 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 +567 -47
- package/server/src/Support/Telematics/Providers/SamsaraProvider.php +122 -14
- package/server/src/Support/Telematics/TelematicService.php +28 -9
- package/server/src/routes.php +67 -15
- package/server/tests/DeviceFilterTest.php +9 -0
- package/server/tests/DriverVehicleStatusDefaultTest.php +19 -2
- package/server/tests/EquipmentAssignmentMorphTypeTest.php +35 -0
- package/server/tests/ExportCoverageTest.php +79 -0
- package/server/tests/MetricsRegistryTest.php +45 -5
- package/server/tests/PublicFleetOpsRestEndpointsTest.php +191 -0
- package/server/tests/ServiceRateRouteValidationTest.php +101 -0
- package/server/tests/TelematicsHardeningTest.php +873 -7
- 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 +0 -1
|
@@ -66,6 +66,26 @@ export default class VehicleActionsService extends ResourceActionService {
|
|
|
66
66
|
this.initialize('vehicle', { status: 'available' });
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
async resolveVehicleResource(vehicle) {
|
|
70
|
+
if (typeof vehicle?.then === 'function') {
|
|
71
|
+
return await vehicle;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof vehicle?.loadResource === 'function') {
|
|
75
|
+
return (await vehicle.loadResource()) ?? vehicle;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return vehicle;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async reloadIndexResource(vehicle) {
|
|
82
|
+
if (vehicle?.meta?._index_resource) {
|
|
83
|
+
await vehicle.reload();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return vehicle;
|
|
87
|
+
}
|
|
88
|
+
|
|
69
89
|
transition = {
|
|
70
90
|
view: (vehicle) => this.transitionTo('management.vehicles.index.details', vehicle),
|
|
71
91
|
edit: (vehicle) => this.transitionTo('management.vehicles.index.edit', vehicle),
|
|
@@ -87,9 +107,7 @@ export default class VehicleActionsService extends ResourceActionService {
|
|
|
87
107
|
});
|
|
88
108
|
},
|
|
89
109
|
edit: async (vehicle, options = {}) => {
|
|
90
|
-
|
|
91
|
-
await vehicle.reload();
|
|
92
|
-
}
|
|
110
|
+
vehicle = await this.reloadIndexResource(await this.resolveVehicleResource(vehicle));
|
|
93
111
|
|
|
94
112
|
return this.resourceContextPanel.open({
|
|
95
113
|
content: 'vehicle/form',
|
|
@@ -109,9 +127,7 @@ export default class VehicleActionsService extends ResourceActionService {
|
|
|
109
127
|
});
|
|
110
128
|
},
|
|
111
129
|
view: async (vehicle, options = {}) => {
|
|
112
|
-
|
|
113
|
-
await vehicle.reload();
|
|
114
|
-
}
|
|
130
|
+
vehicle = await this.reloadIndexResource(await this.resolveVehicleResource(vehicle));
|
|
115
131
|
|
|
116
132
|
return this.resourceContextPanel.open({
|
|
117
133
|
vehicle,
|
|
@@ -144,9 +160,7 @@ export default class VehicleActionsService extends ResourceActionService {
|
|
|
144
160
|
});
|
|
145
161
|
},
|
|
146
162
|
edit: async (vehicle, options = {}, saveOptions = {}) => {
|
|
147
|
-
|
|
148
|
-
await vehicle.reload();
|
|
149
|
-
}
|
|
163
|
+
vehicle = await this.reloadIndexResource(await this.resolveVehicleResource(vehicle));
|
|
150
164
|
|
|
151
165
|
return this.modalsManager.show('modals/resource', {
|
|
152
166
|
resource: vehicle,
|
|
@@ -159,9 +173,7 @@ export default class VehicleActionsService extends ResourceActionService {
|
|
|
159
173
|
});
|
|
160
174
|
},
|
|
161
175
|
view: async (vehicle, options = {}) => {
|
|
162
|
-
|
|
163
|
-
await vehicle.reload();
|
|
164
|
-
}
|
|
176
|
+
vehicle = await this.reloadIndexResource(await this.resolveVehicleResource(vehicle));
|
|
165
177
|
|
|
166
178
|
return this.modalsManager.show('modals/resource', {
|
|
167
179
|
resource: vehicle,
|
|
@@ -43,8 +43,11 @@ export default class VendorActionsService extends ResourceActionService {
|
|
|
43
43
|
view: (vendor) => {
|
|
44
44
|
return this.resourceContextPanel.open({
|
|
45
45
|
vendor,
|
|
46
|
+
header: 'vendor/panel-header',
|
|
46
47
|
tabs: [
|
|
47
48
|
{
|
|
49
|
+
key: 'overview',
|
|
50
|
+
id: 'overview',
|
|
48
51
|
label: this.intl.t('common.overview'),
|
|
49
52
|
component: 'vendor/details',
|
|
50
53
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* stylelint-disable alpha-value-notation --
|
|
1
|
+
/* stylelint-disable alpha-value-notation -- Fleet-Ops lazy engine production CSS is minified by legacy clean-css, which corrupts comma-form rgba() percent alpha values. */
|
|
2
2
|
.scheduler-left-sidebar {
|
|
3
3
|
border-right: 1px rgb(229 231 235 / 100%) solid;
|
|
4
4
|
height: 100vh;
|
|
@@ -294,6 +294,14 @@ body[data-theme='dark'] .fleetops-connectivity-kpi-accent-rose .fleetops-connect
|
|
|
294
294
|
color: #fde047;
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
+
.fleetops-device-status-badge.status-badge > span {
|
|
298
|
+
padding: 0 0.25rem !important;
|
|
299
|
+
border-radius: 0.125rem !important;
|
|
300
|
+
font-size: 0.5625rem !important;
|
|
301
|
+
line-height: 0.75rem !important;
|
|
302
|
+
font-weight: 700;
|
|
303
|
+
}
|
|
304
|
+
|
|
297
305
|
.fleetops-provider-connections-panel .table-wrapper table tbody tr td,
|
|
298
306
|
.fleetops-provider-connections-panel .next-table-wrapper table tbody tr td {
|
|
299
307
|
vertical-align: top;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="flex flex-col gap-3 p-3">
|
|
2
|
-
<div class="flex items-start justify-between gap-3">
|
|
2
|
+
<div class="flex flex-col items-start justify-between gap-3">
|
|
3
3
|
<div class="min-w-0">
|
|
4
4
|
<h2 class="text-base font-bold text-gray-900 dark:text-gray-100">Vehicle Attachment</h2>
|
|
5
5
|
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-300">Fleet context for telemetry from this device.</p>
|
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
{{#if this.hasVehicle}}
|
|
9
9
|
<div class="flex flex-nowrap items-center gap-2 whitespace-nowrap">
|
|
10
|
-
{{#if this.
|
|
10
|
+
{{#if this.canOpenVehicle}}
|
|
11
11
|
<Button @icon="eye" @text="Open Vehicle" @size="xs" @onClick={{this.openVehicle}} />
|
|
12
12
|
{{/if}}
|
|
13
|
+
{{#if this.canLocateVehicle}}
|
|
14
|
+
<Button @icon="location-dot" @text="Locate" @size="xs" @onClick={{this.locateVehicle}} />
|
|
15
|
+
{{/if}}
|
|
13
16
|
<Button @icon="shuffle" @text="Change Vehicle" @size="xs" @onClick={{this.attachToVehicle}} />
|
|
14
17
|
<Button @icon="unlink" @text="Detach" @size="xs" @type="danger" @onClick={{this.detachFromVehicle}} />
|
|
15
18
|
</div>
|
|
@@ -70,6 +73,67 @@
|
|
|
70
73
|
</div>
|
|
71
74
|
</div>
|
|
72
75
|
</section>
|
|
76
|
+
|
|
77
|
+
<section class="overflow-hidden rounded-md border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800">
|
|
78
|
+
<div class="flex items-start justify-between gap-3 border-b border-gray-200 px-3 py-2 dark:border-gray-700">
|
|
79
|
+
<div class="min-w-0">
|
|
80
|
+
<h3 class="text-sm font-bold text-gray-900 dark:text-gray-100">Latest Positions</h3>
|
|
81
|
+
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-300">Recent vehicle coordinates reported through this device attachment.</p>
|
|
82
|
+
</div>
|
|
83
|
+
{{#if this.canOpenVehicle}}
|
|
84
|
+
<Button @icon="route" @text="Full History" @size="xs" @onClick={{this.openVehiclePositions}} />
|
|
85
|
+
{{/if}}
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
{{#if this.hasPositions}}
|
|
89
|
+
<div class="grid grid-cols-1 gap-0 divide-y divide-gray-100 dark:divide-gray-700">
|
|
90
|
+
{{#each this.positions as |position index|}}
|
|
91
|
+
<div class="flex flex-wrap items-center justify-between gap-3 px-3 py-2 text-xs">
|
|
92
|
+
<div class="flex min-w-0 items-center gap-2">
|
|
93
|
+
<div class="flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-md bg-blue-50 text-blue-600 dark:bg-blue-900/30 dark:text-blue-300">
|
|
94
|
+
<span class="font-bold">{{add index 1}}</span>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="min-w-0">
|
|
97
|
+
<div class="truncate font-semibold text-gray-900 dark:text-gray-100">{{n-a (format-date-fns position.created_at "dd MMM yyyy, HH:mm")}}</div>
|
|
98
|
+
<div class="truncate text-gray-500 dark:text-gray-400">{{n-a (point-coordinates position.coordinates)}}</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="grid grid-cols-2 gap-2 text-right text-gray-500 dark:text-gray-400 sm:grid-cols-3">
|
|
102
|
+
<div>
|
|
103
|
+
<div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Speed</div>
|
|
104
|
+
<div class="text-gray-800 dark:text-gray-100">{{n-a position.speed}}</div>
|
|
105
|
+
</div>
|
|
106
|
+
<div>
|
|
107
|
+
<div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Heading</div>
|
|
108
|
+
<div class="text-gray-800 dark:text-gray-100">{{n-a position.heading position.bearing}}</div>
|
|
109
|
+
</div>
|
|
110
|
+
<div>
|
|
111
|
+
<div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Altitude</div>
|
|
112
|
+
<div class="text-gray-800 dark:text-gray-100">{{n-a position.altitude}}</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
{{/each}}
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<div class="border-t border-gray-200 dark:border-gray-700">
|
|
120
|
+
<PositionsReplay @resource={{this.vehicle}} @mapHeight={{180}} class="max-h-[360px] overflow-hidden" />
|
|
121
|
+
</div>
|
|
122
|
+
<Spacer @height="150px" />
|
|
123
|
+
{{else}}
|
|
124
|
+
<div class="p-3">
|
|
125
|
+
<Telematic::TabEmptyState
|
|
126
|
+
@tone="info"
|
|
127
|
+
@icon="location-dot"
|
|
128
|
+
@title="No recent positions"
|
|
129
|
+
@message="This attached vehicle does not have recent position history available yet."
|
|
130
|
+
@primaryText="Locate Vehicle"
|
|
131
|
+
@primaryIcon="location-dot"
|
|
132
|
+
@primaryAction={{this.locateVehicle}}
|
|
133
|
+
/>
|
|
134
|
+
</div>
|
|
135
|
+
{{/if}}
|
|
136
|
+
</section>
|
|
73
137
|
{{else}}
|
|
74
138
|
<Telematic::TabEmptyState
|
|
75
139
|
@tone="warning"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<div class="h-full overflow-y-auto bg-gray-50 dark:bg-gray-900">
|
|
2
|
+
<section class="sticky top-0 z-40 border-b border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-900">
|
|
3
|
+
<div class="mx-auto flex w-full max-w-7xl flex-col gap-3 px-4 py-3 md:px-6 lg:flex-row lg:items-start lg:justify-between">
|
|
4
|
+
<div class="min-w-0 flex-1">
|
|
5
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
6
|
+
<h1 class="truncate text-lg font-bold text-gray-900 dark:text-gray-100">{{smart-humanize this.event.event_type}}</h1>
|
|
7
|
+
<Badge @status={{this.event.severity}} @hideStatusDot={{true}}>{{smart-humanize this.event.severity}}</Badge>
|
|
8
|
+
<Badge @status={{this.processedStatus}} @hideStatusDot={{true}}>{{this.processedLabel}}</Badge>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="mt-1 flex flex-wrap gap-2 text-xs text-gray-500 dark:text-gray-300">
|
|
11
|
+
<span>{{n-a this.event.public_id}}</span>
|
|
12
|
+
<span>Device: {{n-a (or this.event.device_name this.event.device_id this.event.ident)}}</span>
|
|
13
|
+
<span>Provider: {{n-a (or this.event.telematic_name this.event.provider)}}</span>
|
|
14
|
+
<span>Occurred: {{n-a (format-date-fns this.event.occurred_at "dd MMM yyyy, HH:mm")}}</span>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="flex shrink-0 flex-row flex-nowrap items-center gap-2 whitespace-nowrap">
|
|
19
|
+
<Button @icon="arrow-left" @text="Back" @size="xs" @wrapperClass="shrink-0" @onClick={{this.goBack}} />
|
|
20
|
+
<Button @icon="refresh" @text="Refresh" @size="xs" @wrapperClass="shrink-0" @onClick={{this.refresh}} />
|
|
21
|
+
{{#unless this.isProcessed}}
|
|
22
|
+
<Button
|
|
23
|
+
@icon="check"
|
|
24
|
+
@text="Mark Processed"
|
|
25
|
+
@type="primary"
|
|
26
|
+
@size="xs"
|
|
27
|
+
@wrapperClass="shrink-0"
|
|
28
|
+
@isLoading={{this.isMarkingProcessed}}
|
|
29
|
+
@disabled={{this.isMarkingProcessed}}
|
|
30
|
+
@onClick={{this.markProcessed}}
|
|
31
|
+
/>
|
|
32
|
+
{{/unless}}
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</section>
|
|
36
|
+
|
|
37
|
+
<section class="mx-auto w-full max-w-7xl">
|
|
38
|
+
<DeviceEvent::Details @resource={{this.event}} />
|
|
39
|
+
</section>
|
|
40
|
+
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<Layout::Resource::Panel
|
|
2
2
|
@resource={{@model}}
|
|
3
3
|
@controller={{this}}
|
|
4
|
-
@
|
|
4
|
+
@headerComponent={{component "vendor/panel-header"}}
|
|
5
5
|
@actionButtons={{this.actionButtons}}
|
|
6
6
|
@onPressCancel={{transition-to "management.vendors.index"}}
|
|
7
7
|
@onOverlayReady={{fn (mut this.overlay)}}
|
|
@@ -11,4 +11,4 @@
|
|
|
11
11
|
<TabNavigation @tabs={{this.tabs}} @contentClass="scrollable" @tablistClass="pl-2">
|
|
12
12
|
{{outlet}}
|
|
13
13
|
</TabNavigation>
|
|
14
|
-
</Layout::Resource::Panel>
|
|
14
|
+
</Layout::Resource::Panel>
|
|
@@ -14,15 +14,12 @@
|
|
|
14
14
|
<div class="container mx-auto h-screen">
|
|
15
15
|
<div class="max-w-3xl my-10 mx-auto space-y-6">
|
|
16
16
|
|
|
17
|
-
{{
|
|
17
|
+
{{! ─── Map Provider Panel ──────────────────────────────────────────── }}
|
|
18
18
|
<ContentPanel @title={{t "settings.map.configure-map"}} @open={{true}} @wrapperClass="bordered-classic">
|
|
19
19
|
{{#if this.settingsLoaded}}
|
|
20
20
|
|
|
21
|
-
{{
|
|
22
|
-
<InputGroup
|
|
23
|
-
@name={{t "settings.map.map-provider"}}
|
|
24
|
-
@helpText={{t "settings.map.map-provider-help-text"}}
|
|
25
|
-
>
|
|
21
|
+
{{! Provider selector }}
|
|
22
|
+
<InputGroup @name={{t "settings.map.map-provider"}} @helpText={{t "settings.map.map-provider-help-text"}}>
|
|
26
23
|
<Select
|
|
27
24
|
class="w-full flex-1"
|
|
28
25
|
@value={{this.mapProvider}}
|
|
@@ -34,15 +31,47 @@
|
|
|
34
31
|
/>
|
|
35
32
|
</InputGroup>
|
|
36
33
|
|
|
34
|
+
{{#if this.isGoogleMapsSelected}}
|
|
35
|
+
<InputGroup @name={{t "settings.map.google-maps-map-type"}} @helpText={{t "settings.map.google-maps-map-type-help-text"}}>
|
|
36
|
+
<Select
|
|
37
|
+
class="w-full flex-1"
|
|
38
|
+
@value={{this.googleMapsMapType}}
|
|
39
|
+
@options={{this.googleMapsMapTypeOptions}}
|
|
40
|
+
@optionLabel="label"
|
|
41
|
+
@optionValue="value"
|
|
42
|
+
@placeholder={{t "settings.map.select-map-type"}}
|
|
43
|
+
@onSelect={{fn (mut this.googleMapsMapType)}}
|
|
44
|
+
/>
|
|
45
|
+
</InputGroup>
|
|
46
|
+
|
|
47
|
+
<InputGroup>
|
|
48
|
+
<Toggle
|
|
49
|
+
@label={{t "settings.map.show-traffic-layer"}}
|
|
50
|
+
@isToggled={{this.showGoogleMapsTrafficLayer}}
|
|
51
|
+
@onToggle={{fn (mut this.showGoogleMapsTrafficLayer)}}
|
|
52
|
+
@helpText={{t "settings.map.show-traffic-layer-help-text"}}
|
|
53
|
+
/>
|
|
54
|
+
</InputGroup>
|
|
55
|
+
|
|
56
|
+
<InputGroup>
|
|
57
|
+
<Toggle
|
|
58
|
+
@label={{t "settings.map.show-transit-layer"}}
|
|
59
|
+
@isToggled={{this.showGoogleMapsTransitLayer}}
|
|
60
|
+
@onToggle={{fn (mut this.showGoogleMapsTransitLayer)}}
|
|
61
|
+
@helpText={{t "settings.map.show-transit-layer-help-text"}}
|
|
62
|
+
/>
|
|
63
|
+
</InputGroup>
|
|
64
|
+
{{/if}}
|
|
65
|
+
|
|
37
66
|
{{else}}
|
|
38
|
-
{{
|
|
67
|
+
{{! Loading state }}
|
|
39
68
|
<div class="flex items-center justify-center py-8">
|
|
40
69
|
<Spinner />
|
|
41
70
|
</div>
|
|
42
71
|
{{/if}}
|
|
43
72
|
</ContentPanel>
|
|
44
73
|
|
|
45
|
-
{{
|
|
74
|
+
{{! Extension point for third-party panels }}
|
|
46
75
|
<RegistryYield @registry="fleet-ops:template:settings:map" as |RegistryComponent|>
|
|
47
76
|
<RegistryComponent @controller={{this}} />
|
|
48
77
|
</RegistryYield>
|
|
@@ -50,4 +79,4 @@
|
|
|
50
79
|
</div>
|
|
51
80
|
</div>
|
|
52
81
|
<Spacer @height="600px" />
|
|
53
|
-
</Layout::Section::Body>
|
|
82
|
+
</Layout::Section::Body>
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
<div class="fleetbase-model-select fleetbase-power-select ember-model-select">
|
|
20
20
|
<PowerSelectMultiple
|
|
21
21
|
@searchEnabled={{true}}
|
|
22
|
+
@searchField="label"
|
|
22
23
|
@options={{this.notifiables}}
|
|
23
24
|
@selected={{get this.notificationSettings (concat (get-notification-key notification.definition notification.name) ".notifiables")}}
|
|
24
25
|
@onChange={{fn this.onSelectNotifiable notification}}
|
|
@@ -35,4 +36,4 @@
|
|
|
35
36
|
</div>
|
|
36
37
|
</div>
|
|
37
38
|
<Spacer @height="600px" />
|
|
38
|
-
</Layout::Section::Body>
|
|
39
|
+
</Layout::Section::Body>
|
|
@@ -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
|
+
}
|
|
@@ -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
|
+
}
|