@fleetbase/fleetops-engine 0.6.68 → 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 +44 -9
- package/addon/components/admin/telematics-settings.hbs +143 -0
- package/addon/components/admin/telematics-settings.js +145 -0
- package/addon/components/contact/form.hbs +13 -2
- package/addon/components/customer/details.hbs +17 -17
- package/addon/components/customer/form.hbs +13 -2
- package/addon/components/customer/form.js +0 -56
- package/addon/components/driver/details.hbs +13 -19
- package/addon/components/driver/form.hbs +20 -35
- package/addon/components/driver/form.js +0 -58
- 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/modals/driver-form.hbs +2 -2
- package/addon/components/modals/reset-profile-credentials.hbs +23 -0
- package/addon/components/modals/reset-profile-credentials.js +70 -0
- package/addon/components/profile-identity-hint.hbs +13 -0
- package/addon/components/profile-identity-hint.js +49 -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 +8 -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 +42 -8
- 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/services/contact-actions.js +50 -89
- package/addon/services/driver-actions.js +98 -0
- package/addon/templates/settings/telematics.hbs +70 -0
- package/addon/utils/profile-login-actions.js +172 -0
- package/app/components/admin/telematics-settings.js +1 -0
- package/app/components/{modals/reset-customer-credentials.js → map/marker-card/driver.js} +1 -1
- package/app/components/map/marker-card/vehicle.js +1 -0
- package/app/components/modals/reset-profile-credentials.js +1 -0
- package/app/components/profile-identity-hint.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 +3 -3
- package/scripts/pest-bootstrap.php +12 -0
- package/server/config/telemetry.php +12 -0
- package/server/migrations/2026_09_21_000001_convert_profile_only_users_to_managed_accounts.php +132 -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/resources/views/mail/driver-credentials.blade.php +21 -0
- package/server/src/Auth/Schemas/FleetOps.php +104 -5
- package/server/src/Console/Commands/DrainTelematicInbox.php +3 -13
- package/server/src/Console/Commands/FixCustomerCompanies.php +1 -1
- package/server/src/Console/Commands/FixDriverCompanies.php +1 -1
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +3 -3
- package/server/src/Console/Commands/PruneTelematicsData.php +318 -0
- package/server/src/Exceptions/ProfileIdentityConflictException.php +34 -0
- package/server/src/Http/Controllers/Api/v1/CustomerController.php +14 -0
- package/server/src/Http/Controllers/Api/v1/DriverController.php +56 -39
- 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 +16 -17
- package/server/src/Http/Controllers/Internal/v1/CustomerController.php +54 -4
- 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 +204 -162
- package/server/src/Http/Controllers/Internal/v1/FleetOpsLookupController.php +47 -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 +178 -27
- 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/Http/Requests/CreateDriverRequest.php +6 -2
- package/server/src/Http/Requests/Internal/CreateDriverRequest.php +9 -18
- package/server/src/Http/Resources/v1/Contact.php +3 -0
- package/server/src/Http/Resources/v1/Driver.php +3 -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/Mail/DriverCredentialsMail.php +55 -0
- package/server/src/Models/Contact.php +55 -90
- package/server/src/Models/Sensor.php +3 -5
- package/server/src/Observers/ContactObserver.php +2 -22
- package/server/src/Observers/DriverObserver.php +5 -6
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +9 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +18 -0
- package/server/src/Support/Ai/Capabilities/AbstractFleetOpsAICapability.php +62 -5
- package/server/src/Support/Ai/Capabilities/AssetStatusCapability.php +24 -5
- package/server/src/Support/Ai/Capabilities/CreateOrderPreviewCapability.php +6 -2
- package/server/src/Support/Ai/Capabilities/OrderInsightsCapability.php +40 -7
- package/server/src/Support/Ai/Capabilities/SearchResourcesCapability.php +86 -24
- package/server/src/Support/Ai/FleetOpsAiConsoleCommands.php +122 -0
- package/server/src/Support/Ai/Tools/CreateOrderTool.php +86 -0
- package/server/src/Support/Ai/Tools/ImportOrdersTool.php +53 -0
- package/server/src/Support/Ai/Tools/OptimizeOrderRouteTool.php +70 -0
- package/server/src/Support/Ai/Tools/SearchResourcesTool.php +73 -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/ProfileAccountManager.php +405 -0
- 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 +14 -1
- package/server/tests/AiOperationalQueryCapabilityTest.php +1 -0
- package/server/tests/AnalyticsRoutesTest.php +29 -2
- package/server/tests/ApiCustomerControllerContractsTest.php +21 -0
- package/server/tests/ApiDriverControllerContractsTest.php +102 -20
- package/server/tests/CommandContractsTest.php +4 -4
- package/server/tests/ControllerHelperContractsTest.php +3 -11
- package/server/tests/Feature/Http/AfaqyRealtimeIngestionTest.php +21 -1
- package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +36 -0
- package/server/tests/Feature/Http/Api/DriverControllerSessionHelpersTest.php +19 -6
- package/server/tests/Feature/Http/Api/ProfileOnlyUserConversionMigrationTest.php +201 -0
- package/server/tests/Feature/Http/Api/TelematicsRetentionIndexMigrationTest.php +115 -0
- package/server/tests/Feature/Http/Internal/ContactControllerEndpointsTest.php +6 -4
- package/server/tests/Feature/Http/Internal/CustomerControllerCredentialsTest.php +6 -2
- package/server/tests/Feature/Http/Internal/DriverControllerContractsTest.php +23 -0
- package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +42 -17
- package/server/tests/Feature/Http/Internal/DriverControllerExistingUserAdoptionTest.php +168 -277
- package/server/tests/Feature/Http/Internal/DriverControllerLoginManagementTest.php +716 -0
- package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +10 -3
- package/server/tests/Feature/Http/Internal/OrderControllerImportFromFilesTest.php +18 -0
- package/server/tests/Feature/Http/Internal/OrderControllerTenantScopingTest.php +411 -0
- package/server/tests/Feature/Http/Internal/OrderControllerUpstreamNotFoundTest.php +8 -20
- package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +71 -0
- package/server/tests/Feature/Http/Internal/TelematicsStorageDeadlinesTest.php +119 -0
- package/server/tests/InternalCustomerControllerContractsTest.php +32 -1
- package/server/tests/InternalImportExportControllerContractsTest.php +5 -8
- package/server/tests/ModelAccessorContractsTest.php +82 -20
- package/server/tests/NavigatorControllerContractsTest.php +36 -4
- package/server/tests/NotificationAndMailContractsTest.php +31 -0
- package/server/tests/ObserverContractsTest.php +28 -3
- package/server/tests/OrchestratorConsumableApiTest.php +42 -0
- package/server/tests/ProviderContractsTest.php +10 -0
- package/server/tests/ReportSchemaContractsTest.php +120 -6
- package/server/tests/RequestContractsTest.php +19 -11
- 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/SupportJobAndAiCoverageTest.php +3 -3
- package/server/tests/TelematicControllerContractsTest.php +22 -4
- 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/Models/ContactCustomerUserTest.php +90 -14
- package/server/tests/Unit/Models/ContactTest.php +48 -5
- package/server/tests/Unit/Models/SensorTest.php +2 -2
- package/server/tests/Unit/Models/SmallModelSurfacesTest.php +31 -32
- package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +7 -2
- package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +20 -0
- package/server/tests/Unit/Providers/FleetOpsAiRegistrationTest.php +15 -2
- package/server/tests/Unit/Support/Ai/AssetStatusCapabilityQueriesTest.php +42 -0
- package/server/tests/Unit/Support/Ai/Capabilities/OrderInsightsCapabilityTest.php +19 -1
- package/server/tests/Unit/Support/Ai/Capabilities/SearchResourcesCapabilityTest.php +85 -1
- package/server/tests/Unit/Support/Ai/FleetOpsAiConsoleCommandsTest.php +31 -0
- package/server/tests/Unit/Support/Ai/Tools/FleetOpsAiToolsTest.php +246 -0
- package/server/tests/Unit/Support/AiCapabilityPermissionsTest.php +3 -3
- 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/ProfileAccountManagerTest.php +643 -0
- 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 +85 -2
- package/translations/uk-ua.yaml +3475 -0
- package/addon/components/modals/reset-customer-credentials.hbs +0 -18
- package/addon/components/modals/reset-customer-credentials.js +0 -55
|
@@ -1,39 +1,4 @@
|
|
|
1
1
|
<div class="form-wrapper" ...attributes>
|
|
2
|
-
<ContentPanel @title={{t "driver.fields.user-account"}} @open={{true}} @actionButtons={{this.userAccountActionButtons}} @wrapperClass="bordered-top">
|
|
3
|
-
<div class="space-y-2">
|
|
4
|
-
<InputGroup @name={{t "driver.fields.user-account"}} @helpText={{t "driver.fields.user-account-help-text"}}>
|
|
5
|
-
<ModelSelect
|
|
6
|
-
@modelName="user"
|
|
7
|
-
@selectedItemComponent={{component "select-option/user" compact=true}}
|
|
8
|
-
@selectedModel={{@resource.user}}
|
|
9
|
-
@placeholder={{t "driver.fields.select-user"}}
|
|
10
|
-
@query={{hash doesnt_have_driver=true can_be_driver=true}}
|
|
11
|
-
@triggerClass="form-select form-input"
|
|
12
|
-
@infiniteScroll={{false}}
|
|
13
|
-
@renderInPlace={{true}}
|
|
14
|
-
@onChange={{fn (mut @resource.user)}}
|
|
15
|
-
@permission="fleet-ops update-user-for driver"
|
|
16
|
-
as |model|
|
|
17
|
-
>
|
|
18
|
-
<SelectOption::User @option={{model}} />
|
|
19
|
-
</ModelSelect>
|
|
20
|
-
</InputGroup>
|
|
21
|
-
{{#if @resource.user}}
|
|
22
|
-
<div class="grid grid-cols-1 lg:grid-cols-2 gap-2 no-input-group-padding">
|
|
23
|
-
<InputGroup @name={{t "common.name"}} @wrapperClass="col-span-2 mb-0i">
|
|
24
|
-
<Input @value={{@resource.user.name}} @type="text" class="w-full form-input" placeholder={{t "common.name"}} disabled={{true}} />
|
|
25
|
-
</InputGroup>
|
|
26
|
-
<InputGroup @name={{t "common.email"}} @wrapperClass="mb-0i">
|
|
27
|
-
<Input @value={{@resource.user.email}} @type="text" class="w-full form-input" placeholder={{t "common.email"}} disabled={{true}} />
|
|
28
|
-
</InputGroup>
|
|
29
|
-
<InputGroup @name={{t "common.phone"}} @wrapperClass="mb-0i">
|
|
30
|
-
<PhoneInput @value={{@resource.user.phone}} @onInput={{fn (mut @resource.phone)}} class="form-input w-full" disabled={{true}} />
|
|
31
|
-
</InputGroup>
|
|
32
|
-
</div>
|
|
33
|
-
{{/if}}
|
|
34
|
-
</div>
|
|
35
|
-
</ContentPanel>
|
|
36
|
-
|
|
37
2
|
<ContentPanel @title={{t "driver.fields.driver-details"}} @open={{true}} @wrapperClass="bordered-top">
|
|
38
3
|
<div class="flex flex-row space-x-3 mb-3">
|
|
39
4
|
<div class="flex items-center justify-start rounded-full">
|
|
@@ -65,6 +30,26 @@
|
|
|
65
30
|
</div>
|
|
66
31
|
</div>
|
|
67
32
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-2 text-xs no-input-group-padding">
|
|
33
|
+
<InputGroup @name={{t "common.name"}} @required={{true}}>
|
|
34
|
+
<Input @value={{@resource.name}} @type="text" class="w-full form-input" placeholder={{t "common.name"}} disabled={{cannot-write @resource}} />
|
|
35
|
+
</InputGroup>
|
|
36
|
+
<InputGroup @name={{t "common.email"}}>
|
|
37
|
+
<Input
|
|
38
|
+
@value={{@resource.email}}
|
|
39
|
+
@type="text"
|
|
40
|
+
class="w-full form-input"
|
|
41
|
+
placeholder={{t "common.email"}}
|
|
42
|
+
disabled={{or (cannot-write @resource) @resource.is_staff_linked}}
|
|
43
|
+
/>
|
|
44
|
+
</InputGroup>
|
|
45
|
+
<InputGroup @name={{t "common.phone"}}>
|
|
46
|
+
<PhoneInput @value={{@resource.phone}} @onInput={{fn (mut @resource.phone)}} class="form-input w-full" disabled={{or (cannot-write @resource) @resource.is_staff_linked}} />
|
|
47
|
+
</InputGroup>
|
|
48
|
+
{{#if @resource.is_staff_linked}}
|
|
49
|
+
<div class="lg:col-span-2 -mt-1 mb-2 text-xs text-gray-500 dark:text-gray-400" data-test-staff-linked-helper>{{t "profile-account.staff-linked-helper"}}</div>
|
|
50
|
+
{{else if @resource.isNew}}
|
|
51
|
+
<ProfileIdentityHint @email={{@resource.email}} @phone={{@resource.phone}} @type="driver" class="lg:col-span-2" />
|
|
52
|
+
{{/if}}
|
|
68
53
|
<InputGroup @name={{t "common.internal-id"}}>
|
|
69
54
|
<Input @value={{@resource.internal_id}} @type="text" class="w-full form-input" placeholder={{t "common.internal-id"}} disabled={{cannot-write @resource}} />
|
|
70
55
|
</InputGroup>
|
|
@@ -3,67 +3,9 @@ import { inject as service } from '@ember/service';
|
|
|
3
3
|
import { task } from 'ember-concurrency';
|
|
4
4
|
|
|
5
5
|
export default class DriverFormComponent extends Component {
|
|
6
|
-
@service store;
|
|
7
6
|
@service fetch;
|
|
8
7
|
@service currentUser;
|
|
9
8
|
@service notifications;
|
|
10
|
-
@service modalsManager;
|
|
11
|
-
@service('universe/extension-manager') extensionManager;
|
|
12
|
-
|
|
13
|
-
get userAccountActionButtons() {
|
|
14
|
-
return [
|
|
15
|
-
{
|
|
16
|
-
icon: 'user-plus',
|
|
17
|
-
size: 'xs',
|
|
18
|
-
permission: 'iam create user',
|
|
19
|
-
onClick: async () => {
|
|
20
|
-
// Load IAM engine for user-form modal component
|
|
21
|
-
await this.extensionManager.ensureEngineLoaded('@fleetbase/iam-engine');
|
|
22
|
-
|
|
23
|
-
const user = this.store.createRecord('user', {
|
|
24
|
-
status: 'pending',
|
|
25
|
-
type: 'user',
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
this.modalsManager.show('modals/user-form', {
|
|
29
|
-
title: 'Create a new user',
|
|
30
|
-
user,
|
|
31
|
-
formPermission: 'iam create user',
|
|
32
|
-
uploadNewPhoto: (file) => {
|
|
33
|
-
this.fetch.uploadFile.perform(
|
|
34
|
-
file,
|
|
35
|
-
{
|
|
36
|
-
path: `uploads/${this.currentUser.companyId}/users/${user.slug}`,
|
|
37
|
-
subject_uui: user.id,
|
|
38
|
-
subject_type: 'user',
|
|
39
|
-
type: 'user_photo',
|
|
40
|
-
},
|
|
41
|
-
(uploadedFile) => {
|
|
42
|
-
user.setProperties({
|
|
43
|
-
avatar_uuid: uploadedFile.id,
|
|
44
|
-
avatar_url: uploadedFile.url,
|
|
45
|
-
avatar: uploadedFile,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
},
|
|
50
|
-
confirm: async (modal) => {
|
|
51
|
-
modal.startLoading();
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
await user.save();
|
|
55
|
-
this.notifications.success('New user created successfully!');
|
|
56
|
-
modal.done();
|
|
57
|
-
} catch (error) {
|
|
58
|
-
this.notifications.serverError(error);
|
|
59
|
-
modal.stopLoading();
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
];
|
|
66
|
-
}
|
|
67
9
|
|
|
68
10
|
@task *handlePhotoUpload(file) {
|
|
69
11
|
try {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
</div>
|
|
18
18
|
<div class="flex flex-shrink-0 items-center gap-2 whitespace-nowrap">
|
|
19
19
|
<Button @icon="refresh" @size="sm" @helpText={{t "common.reload"}} @onClick={{@onRefresh}} />
|
|
20
|
-
<Button @icon="plus" @text="Connect Integration" @type="primary" @size="sm" @onClick={{this.createIntegration}} />
|
|
20
|
+
<Button @icon="plus" @text="Connect Integration" @type="primary" @size="sm" @permission="fleet-ops create fuel-provider-connection" @onClick={{this.createIntegration}} />
|
|
21
21
|
</div>
|
|
22
22
|
</div>
|
|
23
23
|
</section>
|
|
@@ -151,14 +151,14 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
151
151
|
this.createItem('menu.contacts', 'address-book', 'management.contacts', 'fleet-ops list contact', 'fleet-ops see contact'),
|
|
152
152
|
this.createItem('menu.places', 'location-dot', 'management.places', 'fleet-ops list place', 'fleet-ops see place'),
|
|
153
153
|
this.createItem('menu.fuel-reports', 'gas-pump', 'management.fuel-reports', 'fleet-ops list fuel-report', 'fleet-ops see fuel-report'),
|
|
154
|
-
this.createItem('menu.fuel-transactions', 'credit-card', 'management.fuel-transactions', 'fleet-ops list fuel-
|
|
154
|
+
this.createItem('menu.fuel-transactions', 'credit-card', 'management.fuel-transactions', 'fleet-ops list fuel-provider-transaction', 'fleet-ops see fuel-provider-transaction'),
|
|
155
155
|
this.createItem('menu.issues', 'triangle-exclamation', 'management.issues', 'fleet-ops list issue', 'fleet-ops see issue'),
|
|
156
156
|
]);
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
get maintenanceItems() {
|
|
160
160
|
return this.withRegistryItems('maintenance', [
|
|
161
|
-
this.createHubItem('Maintenance Hub', 'wrench', 'maintenance.index', 'fleet-ops list
|
|
161
|
+
this.createHubItem('Maintenance Hub', 'wrench', 'maintenance.index', 'fleet-ops list work-order', 'fleet-ops see work-order', [
|
|
162
162
|
'maintenance hub',
|
|
163
163
|
'service readiness',
|
|
164
164
|
'maintenance control panel',
|
|
@@ -182,7 +182,9 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
182
182
|
get connectivityItems() {
|
|
183
183
|
return this.withRegistryItems('connectivity', [
|
|
184
184
|
this.createHubItem(this.intl.t('menu.telematics'), 'satellite-dish', 'connectivity.telematics', 'fleet-ops list telematic', 'fleet-ops see telematic', ['connectivity hub']),
|
|
185
|
-
this.createItem('menu.fuel-providers', 'gas-pump', 'connectivity.fuel-providers', 'fleet-ops list fuel-
|
|
185
|
+
this.createItem('menu.fuel-providers', 'gas-pump', 'connectivity.fuel-providers', 'fleet-ops list fuel-provider-connection', 'fleet-ops see fuel-provider-connection', [
|
|
186
|
+
'fuel integrations',
|
|
187
|
+
]),
|
|
186
188
|
this.createItem('menu.devices', 'hard-drive', 'connectivity.devices', 'fleet-ops list device', 'fleet-ops see device'),
|
|
187
189
|
this.createItem('menu.sensors', 'temperature-full', 'connectivity.sensors', 'fleet-ops list sensor', 'fleet-ops see sensor'),
|
|
188
190
|
this.createItem('menu.events', 'stream', 'connectivity.events', 'fleet-ops list device-event', 'fleet-ops see device-event'),
|
|
@@ -191,18 +193,14 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
191
193
|
|
|
192
194
|
get analyticsItems() {
|
|
193
195
|
return this.withRegistryItems('analytics', [
|
|
194
|
-
this.createHubItem('Dashboard', 'chart-line', 'analytics.index', '
|
|
195
|
-
this.createItem('menu.reports', 'file-import', 'analytics.reports', 'iam list report', '
|
|
196
|
+
this.createHubItem('Dashboard', 'chart-line', 'analytics.index', 'fleet-ops view analytics', 'fleet-ops see analytics', ['dashboard', 'fleetops dashboard', 'metrics']),
|
|
197
|
+
this.createItem('menu.reports', 'file-import', 'analytics.reports', 'iam list report', 'iam see report'),
|
|
196
198
|
]);
|
|
197
199
|
}
|
|
198
200
|
|
|
199
201
|
get settingsItems() {
|
|
200
202
|
return this.withRegistryItems('settings', [
|
|
201
|
-
this.createHubItem('Settings Hub', 'sliders', 'settings.index',
|
|
202
|
-
'settings hub',
|
|
203
|
-
'configuration dashboard',
|
|
204
|
-
'setup focus',
|
|
205
|
-
]),
|
|
203
|
+
this.createHubItem('Settings Hub', 'sliders', 'settings.index', null, null, ['settings hub', 'configuration dashboard', 'setup focus']),
|
|
206
204
|
this.createItem('menu.navigator-app', 'location-arrow', 'settings.navigator-app', 'fleet-ops view navigator-settings', 'fleet-ops see navigator-settings'),
|
|
207
205
|
this.createItem('menu.map', 'map', 'settings.map', 'fleet-ops view map-settings', 'fleet-ops see map-settings'),
|
|
208
206
|
this.createItem('menu.payments', 'cash-register', 'settings.payments', 'fleet-ops view payments', 'fleet-ops see payments'),
|
|
@@ -210,8 +208,9 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
210
208
|
this.createItem('menu.routing', 'route', 'settings.routing', 'fleet-ops view routing-settings', 'fleet-ops see routing-settings'),
|
|
211
209
|
this.createItem('menu.orchestrator', 'circle-nodes', 'settings.orchestrator', 'fleet-ops view routing-settings', 'fleet-ops see routing-settings'),
|
|
212
210
|
this.createItem('menu.scheduling', 'calendar-days', 'settings.scheduling', 'fleet-ops view scheduling-settings', 'fleet-ops see scheduling-settings'),
|
|
213
|
-
this.createItem('menu.
|
|
214
|
-
this.createItem('menu.
|
|
211
|
+
this.createItem('menu.telematics-settings', 'satellite-dish', 'settings.telematics', 'fleet-ops view telematics-settings', 'fleet-ops see telematics-settings'),
|
|
212
|
+
this.createItem('menu.custom-fields', 'pen-to-square', 'settings.custom-fields', 'fleet-ops list custom-field', 'fleet-ops see custom-field'),
|
|
213
|
+
this.createItem('menu.avatars', 'icons', 'settings.avatars', 'fleet-ops list avatar', 'fleet-ops see avatar'),
|
|
215
214
|
]);
|
|
216
215
|
}
|
|
217
216
|
|
|
@@ -265,18 +264,36 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
265
264
|
}
|
|
266
265
|
|
|
267
266
|
createBranch({ id, label, icon, route, defaultRoute, requiresVisibleChildren = false, children, keywords = [] }) {
|
|
267
|
+
const visibleChildren = children.filter((item) => item.visible !== false);
|
|
268
|
+
|
|
268
269
|
return {
|
|
269
270
|
id,
|
|
270
271
|
label,
|
|
271
272
|
icon,
|
|
272
273
|
route: this.fullRoute(route),
|
|
273
|
-
defaultRoute: this.fullRoute(defaultRoute),
|
|
274
|
+
defaultRoute: this.resolveDefaultRoute(this.fullRoute(defaultRoute), visibleChildren),
|
|
274
275
|
requiresVisibleChildren,
|
|
275
|
-
children:
|
|
276
|
+
children: visibleChildren,
|
|
276
277
|
keywords,
|
|
277
278
|
};
|
|
278
279
|
}
|
|
279
280
|
|
|
281
|
+
/**
|
|
282
|
+
* Keep the branch's default route when the user may open it; otherwise fall back to the
|
|
283
|
+
* first child route they are permitted to open, so clicking the branch does not land on a
|
|
284
|
+
* route guard that bounces them back out.
|
|
285
|
+
*/
|
|
286
|
+
resolveDefaultRoute(defaultRoute, children = []) {
|
|
287
|
+
const permitted = (item) => [item.visiblePermission, item.permission].every((permission) => !permission || this.abilities.can(permission));
|
|
288
|
+
const defaultChild = children.find((item) => item.route === defaultRoute);
|
|
289
|
+
|
|
290
|
+
if (!defaultChild || permitted(defaultChild)) {
|
|
291
|
+
return defaultRoute;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return children.find((item) => item.route && permitted(item))?.route ?? defaultRoute;
|
|
295
|
+
}
|
|
296
|
+
|
|
280
297
|
createItem(intl, icon, route, permission, ability, keywords = []) {
|
|
281
298
|
return {
|
|
282
299
|
priority: this.defaultPriorityForRoute(route),
|
|
@@ -290,7 +307,7 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
290
307
|
};
|
|
291
308
|
}
|
|
292
309
|
|
|
293
|
-
createHubItem(label, icon, route,
|
|
310
|
+
createHubItem(label, icon, route, permission, ability, keywords = []) {
|
|
294
311
|
return {
|
|
295
312
|
pinnedFirst: true,
|
|
296
313
|
priority: this.defaultPriorityForRoute(route),
|
|
@@ -298,6 +315,8 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
298
315
|
description: label,
|
|
299
316
|
icon,
|
|
300
317
|
route: this.fullRoute(route),
|
|
318
|
+
permission,
|
|
319
|
+
visiblePermission: ability,
|
|
301
320
|
isNavigationHub: true,
|
|
302
321
|
keywords: [label, route, ...keywords].filter(Boolean),
|
|
303
322
|
};
|
|
@@ -387,8 +406,9 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
387
406
|
'settings.routing': 5,
|
|
388
407
|
'settings.orchestrator': 6,
|
|
389
408
|
'settings.scheduling': 7,
|
|
390
|
-
'settings.
|
|
391
|
-
'settings.
|
|
409
|
+
'settings.telematics': 8,
|
|
410
|
+
'settings.custom-fields': 9,
|
|
411
|
+
'settings.avatars': 10,
|
|
392
412
|
};
|
|
393
413
|
|
|
394
414
|
return priorities[route] ?? 0;
|
|
@@ -83,108 +83,10 @@
|
|
|
83
83
|
as |marker|
|
|
84
84
|
>
|
|
85
85
|
<marker.popup @maxWidth="500" @minWidth="225">
|
|
86
|
-
<
|
|
87
|
-
<div class="flex items-center gap-1.5 text-xs font-semibold mb-1.5">
|
|
88
|
-
<span class="inline-block w-2 h-2 rounded-full {{if driver.online 'bg-green-400' 'bg-red-500'}}"></span>
|
|
89
|
-
<span>{{driver.name}}</span>
|
|
90
|
-
<div
|
|
91
|
-
class="status-badge
|
|
92
|
-
{{if driver.status (dasherize driver.status) 'default'}}-status-badge status-badge-{{if driver.status (dasherize driver.status) 'default'}}
|
|
93
|
-
shadow-none ml-auto"
|
|
94
|
-
>
|
|
95
|
-
<span class="rounded-full text-[9px] px-1.5 py-0.5">{{n-a driver.meta.status_label (smart-humanize driver.status)}}</span>
|
|
96
|
-
</div>
|
|
97
|
-
</div>
|
|
98
|
-
<div class="grid grid-cols-2 gap-1">
|
|
99
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
100
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">ID</div>
|
|
101
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.public_id driver.id}}</div>
|
|
102
|
-
</div>
|
|
103
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
104
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Phone</div>
|
|
105
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.phone}}</div>
|
|
106
|
-
</div>
|
|
107
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
108
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Vehicle</div>
|
|
109
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.vehicle_name}}</div>
|
|
110
|
-
</div>
|
|
111
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
112
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Email</div>
|
|
113
|
-
<div class="text-[11px] text-white leading-tight truncate min-w-0 w-full">{{n-a driver.email}}</div>
|
|
114
|
-
</div>
|
|
115
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
116
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Order</div>
|
|
117
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.meta.current_order_reference}}</div>
|
|
118
|
-
</div>
|
|
119
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
120
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Speed</div>
|
|
121
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.meta.speed_label}}</div>
|
|
122
|
-
</div>
|
|
123
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
124
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Heading</div>
|
|
125
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.meta.heading_label}}</div>
|
|
126
|
-
</div>
|
|
127
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
128
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Location</div>
|
|
129
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a
|
|
130
|
-
driver.meta.location_coordinates
|
|
131
|
-
(point-coordinates driver.location)
|
|
132
|
-
}}</div>
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
86
|
+
<Map::MarkerCard::Driver @driver={{driver}} />
|
|
136
87
|
</marker.popup>
|
|
137
88
|
<marker.tooltip @permanent={{false}} @sticky={{true}}>
|
|
138
|
-
<
|
|
139
|
-
<div class="flex items-center gap-1.5 text-xs font-semibold mb-1.5">
|
|
140
|
-
<span class="inline-block w-2 h-2 rounded-full {{if driver.online 'bg-green-400' 'bg-red-500'}}"></span>
|
|
141
|
-
<span>{{driver.name}}</span>
|
|
142
|
-
<div
|
|
143
|
-
class="status-badge
|
|
144
|
-
{{if driver.status (dasherize driver.status) 'default'}}-status-badge status-badge-{{if driver.status (dasherize driver.status) 'default'}}
|
|
145
|
-
shadow-none ml-auto"
|
|
146
|
-
>
|
|
147
|
-
<span class="rounded-full text-[9px] px-1.5 py-0.5">{{n-a driver.meta.status_label (smart-humanize driver.status)}}</span>
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
<div class="grid grid-cols-2 gap-1">
|
|
151
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
152
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">ID</div>
|
|
153
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.public_id driver.id}}</div>
|
|
154
|
-
</div>
|
|
155
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
156
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Phone</div>
|
|
157
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.phone}}</div>
|
|
158
|
-
</div>
|
|
159
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
160
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Vehicle</div>
|
|
161
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.vehicle_name}}</div>
|
|
162
|
-
</div>
|
|
163
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
164
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Email</div>
|
|
165
|
-
<div class="text-[11px] text-white leading-tight truncate min-w-0 w-full">{{n-a driver.email}}</div>
|
|
166
|
-
</div>
|
|
167
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
168
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Order</div>
|
|
169
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.meta.current_order_reference}}</div>
|
|
170
|
-
</div>
|
|
171
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
172
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Speed</div>
|
|
173
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.meta.speed_label}}</div>
|
|
174
|
-
</div>
|
|
175
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
176
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Heading</div>
|
|
177
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a driver.meta.heading_label}}</div>
|
|
178
|
-
</div>
|
|
179
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
180
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Location</div>
|
|
181
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a
|
|
182
|
-
driver.meta.location_coordinates
|
|
183
|
-
(point-coordinates driver.location)
|
|
184
|
-
}}</div>
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
89
|
+
<Map::MarkerCard::Driver @driver={{driver}} @variant="tooltip" />
|
|
188
90
|
</marker.tooltip>
|
|
189
91
|
</layers.tracking-marker>
|
|
190
92
|
{{/each}}
|
|
@@ -202,150 +104,10 @@
|
|
|
202
104
|
as |marker|
|
|
203
105
|
>
|
|
204
106
|
<marker.popup @permanent={{false}} @sticky={{true}}>
|
|
205
|
-
<
|
|
206
|
-
<div class="flex items-center gap-1.5 text-xs font-semibold mb-1.5">
|
|
207
|
-
<span class="inline-block w-2 h-2 rounded-full {{if vehicle.online 'bg-green-400' 'bg-red-500'}}"></span>
|
|
208
|
-
<span>{{vehicle.displayName}}</span>
|
|
209
|
-
<div
|
|
210
|
-
class="status-badge
|
|
211
|
-
{{if vehicle.status (dasherize vehicle.status) 'default'}}-status-badge status-badge-{{if vehicle.status (dasherize vehicle.status) 'default'}}
|
|
212
|
-
shadow-none ml-auto"
|
|
213
|
-
>
|
|
214
|
-
<span class="rounded-full text-[9px] px-1.5 py-0.5">{{n-a vehicle.meta.status_label}}</span>
|
|
215
|
-
</div>
|
|
216
|
-
</div>
|
|
217
|
-
<div class="grid grid-cols-2 gap-1">
|
|
218
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
219
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Vehicle #</div>
|
|
220
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a
|
|
221
|
-
vehicle.internal_id
|
|
222
|
-
vehicle.public_id
|
|
223
|
-
vehicle.plate_number
|
|
224
|
-
vehicle.serial_number
|
|
225
|
-
vehicle.vin
|
|
226
|
-
}}</div>
|
|
227
|
-
</div>
|
|
228
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
229
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Driver</div>
|
|
230
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.driver_name}}</div>
|
|
231
|
-
</div>
|
|
232
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
233
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">{{t "resource.trailers"}}</div>
|
|
234
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">
|
|
235
|
-
{{#each vehicle.trailers as |trailer|}}
|
|
236
|
-
<div class="flex items-center gap-1 min-w-0">
|
|
237
|
-
<span class="inline-block w-1.5 h-1.5 rounded-full shrink-0 {{if trailer.online 'bg-green-400' 'bg-gray-500'}}"></span>
|
|
238
|
-
<span class="truncate">{{or trailer.displayName trailer.display_name trailer.name trailer.public_id}}</span>
|
|
239
|
-
</div>
|
|
240
|
-
{{else}}
|
|
241
|
-
-
|
|
242
|
-
{{/each}}
|
|
243
|
-
</div>
|
|
244
|
-
</div>
|
|
245
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
246
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">{{t "resource.devices"}}</div>
|
|
247
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">
|
|
248
|
-
{{#each vehicle.devices as |device|}}
|
|
249
|
-
<div class="flex items-center gap-1 min-w-0">
|
|
250
|
-
<span class="inline-block w-1.5 h-1.5 rounded-full shrink-0 {{if device.online 'bg-green-400' 'bg-gray-500'}}"></span>
|
|
251
|
-
<span class="truncate">{{or device.displayName device.display_name device.name device.device_id device.public_id}}</span>
|
|
252
|
-
</div>
|
|
253
|
-
{{else}}
|
|
254
|
-
-
|
|
255
|
-
{{/each}}
|
|
256
|
-
</div>
|
|
257
|
-
</div>
|
|
258
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
259
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Order</div>
|
|
260
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.meta.current_order_reference}}</div>
|
|
261
|
-
</div>
|
|
262
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
263
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Speed</div>
|
|
264
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.meta.speed_label}}</div>
|
|
265
|
-
</div>
|
|
266
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
267
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Heading</div>
|
|
268
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.meta.heading_label}}</div>
|
|
269
|
-
</div>
|
|
270
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
271
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Location</div>
|
|
272
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.meta.location_coordinates}}</div>
|
|
273
|
-
</div>
|
|
274
|
-
</div>
|
|
275
|
-
</div>
|
|
107
|
+
<Map::MarkerCard::Vehicle @vehicle={{vehicle}} />
|
|
276
108
|
</marker.popup>
|
|
277
109
|
<marker.tooltip @permanent={{false}} @sticky={{true}}>
|
|
278
|
-
<
|
|
279
|
-
<div class="flex items-center gap-1.5 text-xs font-semibold mb-1.5">
|
|
280
|
-
<span class="inline-block w-2 h-2 rounded-full {{if vehicle.online 'bg-green-400' 'bg-red-500'}}"></span>
|
|
281
|
-
<span>{{vehicle.displayName}}</span>
|
|
282
|
-
<div
|
|
283
|
-
class="status-badge
|
|
284
|
-
{{if vehicle.status (dasherize vehicle.status) 'default'}}-status-badge status-badge-{{if vehicle.status (dasherize vehicle.status) 'default'}}
|
|
285
|
-
shadow-none ml-auto"
|
|
286
|
-
>
|
|
287
|
-
<span class="rounded-full text-[9px] px-1.5 py-0.5">{{n-a vehicle.meta.status_label}}</span>
|
|
288
|
-
</div>
|
|
289
|
-
</div>
|
|
290
|
-
<div class="grid grid-cols-2 gap-1">
|
|
291
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
292
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Vehicle #</div>
|
|
293
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a
|
|
294
|
-
vehicle.internal_id
|
|
295
|
-
vehicle.public_id
|
|
296
|
-
vehicle.plate_number
|
|
297
|
-
vehicle.serial_number
|
|
298
|
-
vehicle.vin
|
|
299
|
-
}}</div>
|
|
300
|
-
</div>
|
|
301
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
302
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Driver</div>
|
|
303
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.driver_name}}</div>
|
|
304
|
-
</div>
|
|
305
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
306
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">{{t "resource.trailers"}}</div>
|
|
307
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">
|
|
308
|
-
{{#each vehicle.trailers as |trailer|}}
|
|
309
|
-
<div class="flex items-center gap-1 min-w-0">
|
|
310
|
-
<span class="inline-block w-1.5 h-1.5 rounded-full shrink-0 {{if trailer.online 'bg-green-400' 'bg-gray-500'}}"></span>
|
|
311
|
-
<span class="truncate">{{or trailer.displayName trailer.display_name trailer.name trailer.public_id}}</span>
|
|
312
|
-
</div>
|
|
313
|
-
{{else}}
|
|
314
|
-
-
|
|
315
|
-
{{/each}}
|
|
316
|
-
</div>
|
|
317
|
-
</div>
|
|
318
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
319
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">{{t "resource.devices"}}</div>
|
|
320
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">
|
|
321
|
-
{{#each vehicle.devices as |device|}}
|
|
322
|
-
<div class="flex items-center gap-1 min-w-0">
|
|
323
|
-
<span class="inline-block w-1.5 h-1.5 rounded-full shrink-0 {{if device.online 'bg-green-400' 'bg-gray-500'}}"></span>
|
|
324
|
-
<span class="truncate">{{or device.displayName device.display_name device.name device.device_id device.public_id}}</span>
|
|
325
|
-
</div>
|
|
326
|
-
{{else}}
|
|
327
|
-
-
|
|
328
|
-
{{/each}}
|
|
329
|
-
</div>
|
|
330
|
-
</div>
|
|
331
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
332
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Order</div>
|
|
333
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.meta.current_order_reference}}</div>
|
|
334
|
-
</div>
|
|
335
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
336
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Speed</div>
|
|
337
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.meta.speed_label}}</div>
|
|
338
|
-
</div>
|
|
339
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
340
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Heading</div>
|
|
341
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.meta.heading_label}}</div>
|
|
342
|
-
</div>
|
|
343
|
-
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
344
|
-
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Location</div>
|
|
345
|
-
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a vehicle.meta.location_coordinates}}</div>
|
|
346
|
-
</div>
|
|
347
|
-
</div>
|
|
348
|
-
</div>
|
|
110
|
+
<Map::MarkerCard::Vehicle @vehicle={{vehicle}} @variant="tooltip" />
|
|
349
111
|
</marker.tooltip>
|
|
350
112
|
</layers.tracking-marker>
|
|
351
113
|
{{/each}}
|
|
@@ -298,7 +298,8 @@ export default class MapLeafletLiveMapComponent extends Component {
|
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
@task *loadResource(path, options = {}) {
|
|
301
|
-
|
|
301
|
+
// Permissions use the singular resource name (e.g. `fleet-ops list vehicle`), not the plural endpoint path.
|
|
302
|
+
if (this.abilities.cannot(`fleet-ops list ${singularize(path)}`)) return [];
|
|
302
303
|
|
|
303
304
|
if (path === 'service-areas') {
|
|
304
305
|
const serviceAreas = yield this.serviceAreaActions.loadAll.perform();
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{{!
|
|
2
|
+
The driver card the fleet-ops live map shows in a marker's popup and hover tooltip.
|
|
3
|
+
Shared with the dashboard's Live Fleet widget so both look the same. @driver is a driver
|
|
4
|
+
model or its index resource payload (the same attributes, plain JSON).
|
|
5
|
+
@variant: "popup" (default, a dark panel) or "tooltip" (inherits the tooltip's panel).
|
|
6
|
+
}}
|
|
7
|
+
<div class="w-[280px] max-w-[calc(100vw-2rem)] {{unless (eq @variant 'tooltip') 'rounded-lg bg-gray-900 shadow-lg p-1.5 text-white'}}" ...attributes>
|
|
8
|
+
<div class="flex items-center gap-1.5 text-xs font-semibold mb-1.5">
|
|
9
|
+
<span class="inline-block w-2 h-2 rounded-full {{if @driver.online 'bg-green-400' 'bg-red-500'}}"></span>
|
|
10
|
+
<span>{{@driver.name}}</span>
|
|
11
|
+
<div
|
|
12
|
+
class="status-badge
|
|
13
|
+
{{if @driver.status (dasherize @driver.status) 'default'}}-status-badge status-badge-{{if @driver.status (dasherize @driver.status) 'default'}}
|
|
14
|
+
shadow-none ml-auto"
|
|
15
|
+
>
|
|
16
|
+
<span class="rounded-full text-[9px] px-1.5 py-0.5">{{n-a @driver.meta.status_label (smart-humanize @driver.status)}}</span>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="grid grid-cols-2 gap-1">
|
|
20
|
+
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
21
|
+
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">ID</div>
|
|
22
|
+
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a @driver.public_id @driver.id}}</div>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
25
|
+
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Phone</div>
|
|
26
|
+
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a @driver.phone}}</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
29
|
+
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Vehicle</div>
|
|
30
|
+
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a @driver.vehicle_name}}</div>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
33
|
+
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Email</div>
|
|
34
|
+
<div class="text-[11px] text-white leading-tight truncate min-w-0 w-full">{{n-a @driver.email}}</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
37
|
+
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Order</div>
|
|
38
|
+
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a @driver.meta.current_order_reference}}</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
41
|
+
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Speed</div>
|
|
42
|
+
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a @driver.meta.speed_label}}</div>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
45
|
+
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Heading</div>
|
|
46
|
+
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a @driver.meta.heading_label}}</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="rounded bg-gray-900 shadow-md px-1.5 py-1 min-w-0">
|
|
49
|
+
<div class="text-[9px] font-semibold uppercase text-gray-400 leading-none">Location</div>
|
|
50
|
+
<div class="text-[11px] text-white leading-tight whitespace-normal break-words">{{n-a
|
|
51
|
+
@driver.meta.location_coordinates
|
|
52
|
+
(point-coordinates @driver.location)
|
|
53
|
+
}}</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|