@fleetbase/fleetops-engine 0.6.52 → 0.6.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/components/device/details.hbs +106 -135
- package/addon/components/device/details.js +174 -1
- package/addon/components/device/panel-header.hbs +2 -2
- package/addon/components/layout/fleet-ops-sidebar/operations-monitor.hbs +201 -0
- package/addon/components/layout/fleet-ops-sidebar/operations-monitor.js +654 -0
- package/addon/components/layout/fleet-ops-sidebar.hbs +19 -233
- package/addon/components/layout/fleet-ops-sidebar.js +364 -395
- package/addon/components/maintenance-schedule/form.js +1 -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 +50 -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/telematic/details.hbs +7 -1
- package/addon/components/telematic/form.js +16 -8
- 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 +74 -0
- package/addon/controllers/connectivity/devices/index/details.js +12 -0
- package/addon/controllers/connectivity/devices/index.js +4 -1
- package/addon/controllers/connectivity/telematics/details/attachments.js +220 -54
- package/addon/controllers/connectivity/telematics/details/devices.js +90 -41
- package/addon/controllers/connectivity/telematics/details/events.js +39 -11
- package/addon/controllers/connectivity/telematics/details/sensors.js +39 -19
- package/addon/controllers/maintenance/index.js +100 -0
- package/addon/controllers/maintenance/work-orders/index.js +18 -1
- package/addon/controllers/management/fuel-transactions/index.js +1 -1
- package/addon/controllers/management/index.js +88 -0
- package/addon/controllers/settings/index.js +142 -0
- package/addon/extension.js +21 -0
- package/addon/routes/analytics/index.js +3 -0
- 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 +7 -0
- package/addon/routes/connectivity/devices/index.js +3 -0
- package/addon/routes/connectivity/telematics/details/attachments.js +72 -9
- package/addon/routes/connectivity/telematics/details/devices.js +4 -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/index.js +3 -0
- package/addon/routes/maintenance/work-orders/index.js +3 -0
- package/addon/routes/settings/index.js +3 -0
- package/addon/routes.js +2 -0
- package/addon/services/order-creation.js +54 -1
- package/addon/services/order-validation.js +3 -2
- package/addon/services/service-rate-actions.js +1 -0
- package/addon/styles/fleetops-engine.css +1821 -6
- package/addon/templates/analytics/index.hbs +14 -0
- package/addon/templates/analytics/reports/index.hbs +4 -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 +84 -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/maintenance/index.hbs +113 -0
- package/addon/templates/management/fuel-transactions/index/details.hbs +1 -1
- package/addon/templates/management/index.hbs +109 -73
- package/addon/templates/management/vehicles/index/edit.hbs +1 -1
- package/addon/templates/operations/orders/index.hbs +1 -1
- package/addon/templates/operations/service-rates/index.hbs +1 -1
- package/addon/templates/settings/index.hbs +83 -0
- package/addon/templates/settings/routing.hbs +2 -2
- package/addon/utils/fleet-ops-options.js +38 -0
- package/app/components/order/form/orchestrator-constraints.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/maintenance/index.js +1 -0
- package/app/controllers/management/index.js +1 -0
- package/app/controllers/settings/index.js +1 -0
- package/app/routes/analytics/index.js +1 -0
- 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/maintenance/index.js +1 -0
- package/app/routes/settings/index.js +1 -0
- package/app/templates/analytics/index.js +1 -0
- 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/maintenance/index.js +1 -0
- package/app/templates/management/index.js +1 -0
- package/app/templates/settings/index.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +3 -3
- package/server/migrations/2025_08_28_054930_create_work_orders_table.php +1 -0
- package/server/migrations/2026_06_15_000001_normalize_device_attachable_vehicle_morph_types.php +30 -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/FixInvalidPolymorphicRelationTypeNamespaces.php +1 -0
- 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 +112 -11
- package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +16 -5
- package/server/src/Http/Controllers/Internal/v1/FleetController.php +9 -0
- package/server/src/Http/Controllers/Internal/v1/HubController.php +300 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +177 -0
- 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 +506 -0
- package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +4 -4
- package/server/src/Http/Controllers/Internal/v1/TelematicController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +94 -10
- package/server/src/Http/Filter/DeviceEventFilter.php +44 -0
- package/server/src/Http/Filter/DeviceFilter.php +131 -0
- package/server/src/Http/Filter/DriverFilter.php +6 -0
- package/server/src/Http/Filter/SensorFilter.php +125 -0
- package/server/src/Http/Filter/VehicleFilter.php +19 -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/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 +181 -66
- package/server/src/Models/Device.php +15 -1
- package/server/src/Models/DeviceEvent.php +1 -1
- package/server/src/Models/Driver.php +17 -1
- 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 +12 -0
- package/server/src/Support/LiveCacheService.php +1 -1
- package/server/src/Support/Telematics/Providers/AfaqyProvider.php +188 -28
- package/server/src/Support/Telematics/Providers/SafeeProvider.php +44 -3
- package/server/src/Support/Telematics/TelematicService.php +330 -30
- package/server/src/routes.php +10 -0
- package/server/tests/DeviceFilterTest.php +36 -0
- package/server/tests/HubRoutesTest.php +62 -0
- package/server/tests/OperationsMonitorEndpointTest.php +38 -0
- package/server/tests/OrderQueuedClosureRegressionTest.php +36 -0
- package/server/tests/TelematicsHardeningTest.php +455 -3
- package/server/tests/VehicleDriverAssignmentTest.php +27 -0
- package/translations/ar-ae.yml +1 -1
- package/translations/en-us.yaml +1 -0
- package/translations/vi-vn.yaml +1 -1
|
@@ -2,6 +2,15 @@ import Controller from '@ember/controller';
|
|
|
2
2
|
import { action } from '@ember/object';
|
|
3
3
|
import { inject as service } from '@ember/service';
|
|
4
4
|
import { tracked } from '@glimmer/tracking';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
|
|
7
|
+
const severityOptions = [
|
|
8
|
+
{ label: 'Info', value: 'info' },
|
|
9
|
+
{ label: 'Warning', value: 'warning' },
|
|
10
|
+
{ label: 'Error', value: 'error' },
|
|
11
|
+
{ label: 'Critical', value: 'critical' },
|
|
12
|
+
{ label: 'High', value: 'high' },
|
|
13
|
+
];
|
|
5
14
|
|
|
6
15
|
export default class ConnectivityTelematicsDetailsEventsController extends Controller {
|
|
7
16
|
@service deviceEventActions;
|
|
@@ -99,15 +108,19 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
|
|
|
99
108
|
];
|
|
100
109
|
}
|
|
101
110
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
get actionButtons() {
|
|
112
|
+
return [
|
|
113
|
+
{
|
|
114
|
+
icon: 'refresh',
|
|
115
|
+
size: 'sm',
|
|
116
|
+
onClick: this.refresh,
|
|
117
|
+
helpText: this.intl.t('common.refresh'),
|
|
118
|
+
wrapperClass: 'fleetops-telematics-action-button',
|
|
119
|
+
isLoading: this.refreshTask.isRunning,
|
|
120
|
+
disabled: this.refreshTask.isRunning,
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
}
|
|
111
124
|
|
|
112
125
|
@tracked bulkActions = [];
|
|
113
126
|
|
|
@@ -136,6 +149,8 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
|
|
|
136
149
|
filterComponentPlaceholder: 'Select device',
|
|
137
150
|
filterParam: 'device_uuid',
|
|
138
151
|
model: 'device',
|
|
152
|
+
modelNamePath: 'displayName',
|
|
153
|
+
query: { telematic_uuid: this.telematic?.id },
|
|
139
154
|
},
|
|
140
155
|
{
|
|
141
156
|
label: 'Provider',
|
|
@@ -155,7 +170,10 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
|
|
|
155
170
|
sortable: true,
|
|
156
171
|
filterable: true,
|
|
157
172
|
filterParam: 'severity',
|
|
158
|
-
filterComponent: 'filter/
|
|
173
|
+
filterComponent: 'filter/multi-option',
|
|
174
|
+
filterOptions: severityOptions,
|
|
175
|
+
filterOptionLabel: 'label',
|
|
176
|
+
filterOptionValue: 'value',
|
|
159
177
|
},
|
|
160
178
|
{
|
|
161
179
|
label: 'Processed',
|
|
@@ -170,6 +188,8 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
|
|
|
170
188
|
{ label: 'Processed', value: 'processed' },
|
|
171
189
|
{ label: 'Unprocessed', value: 'unprocessed' },
|
|
172
190
|
],
|
|
191
|
+
filterOptionLabel: 'label',
|
|
192
|
+
filterOptionValue: 'value',
|
|
173
193
|
},
|
|
174
194
|
{
|
|
175
195
|
label: 'Occurred',
|
|
@@ -222,7 +242,11 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
|
|
|
222
242
|
}
|
|
223
243
|
|
|
224
244
|
@action refresh() {
|
|
225
|
-
|
|
245
|
+
if (this.refreshTask.isRunning) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return this.refreshTask.perform();
|
|
226
250
|
}
|
|
227
251
|
|
|
228
252
|
@action clearFilters() {
|
|
@@ -241,4 +265,8 @@ export default class ConnectivityTelematicsDetailsEventsController extends Contr
|
|
|
241
265
|
await this.deviceEventActions.markProcessed(deviceEvent);
|
|
242
266
|
await this.hostRouter.refresh();
|
|
243
267
|
}
|
|
268
|
+
|
|
269
|
+
@task *refreshTask() {
|
|
270
|
+
yield this.hostRouter.refresh();
|
|
271
|
+
}
|
|
244
272
|
}
|
|
@@ -2,6 +2,7 @@ import Controller from '@ember/controller';
|
|
|
2
2
|
import { action } from '@ember/object';
|
|
3
3
|
import { inject as service } from '@ember/service';
|
|
4
4
|
import { tracked } from '@glimmer/tracking';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
5
6
|
import fleetOpsOptions from '../../../../utils/fleet-ops-options';
|
|
6
7
|
|
|
7
8
|
export default class ConnectivityTelematicsDetailsSensorsController extends Controller {
|
|
@@ -10,7 +11,7 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
|
|
|
10
11
|
@service hostRouter;
|
|
11
12
|
@service intl;
|
|
12
13
|
|
|
13
|
-
@tracked queryParams = ['page', 'limit', 'sort', 'query', 'status', 'type', 'device_uuid'];
|
|
14
|
+
@tracked queryParams = ['page', 'limit', 'sort', 'query', 'status', 'type', 'device_uuid', 'last_reading_at'];
|
|
14
15
|
@tracked telematic;
|
|
15
16
|
@tracked page = 1;
|
|
16
17
|
@tracked limit;
|
|
@@ -19,6 +20,7 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
|
|
|
19
20
|
@tracked status;
|
|
20
21
|
@tracked type;
|
|
21
22
|
@tracked device_uuid;
|
|
23
|
+
@tracked last_reading_at;
|
|
22
24
|
|
|
23
25
|
get sensors() {
|
|
24
26
|
return Array.from(this.model ?? []);
|
|
@@ -37,7 +39,7 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
|
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
get hasActiveFilters() {
|
|
40
|
-
return Boolean(this.query || this.status || this.type || this.device_uuid);
|
|
42
|
+
return Boolean(this.query || this.status || this.type || this.device_uuid || this.last_reading_at);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
get hasSensors() {
|
|
@@ -122,22 +124,26 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
|
|
|
122
124
|
];
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
127
|
+
get actionButtons() {
|
|
128
|
+
return [
|
|
129
|
+
{
|
|
130
|
+
icon: 'refresh',
|
|
131
|
+
size: 'sm',
|
|
132
|
+
onClick: this.refresh,
|
|
133
|
+
helpText: this.intl.t('common.refresh'),
|
|
134
|
+
wrapperClass: 'fleetops-telematics-action-button',
|
|
135
|
+
isLoading: this.refreshTask.isRunning,
|
|
136
|
+
disabled: this.refreshTask.isRunning,
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
icon: 'microchip',
|
|
140
|
+
text: 'View Devices',
|
|
141
|
+
size: 'sm',
|
|
142
|
+
onClick: this.goToDevices,
|
|
143
|
+
wrapperClass: 'fleetops-telematics-action-button',
|
|
144
|
+
},
|
|
145
|
+
];
|
|
146
|
+
}
|
|
141
147
|
|
|
142
148
|
@tracked bulkActions = [];
|
|
143
149
|
|
|
@@ -179,6 +185,8 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
|
|
|
179
185
|
filterComponentPlaceholder: 'Select device',
|
|
180
186
|
filterParam: 'device_uuid',
|
|
181
187
|
model: 'device',
|
|
188
|
+
modelNamePath: 'displayName',
|
|
189
|
+
query: { telematic_uuid: this.telematic?.id },
|
|
182
190
|
},
|
|
183
191
|
{
|
|
184
192
|
label: 'Value',
|
|
@@ -208,6 +216,9 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
|
|
|
208
216
|
sortParam: 'last_reading_at',
|
|
209
217
|
resizable: true,
|
|
210
218
|
sortable: true,
|
|
219
|
+
filterable: true,
|
|
220
|
+
filterParam: 'last_reading_at',
|
|
221
|
+
filterComponent: 'filter/date',
|
|
211
222
|
},
|
|
212
223
|
{
|
|
213
224
|
label: '',
|
|
@@ -241,7 +252,11 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
|
|
|
241
252
|
}
|
|
242
253
|
|
|
243
254
|
@action refresh() {
|
|
244
|
-
|
|
255
|
+
if (this.refreshTask.isRunning) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return this.refreshTask.perform();
|
|
245
260
|
}
|
|
246
261
|
|
|
247
262
|
@action clearFilters() {
|
|
@@ -249,6 +264,7 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
|
|
|
249
264
|
this.status = null;
|
|
250
265
|
this.type = null;
|
|
251
266
|
this.device_uuid = null;
|
|
267
|
+
this.last_reading_at = null;
|
|
252
268
|
this.page = 1;
|
|
253
269
|
}
|
|
254
270
|
|
|
@@ -267,4 +283,8 @@ export default class ConnectivityTelematicsDetailsSensorsController extends Cont
|
|
|
267
283
|
queryParams: { device_id: sensor.device_uuid },
|
|
268
284
|
});
|
|
269
285
|
}
|
|
286
|
+
|
|
287
|
+
@task *refreshTask() {
|
|
288
|
+
yield this.hostRouter.refresh();
|
|
289
|
+
}
|
|
270
290
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
|
|
7
|
+
export default class MaintenanceIndexController extends Controller {
|
|
8
|
+
@service fetch;
|
|
9
|
+
@service docsPanel;
|
|
10
|
+
|
|
11
|
+
@tracked hub = null;
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.loadHub.perform();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get kpis() {
|
|
19
|
+
return this.hub?.kpis ?? this.loadingKpis;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get actions() {
|
|
23
|
+
return (this.hub?.actions ?? []).map((action) => this.normalizeAction(action));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get sections() {
|
|
27
|
+
return this.hub?.sections ?? [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get docs() {
|
|
31
|
+
return (this.hub?.docs ?? []).map((doc) => ({
|
|
32
|
+
...doc,
|
|
33
|
+
description: doc.description ?? this.docDescriptions[doc.slug] ?? '',
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
docDescriptions = {
|
|
38
|
+
'fleet-ops/maintenance/schedules/overview': 'Plan recurring service windows and convert due schedules into work orders.',
|
|
39
|
+
'fleet-ops/maintenance/work-orders/overview': 'Coordinate assigned maintenance work, vendors, due dates, and completion.',
|
|
40
|
+
'fleet-ops/maintenance/equipment/overview': 'Track serviceable equipment that participates in maintenance operations.',
|
|
41
|
+
'fleet-ops/maintenance/parts/overview': 'Manage parts inventory and restocking signals used by maintenance teams.',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
normalizeAction(action = {}) {
|
|
45
|
+
const query = action.query && typeof action.query === 'object' && !Array.isArray(action.query) ? action.query : {};
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
...action,
|
|
49
|
+
query,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get loadingKpis() {
|
|
54
|
+
return [
|
|
55
|
+
{
|
|
56
|
+
key: 'overdue_schedules',
|
|
57
|
+
label: 'Overdue Schedules',
|
|
58
|
+
value: '...',
|
|
59
|
+
caption: 'Loading recurring service risk.',
|
|
60
|
+
tone: 'rose',
|
|
61
|
+
icon: 'calendar-xmark',
|
|
62
|
+
route: 'maintenance.schedules',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
key: 'upcoming_schedules',
|
|
66
|
+
label: 'Due This Week',
|
|
67
|
+
value: '...',
|
|
68
|
+
caption: 'Loading upcoming service windows.',
|
|
69
|
+
tone: 'blue',
|
|
70
|
+
icon: 'calendar-day',
|
|
71
|
+
route: 'maintenance.schedules',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
key: 'open_work_orders',
|
|
75
|
+
label: 'Open Work Orders',
|
|
76
|
+
value: '...',
|
|
77
|
+
caption: 'Loading active maintenance work.',
|
|
78
|
+
tone: 'amber',
|
|
79
|
+
icon: 'clipboard-list',
|
|
80
|
+
route: 'maintenance.work-orders',
|
|
81
|
+
},
|
|
82
|
+
{ key: 'low_stock_parts', label: 'Low Stock Parts', value: '...', caption: 'Loading parts inventory signals.', tone: 'amber', icon: 'cog', route: 'maintenance.parts' },
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@action openDocs(link) {
|
|
87
|
+
if (!link?.slug) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return this.docsPanel.open(link.slug, {
|
|
92
|
+
title: link.title ?? link.label,
|
|
93
|
+
source: 'fleet-ops-maintenance-hub',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@task *loadHub() {
|
|
98
|
+
this.hub = yield this.fetch.get('fleet-ops/hubs/maintenance');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import Controller from '@ember/controller';
|
|
2
2
|
import { inject as service } from '@ember/service';
|
|
3
3
|
import { tracked } from '@glimmer/tracking';
|
|
4
|
+
import fleetOpsOptions from '../../../utils/fleet-ops-options';
|
|
4
5
|
|
|
5
6
|
export default class MaintenanceWorkOrdersIndexController extends Controller {
|
|
6
7
|
@service workOrderActions;
|
|
7
8
|
@service intl;
|
|
8
9
|
|
|
9
|
-
@tracked queryParams = ['status', 'priority', 'page', 'limit', 'sort', 'query', 'public_id', 'created_at', 'updated_at'];
|
|
10
|
+
@tracked queryParams = ['category', 'status', 'priority', 'page', 'limit', 'sort', 'query', 'public_id', 'created_at', 'updated_at'];
|
|
10
11
|
@tracked page = 1;
|
|
11
12
|
@tracked limit;
|
|
12
13
|
@tracked sort = '-created_at';
|
|
13
14
|
@tracked public_id;
|
|
15
|
+
@tracked category;
|
|
14
16
|
@tracked status;
|
|
15
17
|
@tracked priority;
|
|
16
18
|
|
|
@@ -43,6 +45,21 @@ export default class MaintenanceWorkOrdersIndexController extends Controller {
|
|
|
43
45
|
filterComponent: 'filter/string',
|
|
44
46
|
},
|
|
45
47
|
{ label: this.intl.t('column.subject'), valuePath: 'subject', resizable: true, sortable: true, filterable: true, filterParam: 'subject', filterComponent: 'filter/string' },
|
|
48
|
+
{
|
|
49
|
+
label: this.intl.t('column.category'),
|
|
50
|
+
valuePath: 'category',
|
|
51
|
+
cellComponent: 'table/cell/base',
|
|
52
|
+
humanize: true,
|
|
53
|
+
resizable: true,
|
|
54
|
+
sortable: true,
|
|
55
|
+
filterable: true,
|
|
56
|
+
filterParam: 'category',
|
|
57
|
+
filterComponent: 'filter/select',
|
|
58
|
+
filterOptionLabel: 'label',
|
|
59
|
+
filterOptionValue: 'value',
|
|
60
|
+
filterOptions: fleetOpsOptions('workOrderCategories'),
|
|
61
|
+
placeholder: 'Select work order category',
|
|
62
|
+
},
|
|
46
63
|
{
|
|
47
64
|
label: this.intl.t('column.status'),
|
|
48
65
|
valuePath: 'status',
|
|
@@ -40,7 +40,7 @@ export default class ManagementFuelTransactionsIndexController extends Controlle
|
|
|
40
40
|
|
|
41
41
|
get emptyStateMessage() {
|
|
42
42
|
if (this.sync_status === 'unmatched') {
|
|
43
|
-
return '
|
|
43
|
+
return 'Fleet-Ops did not find imported provider bills that still need vehicle or trip matching.';
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
if (this.connection) {
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
|
|
7
|
+
export default class ManagementIndexController extends Controller {
|
|
8
|
+
@service fetch;
|
|
9
|
+
@service docsPanel;
|
|
10
|
+
|
|
11
|
+
@tracked hub = null;
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.loadHub.perform();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get kpis() {
|
|
19
|
+
return (this.hub?.kpis ?? this.loadingKpis).map((kpi) => ({
|
|
20
|
+
...kpi,
|
|
21
|
+
actionLabel: kpi.actionLabel ?? this.kpiActionLabels[kpi.key] ?? `Open ${kpi.label}`,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get actions() {
|
|
26
|
+
return (this.hub?.actions ?? []).map((action) => this.normalizeAction(action));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get sections() {
|
|
30
|
+
return this.hub?.sections ?? [];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get docs() {
|
|
34
|
+
return (this.hub?.docs ?? []).map((doc) => ({
|
|
35
|
+
...doc,
|
|
36
|
+
description: doc.description ?? this.docDescriptions[doc.slug] ?? '',
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
docDescriptions = {
|
|
41
|
+
'fleet-ops/resources/drivers/overview': 'Create driver profiles, app access, assignment context, and operating status.',
|
|
42
|
+
'fleet-ops/resources/vehicles/overview': 'Track fleet assets, assignment readiness, and vehicle operating details.',
|
|
43
|
+
'fleet-ops/resources/fleets/overview': 'Group drivers and vehicles by team, region, or service coverage.',
|
|
44
|
+
'fleet-ops/resources/contacts/overview': 'Manage people and organizations used across orders and operational records.',
|
|
45
|
+
'fleet-ops/resources/places/overview': 'Manage reusable pickup, dropoff, hub, and facility locations.',
|
|
46
|
+
'fleet-ops/resources/issues/overview': 'Track incidents, service exceptions, and operational follow-up.',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
kpiActionLabels = {
|
|
50
|
+
drivers: 'Manage Drivers',
|
|
51
|
+
vehicles: 'Track Vehicles',
|
|
52
|
+
issues: 'Review Issues',
|
|
53
|
+
fuel_records: 'Review Fuel Records',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
normalizeAction(action = {}) {
|
|
57
|
+
const query = action.query && typeof action.query === 'object' && !Array.isArray(action.query) ? action.query : {};
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
...action,
|
|
61
|
+
query,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get loadingKpis() {
|
|
66
|
+
return [
|
|
67
|
+
{ key: 'drivers', label: 'Drivers', value: '...', caption: 'Loading resource readiness.', tone: 'blue', icon: 'id-card', route: 'management.drivers' },
|
|
68
|
+
{ key: 'vehicles', label: 'Vehicles', value: '...', caption: 'Loading fleet asset coverage.', tone: 'green', icon: 'truck', route: 'management.vehicles' },
|
|
69
|
+
{ key: 'issues', label: 'Open Issues', value: '...', caption: 'Loading exception health.', tone: 'rose', icon: 'triangle-exclamation', route: 'management.issues' },
|
|
70
|
+
{ key: 'fuel_records', label: 'Fuel Records', value: '...', caption: 'Loading fuel activity.', tone: 'amber', icon: 'gas-pump', route: 'management.fuel-reports' },
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@action openDocs(link) {
|
|
75
|
+
if (!link?.slug) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return this.docsPanel.open(link.slug, {
|
|
80
|
+
title: link.title ?? link.label,
|
|
81
|
+
source: 'fleet-ops-resources-hub',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@task *loadHub() {
|
|
86
|
+
this.hub = yield this.fetch.get('fleet-ops/hubs/resources');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import Controller from '@ember/controller';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
|
|
5
|
+
export default class SettingsIndexController extends Controller {
|
|
6
|
+
@service docsPanel;
|
|
7
|
+
|
|
8
|
+
groups = [
|
|
9
|
+
{
|
|
10
|
+
title: 'Driver And Map Experience',
|
|
11
|
+
description: 'Tune what dispatchers and drivers see while work is moving.',
|
|
12
|
+
links: [
|
|
13
|
+
{ label: 'Navigator App', route: 'settings.navigator-app', icon: 'location-arrow', description: 'Driver app behavior and workflow defaults.' },
|
|
14
|
+
{ label: 'Map', route: 'settings.map', icon: 'map', description: 'Map providers, defaults, and display behavior.' },
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
title: 'Dispatch Automation',
|
|
19
|
+
description: 'Shape route planning, assignment, and scheduling behavior.',
|
|
20
|
+
links: [
|
|
21
|
+
{ label: 'Routing', route: 'settings.routing', icon: 'route', description: 'Routing engines and routing defaults.' },
|
|
22
|
+
{ label: 'Orchestrator', route: 'settings.orchestrator', icon: 'circle-nodes', description: 'Dispatch orchestration and assignment behavior.' },
|
|
23
|
+
{ label: 'Scheduling', route: 'settings.scheduling', icon: 'calendar-days', description: 'Schedule planning and operational timing rules.' },
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
title: 'Business And Data',
|
|
28
|
+
description: 'Keep commerce, metadata, and visual conventions aligned.',
|
|
29
|
+
links: [
|
|
30
|
+
{ label: 'Payments', route: 'settings.payments', icon: 'cash-register', description: 'Payment setup for operational commerce workflows.' },
|
|
31
|
+
{ label: 'Custom Fields', route: 'settings.custom-fields', icon: 'pen-to-square', description: 'Operational metadata fields for Fleet-Ops records.' },
|
|
32
|
+
{ label: 'Avatars', route: 'settings.avatars', icon: 'icons', description: 'Visual assets for driver, vehicle, and map displays.' },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: 'Communication',
|
|
37
|
+
description: 'Control operational alerts and notification behavior.',
|
|
38
|
+
links: [{ label: 'Notifications', route: 'settings.notifications', icon: 'bell', description: 'Operational status alerts and notification rules.' }],
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
actions = [
|
|
43
|
+
{
|
|
44
|
+
label: 'Start with driver experience',
|
|
45
|
+
description: 'Navigator App and Map settings should be reviewed before operators rely on live dispatch defaults.',
|
|
46
|
+
icon: 'location-arrow',
|
|
47
|
+
route: 'settings.navigator-app',
|
|
48
|
+
tone: 'info',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
label: 'Review automation rules',
|
|
52
|
+
description: 'Routing, orchestration, and scheduling settings affect assignment and planning behavior.',
|
|
53
|
+
icon: 'route',
|
|
54
|
+
route: 'settings.routing',
|
|
55
|
+
tone: 'warning',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
label: 'Keep forms focused',
|
|
59
|
+
description: 'Add custom fields after core workflows are stable so operational screens stay easy to scan.',
|
|
60
|
+
icon: 'pen-to-square',
|
|
61
|
+
route: 'settings.custom-fields',
|
|
62
|
+
tone: 'success',
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
docs = [
|
|
67
|
+
{
|
|
68
|
+
label: 'Navigator App',
|
|
69
|
+
icon: 'location-arrow',
|
|
70
|
+
slug: 'fleet-ops/settings/navigator-app',
|
|
71
|
+
title: 'Navigator App settings',
|
|
72
|
+
description: 'Configure driver app behavior, onboarding, and live workflow defaults.',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
label: 'Map',
|
|
76
|
+
icon: 'map',
|
|
77
|
+
slug: 'fleet-ops/settings/map',
|
|
78
|
+
title: 'Map settings',
|
|
79
|
+
description: 'Set map providers, display defaults, and operator map behavior.',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
label: 'Payments',
|
|
83
|
+
icon: 'cash-register',
|
|
84
|
+
slug: 'fleet-ops/settings/payments',
|
|
85
|
+
title: 'Payments guide',
|
|
86
|
+
description: 'Connect payment providers and payment behavior for Fleet-Ops workflows.',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: 'Notifications',
|
|
90
|
+
icon: 'bell',
|
|
91
|
+
slug: 'fleet-ops/settings/notifications',
|
|
92
|
+
title: 'Notification settings',
|
|
93
|
+
description: 'Tune operational alerts sent to dispatchers, customers, and drivers.',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
label: 'Routing',
|
|
97
|
+
icon: 'route',
|
|
98
|
+
slug: 'fleet-ops/settings/routing',
|
|
99
|
+
title: 'Routing settings',
|
|
100
|
+
description: 'Configure routing engines, tracking defaults, and distance units.',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
label: 'Orchestrator',
|
|
104
|
+
icon: 'circle-nodes',
|
|
105
|
+
slug: 'fleet-ops/settings/orchestrator',
|
|
106
|
+
title: 'Orchestrator settings',
|
|
107
|
+
description: 'Select dispatch automation engines and assignment behavior.',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
label: 'Scheduling',
|
|
111
|
+
icon: 'calendar-days',
|
|
112
|
+
slug: 'fleet-ops/settings/scheduling',
|
|
113
|
+
title: 'Scheduling settings',
|
|
114
|
+
description: 'Manage schedule templates and timing rules for planned work.',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
label: 'Custom Fields',
|
|
118
|
+
icon: 'pen-to-square',
|
|
119
|
+
slug: 'fleet-ops/settings/custom-fields',
|
|
120
|
+
title: 'Custom field settings',
|
|
121
|
+
description: 'Add structured operational metadata to Fleet-Ops records.',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
label: 'Avatars',
|
|
125
|
+
icon: 'icons',
|
|
126
|
+
slug: 'fleet-ops/settings/avatars',
|
|
127
|
+
title: 'Avatar settings',
|
|
128
|
+
description: 'Manage visual markers used across maps and operational screens.',
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
@action openDocs(link) {
|
|
133
|
+
if (!link?.slug) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return this.docsPanel.open(link.slug, {
|
|
138
|
+
title: link.title ?? link.label,
|
|
139
|
+
source: 'fleet-ops-settings-hub',
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
package/addon/extension.js
CHANGED
|
@@ -321,7 +321,28 @@ export default {
|
|
|
321
321
|
}),
|
|
322
322
|
];
|
|
323
323
|
|
|
324
|
+
const defaultWidgets = widgets
|
|
325
|
+
.filter((widget) => (typeof widget.isDefault === 'function' ? widget.isDefault() : widget.default === true))
|
|
326
|
+
.map((widget) => {
|
|
327
|
+
const definition = typeof widget.toObject === 'function' ? widget.toObject() : widget;
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
...definition,
|
|
331
|
+
widgetId: definition.widgetId ?? definition.id,
|
|
332
|
+
};
|
|
333
|
+
});
|
|
334
|
+
|
|
324
335
|
widgetService.registerWidgets('dashboard', widgets);
|
|
336
|
+
|
|
337
|
+
if (typeof widgetService.registerDashboard === 'function') {
|
|
338
|
+
widgetService.registerDashboard('fleet-ops');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
widgetService.registerWidgets('fleet-ops', widgets);
|
|
342
|
+
|
|
343
|
+
if (typeof widgetService.registerDefaultWidgets === 'function') {
|
|
344
|
+
widgetService.registerDefaultWidgets('fleet-ops', defaultWidgets);
|
|
345
|
+
}
|
|
325
346
|
},
|
|
326
347
|
|
|
327
348
|
registerHomeComponents(registryService) {
|
|
@@ -1,3 +1,39 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class ConnectivityDevicesIndexDetailsEventsRoute extends Route {
|
|
4
|
+
export default class ConnectivityDevicesIndexDetailsEventsRoute extends Route {
|
|
5
|
+
@service store;
|
|
6
|
+
|
|
7
|
+
queryParams = {
|
|
8
|
+
events_page: { refreshModel: true },
|
|
9
|
+
events_limit: { refreshModel: true },
|
|
10
|
+
events_sort: { refreshModel: true },
|
|
11
|
+
events_query: { refreshModel: true },
|
|
12
|
+
events_event_type: { refreshModel: true },
|
|
13
|
+
events_severity: { refreshModel: true },
|
|
14
|
+
events_processed: { refreshModel: true },
|
|
15
|
+
events_occurred_at: { refreshModel: true },
|
|
16
|
+
events_created_at: { refreshModel: true },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
model(params) {
|
|
20
|
+
const device = this.modelFor('connectivity.devices.index.details');
|
|
21
|
+
return this.store.query('device-event', {
|
|
22
|
+
page: params.events_page,
|
|
23
|
+
limit: params.events_limit,
|
|
24
|
+
sort: params.events_sort,
|
|
25
|
+
query: params.events_query,
|
|
26
|
+
event_type: params.events_event_type,
|
|
27
|
+
severity: params.events_severity,
|
|
28
|
+
processed: params.events_processed,
|
|
29
|
+
occurred_at: params.events_occurred_at,
|
|
30
|
+
created_at: params.events_created_at,
|
|
31
|
+
device_uuid: device.id,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setupController(controller, model) {
|
|
36
|
+
super.setupController(controller, model);
|
|
37
|
+
controller.device = this.modelFor('connectivity.devices.index.details');
|
|
38
|
+
}
|
|
39
|
+
}
|