@fleetbase/fleetops-engine 0.6.69 → 0.6.70
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 +41 -8
- package/addon/components/admin/telematics-settings.hbs +143 -0
- package/addon/components/admin/telematics-settings.js +145 -0
- package/addon/components/fuel-integration/hub.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +37 -17
- package/addon/components/map/leaflet-live-map.hbs +4 -242
- package/addon/components/map/leaflet-live-map.js +2 -1
- package/addon/components/map/marker-card/driver.hbs +57 -0
- package/addon/components/map/marker-card/driver.js +3 -0
- package/addon/components/map/marker-card/vehicle.hbs +78 -0
- package/addon/components/map/marker-card/vehicle.js +3 -0
- package/addon/components/telematic/hub.hbs +1 -1
- package/addon/components/widget/live-fleet.hbs +8 -40
- package/addon/controllers/analytics/reports/index.js +5 -0
- package/addon/controllers/connectivity/devices/index.js +4 -0
- package/addon/controllers/connectivity/fuel-providers/index.js +6 -4
- package/addon/controllers/connectivity/sensors/index.js +4 -0
- package/addon/controllers/connectivity/telematics/index.js +4 -0
- package/addon/controllers/maintenance/equipment/index.js +11 -4
- package/addon/controllers/maintenance/inspection-forms/index.js +2 -2
- package/addon/controllers/maintenance/inspection-submissions/index.js +8 -2
- package/addon/controllers/maintenance/maintenances/index.js +4 -0
- package/addon/controllers/maintenance/parts/index.js +11 -4
- package/addon/controllers/maintenance/schedules/index.js +17 -4
- package/addon/controllers/maintenance/work-orders/index.js +11 -4
- package/addon/controllers/management/contacts/index.js +4 -0
- package/addon/controllers/management/drivers/index.js +4 -0
- package/addon/controllers/management/fleets/index.js +4 -0
- package/addon/controllers/management/fuel-reports/index.js +4 -0
- package/addon/controllers/management/fuel-transactions/index.js +9 -7
- package/addon/controllers/management/issues/index.js +4 -0
- package/addon/controllers/management/places/index.js +4 -0
- package/addon/controllers/management/vehicles/index.js +4 -0
- package/addon/controllers/management/vendors/index.js +4 -0
- package/addon/controllers/operations/orders/index/details.js +30 -1
- package/addon/controllers/operations/orders/index.js +7 -0
- package/addon/controllers/operations/service-rates/index.js +3 -0
- package/addon/controllers/settings/index.js +13 -0
- package/addon/controllers/settings/telematics.js +113 -0
- package/addon/extension.js +38 -6
- package/addon/routes/analytics/index.js +14 -1
- package/addon/routes/analytics/reports/index/details.js +1 -1
- package/addon/routes/analytics/reports/index/edit.js +1 -1
- package/addon/routes/analytics/reports/index/new.js +14 -1
- package/addon/routes/analytics/reports.js +14 -1
- package/addon/routes/connectivity/devices/index/new.js +14 -1
- package/addon/routes/connectivity/devices.js +14 -1
- package/addon/routes/connectivity/events.js +14 -1
- package/addon/routes/connectivity/fuel-providers/details/transactions.js +12 -0
- package/addon/routes/connectivity/fuel-providers/details.js +9 -0
- package/addon/routes/connectivity/fuel-providers/edit.js +9 -0
- package/addon/routes/connectivity/fuel-providers/new.js +14 -1
- package/addon/routes/connectivity/fuel-providers.js +14 -1
- package/addon/routes/connectivity/sensors/index/new.js +14 -1
- package/addon/routes/connectivity/sensors.js +14 -1
- package/addon/routes/connectivity/telematics/new.js +14 -1
- package/addon/routes/connectivity/telematics.js +14 -1
- package/addon/routes/connectivity/tracking.js +14 -1
- package/addon/routes/maintenance/equipment/index/details.js +2 -2
- package/addon/routes/maintenance/equipment/index/edit.js +2 -2
- package/addon/routes/maintenance/equipment/index/new.js +14 -1
- package/addon/routes/maintenance/equipment.js +14 -1
- package/addon/routes/maintenance/index.js +14 -1
- package/addon/routes/maintenance/inspection-forms/index/details.js +10 -1
- package/addon/routes/maintenance/inspection-forms/index/edit.js +10 -1
- package/addon/routes/maintenance/inspection-forms/index/new.js +14 -1
- package/addon/routes/maintenance/inspection-forms.js +14 -1
- package/addon/routes/maintenance/inspection-submissions/index/details.js +10 -1
- package/addon/routes/maintenance/inspection-submissions/index/edit.js +10 -1
- package/addon/routes/maintenance/inspection-submissions/index/new.js +14 -1
- package/addon/routes/maintenance/inspection-submissions.js +14 -1
- package/addon/routes/maintenance/maintenances/index/details.js +2 -2
- package/addon/routes/maintenance/maintenances/index/edit.js +2 -2
- package/addon/routes/maintenance/maintenances/index/new.js +14 -1
- package/addon/routes/maintenance/maintenances.js +14 -1
- package/addon/routes/maintenance/parts/index/details.js +2 -2
- package/addon/routes/maintenance/parts/index/edit.js +2 -2
- package/addon/routes/maintenance/parts/index/new.js +14 -1
- package/addon/routes/maintenance/parts.js +14 -1
- package/addon/routes/maintenance/schedules/index/details.js +2 -2
- package/addon/routes/maintenance/schedules/index/edit.js +2 -2
- package/addon/routes/maintenance/schedules/index/new.js +15 -1
- package/addon/routes/maintenance/schedules.js +15 -1
- package/addon/routes/maintenance/work-orders/index/details.js +2 -2
- package/addon/routes/maintenance/work-orders/index/edit.js +2 -2
- package/addon/routes/maintenance/work-orders/index/new.js +14 -1
- package/addon/routes/maintenance/work-orders.js +14 -1
- package/addon/routes/management/fuel-transactions/index/details.js +9 -0
- package/addon/routes/management/fuel-transactions.js +14 -1
- package/addon/routes/management/index.js +13 -0
- package/addon/routes/management/trailers.js +16 -0
- package/addon/routes/management/vendors/integrated/details.js +14 -1
- package/addon/routes/management/vendors/integrated/edit.js +14 -1
- package/addon/routes/management/vendors/integrated/new.js +14 -1
- package/addon/routes/management/vendors/integrated.js +14 -1
- package/addon/routes/operations/orders.js +40 -1
- package/addon/routes/operations/routes/index/details.js +14 -1
- package/addon/routes/operations/routes/index/new.js +13 -0
- package/addon/routes/operations/routes.js +14 -1
- package/addon/routes/operations/service-rates/index/new.js +11 -0
- package/addon/routes/operations/service-rates.js +14 -1
- package/addon/routes/settings/avatars.js +14 -1
- package/addon/routes/settings/custom-fields.js +14 -1
- package/addon/routes/settings/map.js +14 -1
- package/addon/routes/settings/notifications.js +11 -0
- package/addon/routes/settings/orchestrator.js +1 -1
- package/addon/routes/settings/payments/index.js +1 -1
- package/addon/routes/settings/routing.js +14 -1
- package/addon/routes/settings/scheduling.js +14 -1
- package/addon/routes/settings/telematics.js +21 -0
- package/addon/routes/virtual.js +11 -0
- package/addon/routes.js +1 -0
- package/addon/templates/settings/telematics.hbs +70 -0
- package/app/components/admin/telematics-settings.js +1 -0
- package/app/components/map/marker-card/driver.js +1 -0
- package/app/components/map/marker-card/vehicle.js +1 -0
- package/app/controllers/settings/telematics.js +1 -0
- package/app/routes/settings/telematics.js +1 -0
- package/app/templates/settings/telematics.js +1 -0
- package/composer.json +2 -2
- package/docs/AFAQY.md +1 -1
- package/docs/TELEMATICS_QUEUES.md +1 -1
- package/docs/TELEMETRY_ARCHITECTURE.md +72 -1
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/config/telemetry.php +12 -0
- package/server/migrations/2026_09_23_000001_add_retention_index_to_device_events.php +40 -0
- package/server/migrations/2026_09_23_000002_add_retention_index_to_positions.php +40 -0
- package/server/migrations/2026_09_23_000003_add_retention_index_to_telematic_sync_runs.php +40 -0
- package/server/src/Auth/Schemas/FleetOps.php +104 -5
- package/server/src/Console/Commands/DrainTelematicInbox.php +3 -13
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +3 -3
- package/server/src/Console/Commands/PruneTelematicsData.php +318 -0
- package/server/src/Http/Controllers/Api/v1/OrchestrationController.php +9 -0
- package/server/src/Http/Controllers/FleetOpsController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/CustomerController.php +14 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderConnectionController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderTransactionController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +9 -3
- package/server/src/Http/Controllers/Internal/v1/InspectionFormController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +16 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/ManifestController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/MetricsController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +42 -1
- package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +12 -0
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/PaymentController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/RadarController.php +19 -0
- package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +9 -3
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +465 -14
- package/server/src/Http/Controllers/Internal/v1/TelematicController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/TrailerController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/VendorController.php +17 -0
- package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +11 -0
- package/server/src/Jobs/DispatchTelematicsRetentionJobs.php +70 -0
- package/server/src/Jobs/PruneTelematicsDataJob.php +74 -0
- package/server/src/Listeners/NotifyDriverOnShiftChange.php +3 -3
- package/server/src/Mail/CustomerCredentialsMail.php +1 -1
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +9 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +3 -0
- package/server/src/Support/Analytics/LiveFleet.php +18 -2
- package/server/src/Support/Authorization.php +103 -0
- package/server/src/Support/Database/TableIndexes.php +66 -0
- package/server/src/Support/OrderTracker.php +2 -2
- package/server/src/Support/Reporting/FleetOpsReportSchema.php +476 -116
- package/server/src/Support/Telematics/Retention/RetentionPolicy.php +300 -0
- package/server/src/Support/Telematics/Retention/TelemetryActivity.php +40 -0
- package/server/src/Support/Telematics/TelematicService.php +12 -2
- package/server/src/Support/Telematics/Telemetry/Ingestor.php +4 -2
- package/server/src/Tracking/TrackingIntelligenceService.php +1 -1
- package/server/src/Tracking/TrackingOptions.php +2 -2
- package/server/src/Traits/AuthorizesMethods.php +37 -0
- package/server/src/routes.php +9 -1
- package/server/tests/AnalyticsRoutesTest.php +29 -2
- package/server/tests/Feature/Http/AfaqyRealtimeIngestionTest.php +16 -1
- package/server/tests/Feature/Http/Api/TelematicsRetentionIndexMigrationTest.php +115 -0
- package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +71 -0
- package/server/tests/Feature/Http/Internal/TelematicsStorageDeadlinesTest.php +119 -0
- package/server/tests/InternalImportExportControllerContractsTest.php +5 -8
- package/server/tests/NavigatorControllerContractsTest.php +36 -4
- package/server/tests/NotificationAndMailContractsTest.php +31 -0
- package/server/tests/ObserverContractsTest.php +1 -1
- package/server/tests/OrchestratorConsumableApiTest.php +42 -0
- package/server/tests/ProviderContractsTest.php +10 -0
- package/server/tests/ReportSchemaContractsTest.php +120 -6
- package/server/tests/SettingControllerContractsTest.php +429 -18
- package/server/tests/SmallControllerContractsTest.php +8 -5
- package/server/tests/Support/PruneTelematicsDataProbe.php +55 -0
- package/server/tests/Unit/Console/Commands/ProcessOperationalAlertsCommandTest.php +2 -2
- package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +353 -0
- package/server/tests/Unit/Jobs/DispatchTelematicsRetentionJobsTest.php +114 -0
- package/server/tests/Unit/Jobs/PruneTelematicsDataJobTest.php +60 -0
- package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +20 -0
- package/server/tests/Unit/Support/Analytics/LiveFleetTest.php +6 -0
- package/server/tests/Unit/Support/AuthorizationTest.php +142 -0
- package/server/tests/Unit/Support/MaintainableAndOperationalAlertsTest.php +12 -1
- package/server/tests/Unit/Support/MoreQuerySeamsTest.php +11 -2
- package/server/tests/Unit/Support/Telematics/Retention/RetentionPolicyTest.php +190 -0
- package/server/tests/Unit/Support/Telematics/Retention/TelemetryActivityTest.php +68 -0
- package/server/tests/Unit/Tracking/TrackingOptionsCompanySettingsTest.php +109 -0
- package/translations/en-us.yaml +48 -0
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class ManagementFuelTransactionsRoute extends Route {
|
|
4
|
+
export default class ManagementFuelTransactionsRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops list fuel-provider-transaction')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
4
|
export default class ManagementIndexRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops list driver')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
4
17
|
queryParams = {
|
|
5
18
|
view: { refreshModel: false },
|
|
6
19
|
status: { refreshModel: false },
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
|
|
4
|
+
export default class ManagementTrailersRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops list trailer')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class ManagementVendorsIntegratedDetailsRoute extends Route {
|
|
4
|
+
export default class ManagementVendorsIntegratedDetailsRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops view integrated-vendor')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops.management.vendors.index');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class ManagementVendorsIntegratedEditRoute extends Route {
|
|
4
|
+
export default class ManagementVendorsIntegratedEditRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops update integrated-vendor')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops.management.vendors.index');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class ManagementVendorsIntegratedNewRoute extends Route {
|
|
4
|
+
export default class ManagementVendorsIntegratedNewRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops create integrated-vendor')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops.management.vendors.index');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class ManagementVendorsIntegratedRoute extends Route {
|
|
4
|
+
export default class ManagementVendorsIntegratedRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops list integrated-vendor')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops.management.vendors.index');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,42 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Orders are the FleetOps landing route (`console.fleet-ops` resolves here), so a user
|
|
6
|
+
* without `fleet-ops list order` cannot be sent back to `console.fleet-ops` - that would
|
|
7
|
+
* loop. Instead they are forwarded to the first FleetOps area they are permitted to list,
|
|
8
|
+
* falling back to the console when there is none.
|
|
9
|
+
*/
|
|
10
|
+
const FALLBACK_ROUTES = [
|
|
11
|
+
['fleet-ops list driver', 'console.fleet-ops.management.drivers'],
|
|
12
|
+
['fleet-ops list vehicle', 'console.fleet-ops.management.vehicles'],
|
|
13
|
+
['fleet-ops list trailer', 'console.fleet-ops.management.trailers'],
|
|
14
|
+
['fleet-ops list fleet', 'console.fleet-ops.management.fleets'],
|
|
15
|
+
['fleet-ops list place', 'console.fleet-ops.management.places'],
|
|
16
|
+
['fleet-ops list contact', 'console.fleet-ops.management.contacts'],
|
|
17
|
+
['fleet-ops list vendor', 'console.fleet-ops.management.vendors'],
|
|
18
|
+
['fleet-ops list fuel-report', 'console.fleet-ops.management.fuel-reports'],
|
|
19
|
+
['fleet-ops list issue', 'console.fleet-ops.management.issues'],
|
|
20
|
+
['fleet-ops list work-order', 'console.fleet-ops.maintenance.work-orders'],
|
|
21
|
+
['fleet-ops list device', 'console.fleet-ops.connectivity.devices'],
|
|
22
|
+
['iam list report', 'console.fleet-ops.analytics.reports'],
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export default class OperationsOrdersRoute extends Route {
|
|
26
|
+
@service notifications;
|
|
27
|
+
@service hostRouter;
|
|
28
|
+
@service abilities;
|
|
29
|
+
@service intl;
|
|
30
|
+
|
|
31
|
+
beforeModel() {
|
|
32
|
+
if (this.abilities.cannot('fleet-ops list order')) {
|
|
33
|
+
const fallback = FALLBACK_ROUTES.find(([permission]) => this.abilities.can(permission));
|
|
34
|
+
if (fallback) {
|
|
35
|
+
return this.hostRouter.transitionTo(fallback[1]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
39
|
+
return this.hostRouter.transitionTo('console');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class OperationsRoutesIndexDetailsRoute extends Route {
|
|
4
|
+
export default class OperationsRoutesIndexDetailsRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops view route')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops.operations.routes.index');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
4
|
export default class OperationsRoutesIndexNewRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops create route')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops.operations.routes.index');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
4
17
|
queryParams = {
|
|
5
18
|
selectedOrders: {
|
|
6
19
|
refreshModel: false,
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class OperationsRoutesRoute extends Route {
|
|
4
|
+
export default class OperationsRoutesRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops list route')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -3,6 +3,17 @@ import { inject as service } from '@ember/service';
|
|
|
3
3
|
|
|
4
4
|
export default class OperationsServiceRatesIndexNewRoute extends Route {
|
|
5
5
|
@service store;
|
|
6
|
+
@service notifications;
|
|
7
|
+
@service hostRouter;
|
|
8
|
+
@service abilities;
|
|
9
|
+
@service intl;
|
|
10
|
+
|
|
11
|
+
beforeModel() {
|
|
12
|
+
if (this.abilities.cannot('fleet-ops create service-rate')) {
|
|
13
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
14
|
+
return this.hostRouter.transitionTo('console.fleet-ops.operations.service-rates.index');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
6
17
|
|
|
7
18
|
async setupController(controller) {
|
|
8
19
|
super.setupController(...arguments);
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class OperationsServiceRatesRoute extends Route {
|
|
4
|
+
export default class OperationsServiceRatesRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops list service-rate')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class SettingsAvatarsRoute extends Route {
|
|
4
|
+
export default class SettingsAvatarsRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops list avatar')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class SettingsCustomFieldsRoute extends Route {
|
|
4
|
+
export default class SettingsCustomFieldsRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops list custom-field')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class SettingsMapRoute extends Route {
|
|
4
|
+
export default class SettingsMapRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops view map-settings')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -4,6 +4,17 @@ import { hash } from 'rsvp';
|
|
|
4
4
|
|
|
5
5
|
export default class SettingsNotificationsRoute extends Route {
|
|
6
6
|
@service fetch;
|
|
7
|
+
@service notifications;
|
|
8
|
+
@service hostRouter;
|
|
9
|
+
@service abilities;
|
|
10
|
+
@service intl;
|
|
11
|
+
|
|
12
|
+
beforeModel() {
|
|
13
|
+
if (this.abilities.cannot('fleet-ops view notification-settings')) {
|
|
14
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
15
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
7
18
|
|
|
8
19
|
model() {
|
|
9
20
|
return hash({
|
|
@@ -14,7 +14,7 @@ export default class SettingsOrchestratorRoute extends Route {
|
|
|
14
14
|
@service hostRouter;
|
|
15
15
|
|
|
16
16
|
beforeModel() {
|
|
17
|
-
if (this.abilities.cannot('fleet-ops
|
|
17
|
+
if (this.abilities.cannot('fleet-ops view routing-settings')) {
|
|
18
18
|
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
19
19
|
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
20
20
|
}
|
|
@@ -16,7 +16,7 @@ export default class SettingsPaymentsIndexRoute extends Route {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
beforeModel() {
|
|
19
|
-
if (this.abilities.cannot('fleet-ops
|
|
19
|
+
if (this.abilities.cannot('fleet-ops view payments')) {
|
|
20
20
|
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
21
21
|
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
22
22
|
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class SettingsRoutingRoute extends Route {
|
|
4
|
+
export default class SettingsRoutingRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops view routing-settings')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
2
3
|
|
|
3
|
-
export default class SettingsSchedulingRoute extends Route {
|
|
4
|
+
export default class SettingsSchedulingRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops view scheduling-settings')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Route from '@ember/routing/route';
|
|
2
|
+
import { inject as service } from '@ember/service';
|
|
3
|
+
|
|
4
|
+
export default class SettingsTelematicsRoute extends Route {
|
|
5
|
+
@service notifications;
|
|
6
|
+
@service hostRouter;
|
|
7
|
+
@service abilities;
|
|
8
|
+
@service intl;
|
|
9
|
+
|
|
10
|
+
beforeModel() {
|
|
11
|
+
if (this.abilities.cannot('fleet-ops view telematics-settings')) {
|
|
12
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
13
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
setupController(controller) {
|
|
18
|
+
super.setupController(...arguments);
|
|
19
|
+
controller.getSettings.perform();
|
|
20
|
+
}
|
|
21
|
+
}
|
package/addon/routes/virtual.js
CHANGED
|
@@ -4,6 +4,10 @@ import { inject as service } from '@ember/service';
|
|
|
4
4
|
export default class VirtualRoute extends Route {
|
|
5
5
|
@service universe;
|
|
6
6
|
@service('universe/menu-service') menuService;
|
|
7
|
+
@service notifications;
|
|
8
|
+
@service hostRouter;
|
|
9
|
+
@service abilities;
|
|
10
|
+
@service intl;
|
|
7
11
|
|
|
8
12
|
queryParams = {
|
|
9
13
|
view: {
|
|
@@ -15,4 +19,11 @@ export default class VirtualRoute extends Route {
|
|
|
15
19
|
const view = this.universe.getViewFromTransition(transition);
|
|
16
20
|
return this.menuService.lookupMenuItem('engine:fleet-ops', slug, view, section);
|
|
17
21
|
}
|
|
22
|
+
|
|
23
|
+
afterModel(menuItem) {
|
|
24
|
+
if (menuItem?.permission && this.abilities.cannot(menuItem.permission)) {
|
|
25
|
+
this.notifications.warning(this.intl.t('common.unauthorized-access'));
|
|
26
|
+
return this.hostRouter.transitionTo('console.fleet-ops');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
18
29
|
}
|
package/addon/routes.js
CHANGED
|
@@ -323,6 +323,7 @@ export default buildRoutes(function () {
|
|
|
323
323
|
this.route('map');
|
|
324
324
|
this.route('orchestrator');
|
|
325
325
|
this.route('scheduling');
|
|
326
|
+
this.route('telematics');
|
|
326
327
|
this.route('payments', function () {
|
|
327
328
|
this.route('index', { path: '/' });
|
|
328
329
|
this.route('onboard');
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<Layout::Section::Header @title={{t "settings.telematics.telematics-settings"}}>
|
|
2
|
+
<Button
|
|
3
|
+
@type="primary"
|
|
4
|
+
@size="sm"
|
|
5
|
+
@icon="save"
|
|
6
|
+
@text={{t "common.save-changes"}}
|
|
7
|
+
@onClick={{perform this.saveSettings}}
|
|
8
|
+
@disabled={{or this.saveSettings.isRunning this.getSettings.isRunning (not this.settingsLoaded)}}
|
|
9
|
+
@isLoading={{or this.saveSettings.isRunning this.getSettings.isRunning}}
|
|
10
|
+
@permission="fleet-ops update telematics-settings"
|
|
11
|
+
/>
|
|
12
|
+
</Layout::Section::Header>
|
|
13
|
+
<Layout::Section::Body class="overflow-y-scroll-i h-full">
|
|
14
|
+
<div class="container mx-auto">
|
|
15
|
+
<div class="max-w-3xl my-10 mx-auto space-y-6">
|
|
16
|
+
<InfoBlock @type="info" @icon="circle-info">
|
|
17
|
+
{{t "settings.telematics.intro"}}
|
|
18
|
+
</InfoBlock>
|
|
19
|
+
|
|
20
|
+
<ContentPanel @title={{t "settings.telematics.device-events"}} @open={{true}} @wrapperClass="bordered-classic">
|
|
21
|
+
<InputGroup>
|
|
22
|
+
<Toggle
|
|
23
|
+
@label={{t "settings.telematics.use-system-default"}}
|
|
24
|
+
@isToggled={{this.useDefaultEventRetention}}
|
|
25
|
+
@onToggle={{this.setUseDefaultEventRetention}}
|
|
26
|
+
@disabled={{not this.settingsLoaded}}
|
|
27
|
+
/>
|
|
28
|
+
</InputGroup>
|
|
29
|
+
<InputGroup @name={{t "settings.telematics.event-retention-days"}} @helpText={{t "settings.telematics.event-retention-days-help"}}>
|
|
30
|
+
<Input
|
|
31
|
+
@type="number"
|
|
32
|
+
@value={{this.eventRetentionDays}}
|
|
33
|
+
min={{this.eventRetentionMinimum}}
|
|
34
|
+
max={{this.eventRetentionMaximum}}
|
|
35
|
+
disabled={{or this.useDefaultEventRetention (not this.settingsLoaded)}}
|
|
36
|
+
class="w-full form-input"
|
|
37
|
+
/>
|
|
38
|
+
</InputGroup>
|
|
39
|
+
{{#if this.settingsLoaded}}
|
|
40
|
+
<p class="text-xs text-gray-500 dark:text-gray-400">{{this.eventRetentionPolicyHelp}}</p>
|
|
41
|
+
{{/if}}
|
|
42
|
+
</ContentPanel>
|
|
43
|
+
|
|
44
|
+
<ContentPanel @title={{t "settings.telematics.positions"}} @open={{true}} @wrapperClass="bordered-classic">
|
|
45
|
+
<InputGroup>
|
|
46
|
+
<Toggle
|
|
47
|
+
@label={{t "settings.telematics.use-system-default"}}
|
|
48
|
+
@isToggled={{this.useDefaultPositionRetention}}
|
|
49
|
+
@onToggle={{this.setUseDefaultPositionRetention}}
|
|
50
|
+
@disabled={{not this.settingsLoaded}}
|
|
51
|
+
/>
|
|
52
|
+
</InputGroup>
|
|
53
|
+
<InputGroup @name={{t "settings.telematics.position-retention-days"}} @helpText={{t "settings.telematics.position-retention-days-help"}}>
|
|
54
|
+
<Input
|
|
55
|
+
@type="number"
|
|
56
|
+
@value={{this.positionRetentionDays}}
|
|
57
|
+
min={{this.positionRetentionMinimum}}
|
|
58
|
+
max={{this.positionRetentionMaximum}}
|
|
59
|
+
disabled={{or this.useDefaultPositionRetention (not this.settingsLoaded)}}
|
|
60
|
+
class="w-full form-input"
|
|
61
|
+
/>
|
|
62
|
+
</InputGroup>
|
|
63
|
+
{{#if this.settingsLoaded}}
|
|
64
|
+
<p class="text-xs text-gray-500 dark:text-gray-400">{{this.positionRetentionPolicyHelp}}</p>
|
|
65
|
+
{{/if}}
|
|
66
|
+
</ContentPanel>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
<Spacer @height="200px" />
|
|
70
|
+
</Layout::Section::Body>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/admin/telematics-settings';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/map/marker-card/driver';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/map/marker-card/vehicle';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/controllers/settings/telematics';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/routes/settings/telematics';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/templates/settings/telematics';
|
package/composer.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fleetbase/fleetops-api",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.70",
|
|
4
4
|
"description": "Fleet & Transport Management Extension for Fleetbase",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fleetbase-extension",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"barryvdh/laravel-dompdf": "^3.1",
|
|
26
26
|
"brick/geo": "0.7.2",
|
|
27
27
|
"cknow/laravel-money": "^7.1",
|
|
28
|
-
"fleetbase/core-api": "
|
|
28
|
+
"fleetbase/core-api": ">=1.6.65",
|
|
29
29
|
"geocoder-php/google-maps-places-provider": "^1.4",
|
|
30
30
|
"giggsey/libphonenumber-for-php": "^8.13",
|
|
31
31
|
"league/geotools": "^1.1.0",
|
package/docs/AFAQY.md
CHANGED
|
@@ -57,7 +57,7 @@ Existing provider interfaces and vehicle/trailer event names remain compatible.
|
|
|
57
57
|
|
|
58
58
|
The public receiver remains `POST webhooks/telematics/afaqy?telematic=...&key=...` under the application's API prefix. A new `device.telemetry_updated` broadcast identifies the device; an open device panel reloads its authorized resource and refetches after socket reconnection. Company broadcast identity comes from the persisted asset, not a worker session. Map movement uses the existing vehicle/trailer events, rejects older source timestamps, and reloads visible telemetry assets after socket reconnection with at most five concurrent requests.
|
|
59
59
|
|
|
60
|
-
Configure shared queues, retention, limits, and freshness under `telematics.telemetry` using `server/config/telemetry.php`. `TELEMATICS_BATCH_SIZE` controls units per ingestion delivery (default 100); `TELEMATICS_REQUEST_TIMEOUT_SECONDS` controls the bounded polling request timeout (default 45 seconds). AFAQY's adapter switches and optional queue overrides remain under `telematics.afaqy` in `server/config/afaqy.php`. Defaults: two MiB per webhook, 10,000 pending deliveries per connection, processed
|
|
60
|
+
Configure shared queues, retention, limits, and freshness under `telematics.telemetry` using `server/config/telemetry.php`. `TELEMATICS_BATCH_SIZE` controls units per ingestion delivery (default 100); `TELEMATICS_REQUEST_TIMEOUT_SECONDS` controls the bounded polling request timeout (default 45 seconds). AFAQY's adapter switches and optional queue overrides remain under `telematics.afaqy` in `server/config/afaqy.php`. Defaults: two MiB per webhook, 10,000 pending deliveries per connection, stale-position thresholds 120 seconds with ignition on and 600 seconds with ignition off/unknown. Retention (processed payloads 24 hours, quarantined deliveries seven days, device events 30 days, positions 90 days) is applied by `fleetops:prune-telematics-data`. Administrators configure retention policy, logging, system storage diagnostics and system cleanup in Admin → Fleet-Ops Config → Telematics. Organizations choose only event and position history preferences within those limits in Fleet-Ops → Settings → Telematics; config values are the fallback. See `docs/TELEMETRY_ARCHITECTURE.md` § Retention. Each device's metadata records the effective threshold. Connection status categories remain unchanged.
|
|
61
61
|
|
|
62
62
|
## Incident verification
|
|
63
63
|
|
|
@@ -14,7 +14,7 @@ nothing changes: every job and broadcast stays on the same queue as before.
|
|
|
14
14
|
| Setting | Default | Work routed |
|
|
15
15
|
| --- | --- | --- |
|
|
16
16
|
| `TELEMATICS_POLL_QUEUE` | `default` | Scheduled and manual polls (`PollTelematicTelemetry`), legacy device discovery (`SyncTelematicDevicesJob`), and queued connection tests (`TestTelematicConnectionJob`). |
|
|
17
|
-
| `TELEMATICS_INGESTION_QUEUE` | `default` | Applying polled or pushed positions (`ProcessTelematicDelivery`), including jobs re-queued by `fleetops:drain-telematic-inbox` and manual replays. |
|
|
17
|
+
| `TELEMATICS_INGESTION_QUEUE` | `default` | Applying polled or pushed positions (`ProcessTelematicDelivery`), including jobs re-queued by `fleetops:drain-telematic-inbox` and manual replays, and on-demand retention runs (`PruneTelematicsDataJob`, queued by "Run system cleanup" in Admin → Fleet-Ops Config → Telematics). |
|
|
18
18
|
| `TELEMATICS_BROADCAST_QUEUE` | unset | Live-map broadcasts created by telematics ingestion: `DeviceTelemetryUpdated`, and `VehicleLocationChanged` / `TrailerLocationChanged` when a device is attached. When unset, broadcasts use the queue connection's default queue. |
|
|
19
19
|
|
|
20
20
|
`TELEMATICS_BROADCAST_QUEUE` affects only broadcasts that telematics ingestion
|