@fleetbase/fleetops-engine 0.6.47 → 0.6.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/components/admin/routing-settings.hbs +71 -0
- package/addon/components/admin/routing-settings.js +124 -0
- package/addon/components/customer/orders.js +1 -1
- package/addon/components/display-place.hbs +1 -1
- package/addon/components/driver/details.hbs +5 -1
- package/addon/components/driver/form.hbs +11 -1
- package/addon/components/fleet-listing-panel.hbs +2 -2
- package/addon/components/fleet-listing-panel.js +10 -0
- package/addon/components/map/google-live-map.js +12 -73
- package/addon/components/map/leaflet-live-map.hbs +149 -33
- package/addon/components/map/order-list-overlay/order.hbs +18 -3
- package/addon/components/map/toolbar.hbs +2 -2
- package/addon/components/map/toolbar.js +10 -2
- package/addon/components/orchestrator/phase-builder.hbs +49 -5
- package/addon/components/orchestrator/phase-builder.js +34 -1
- package/addon/components/orchestrator/resource-panel.hbs +19 -1
- package/addon/components/orchestrator/resource-panel.js +4 -0
- package/addon/components/orchestrator-workbench.js +4 -1
- package/addon/components/order/details/purchase-rate.hbs +19 -22
- package/addon/components/order/details/route.hbs +26 -1
- package/addon/components/order/details/route.js +50 -0
- package/addon/components/order/details/tracking.hbs +171 -27
- package/addon/components/order/details/tracking.js +457 -0
- package/addon/components/order/form.hbs +2 -2
- package/addon/components/order/kanban-card.hbs +18 -3
- package/addon/components/order-list-overlay/order.hbs +18 -3
- package/addon/components/order-progress-card.hbs +21 -6
- package/addon/components/order-tracking-lookup.hbs +7 -7
- package/addon/components/order-tracking-lookup.js +1 -1
- package/addon/components/route-list.hbs +78 -8
- package/addon/components/route-list.js +48 -6
- package/addon/components/tracking-stop-progress.hbs +45 -0
- package/addon/components/tracking-stop-progress.js +79 -0
- package/addon/components/widget/fleet-ops-key-metrics.hbs +19 -17
- package/addon/components/widget/fleet-ops-key-metrics.js +26 -0
- package/addon/components/widget/fuel-efficiency.hbs +26 -0
- package/addon/components/widget/fuel-efficiency.js +43 -0
- package/addon/components/widget/geofence-violations.hbs +44 -0
- package/addon/components/widget/geofence-violations.js +55 -0
- package/addon/components/widget/issues-insights.hbs +43 -0
- package/addon/components/widget/issues-insights.js +62 -0
- package/addon/components/widget/kpi-active-orders.hbs +10 -0
- package/addon/components/widget/kpi-active-orders.js +5 -0
- package/addon/components/widget/kpi-aov.hbs +10 -0
- package/addon/components/widget/kpi-aov.js +5 -0
- package/addon/components/widget/kpi-distance.hbs +10 -0
- package/addon/components/widget/kpi-distance.js +5 -0
- package/addon/components/widget/kpi-drivers-online.hbs +10 -0
- package/addon/components/widget/kpi-drivers-online.js +5 -0
- package/addon/components/widget/kpi-earnings.hbs +10 -0
- package/addon/components/widget/kpi-earnings.js +5 -0
- package/addon/components/widget/kpi-open-issues.hbs +11 -0
- package/addon/components/widget/kpi-open-issues.js +5 -0
- package/addon/components/widget/kpi-tile.hbs +59 -0
- package/addon/components/widget/kpi-tile.js +168 -0
- package/addon/components/widget/live-fleet.hbs +122 -0
- package/addon/components/widget/live-fleet.js +365 -0
- package/addon/components/widget/maintenance-overview.hbs +45 -0
- package/addon/components/widget/maintenance-overview.js +40 -0
- package/addon/components/widget/on-time-delivery.hbs +27 -0
- package/addon/components/widget/on-time-delivery.js +73 -0
- package/addon/components/widget/operations-pulse.hbs +51 -0
- package/addon/components/widget/operations-pulse.js +173 -0
- package/addon/components/widget/orders-by-status.hbs +26 -0
- package/addon/components/widget/orders-by-status.js +54 -0
- package/addon/components/widget/revenue-trend.hbs +34 -0
- package/addon/components/widget/revenue-trend.js +67 -0
- package/addon/components/widget/top-drivers.hbs +44 -0
- package/addon/components/widget/top-drivers.js +54 -0
- package/addon/controllers/settings/routing.js +124 -1
- package/addon/extension.js +172 -3
- package/addon/helpers/format-duration.js +38 -0
- package/addon/routes/application.js +6 -0
- package/addon/services/map-adapter/google.js +13 -2
- package/addon/services/order-list-overlay.js +2 -2
- package/addon/styles/fleetops-engine.css +806 -46
- package/addon/templates/maintenance/equipment/index.hbs +1 -1
- package/addon/templates/maintenance/parts/index.hbs +1 -1
- package/addon/templates/maintenance/schedules/index.hbs +1 -1
- package/addon/templates/management/vehicles/index.hbs +1 -1
- package/addon/templates/settings/avatars.hbs +1 -1
- package/addon/templates/settings/custom-fields.hbs +1 -1
- package/addon/templates/settings/map.hbs +1 -1
- package/addon/templates/settings/navigator-app.hbs +1 -1
- package/addon/templates/settings/notifications.hbs +1 -1
- package/addon/templates/settings/orchestrator.hbs +1 -1
- package/addon/templates/settings/payments/index.hbs +1 -1
- package/addon/templates/settings/payments/onboard.hbs +1 -1
- package/addon/templates/settings/routing.hbs +82 -4
- package/addon/templates/settings/scheduling.hbs +1 -1
- package/addon/utils/live-map-card-content.js +171 -0
- package/app/components/tracking-stop-progress.js +1 -0
- package/app/components/widget/fuel-efficiency.js +1 -0
- package/app/components/widget/geofence-violations.js +1 -0
- package/app/components/widget/issues-insights.js +1 -0
- package/app/components/widget/kpi-active-orders.js +1 -0
- package/app/components/widget/kpi-aov.js +1 -0
- package/app/components/widget/kpi-distance.js +1 -0
- package/app/components/widget/kpi-drivers-online.js +1 -0
- package/app/components/widget/kpi-earnings.js +1 -0
- package/app/components/widget/kpi-open-issues.js +1 -0
- package/app/components/widget/kpi-tile.js +1 -0
- package/app/components/widget/live-fleet.js +1 -0
- package/app/components/widget/maintenance-overview.js +1 -0
- package/app/components/widget/on-time-delivery.js +1 -0
- package/app/components/widget/operations-pulse.js +1 -0
- package/app/components/widget/orders-by-status.js +1 -0
- package/app/components/widget/revenue-trend.js +1 -0
- package/app/components/widget/top-drivers.js +1 -0
- package/app/helpers/format-duration.js +1 -0
- package/app/utils/live-map-card-content.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +3 -3
- package/pnpm-workspace.yaml +1 -0
- package/server/config/fleetops.php +32 -11
- package/server/config/telematics.php +111 -1
- package/server/migrations/2026_05_13_000001_repair_customer_contact_user_types.php +86 -0
- package/server/migrations/2026_05_18_000001_add_license_expiry_to_drivers_table.php +25 -0
- package/server/seeders/Testing/Concerns/SeedsTestingData.php +183 -0
- package/server/seeders/Testing/ConnectivitySeeder.php +212 -0
- package/server/seeders/Testing/FleetSeeder.php +341 -0
- package/server/seeders/Testing/MaintenanceSeeder.php +238 -0
- package/server/seeders/Testing/NetworkSeeder.php +250 -0
- package/server/seeders/Testing/OrdersSeeder.php +214 -0
- package/server/seeders/Testing/TestingSeeder.php +40 -0
- package/server/seeders/Testing/VroomOrchestrationSeeder.php +409 -0
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +279 -0
- package/server/src/Http/Controllers/Api/v1/OrchestrationController.php +64 -0
- package/server/src/Http/Controllers/Api/v1/OrderController.php +26 -26
- package/server/src/Http/Controllers/Api/v1/PayloadController.php +10 -10
- package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +119 -0
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +41 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +6 -42
- package/server/src/Http/Controllers/Internal/v1/MetricsController.php +82 -3
- package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +52 -21
- package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +164 -12
- package/server/src/Http/Resources/v1/Driver.php +2 -0
- package/server/src/Http/Resources/v1/Fleet.php +4 -0
- package/server/src/Http/Resources/v1/Index/Driver.php +48 -0
- package/server/src/Http/Resources/v1/Index/Payload.php +2 -2
- package/server/src/Http/Resources/v1/Index/Vehicle.php +74 -1
- package/server/src/Models/Contact.php +122 -13
- package/server/src/Models/Driver.php +2 -0
- package/server/src/Models/Order.php +1 -1
- package/server/src/Models/OrderConfig.php +14 -11
- package/server/src/Models/Payload.php +8 -8
- package/server/src/Models/Place.php +0 -3
- package/server/src/Models/ServiceRate.php +1 -1
- package/server/src/Notifications/LateDeparture.php +48 -0
- package/server/src/Notifications/ProlongedStoppage.php +48 -0
- package/server/src/Notifications/RouteDeviation.php +48 -0
- package/server/src/Observers/ContactObserver.php +8 -0
- package/server/src/Orchestration/Engines/CapacityAllocationEngine.php +220 -0
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +357 -38
- package/server/src/Orchestration/Support/OrchestrationPayloadBuilder.php +259 -51
- package/server/src/Providers/FleetOpsServiceProvider.php +32 -0
- package/server/src/Providers/NotificationServiceProvider.php +3 -0
- package/server/src/Support/Analytics/AbstractAnalytics.php +77 -0
- package/server/src/Support/Analytics/FuelEfficiency.php +83 -0
- package/server/src/Support/Analytics/GeofenceViolations.php +63 -0
- package/server/src/Support/Analytics/IssuesInsights.php +67 -0
- package/server/src/Support/Analytics/LiveFleet.php +127 -0
- package/server/src/Support/Analytics/MaintenanceOverview.php +70 -0
- package/server/src/Support/Analytics/OnTimeDelivery.php +75 -0
- package/server/src/Support/Analytics/OperationsPulse.php +86 -0
- package/server/src/Support/Analytics/OrdersByStatus.php +64 -0
- package/server/src/Support/Analytics/RevenueTrend.php +79 -0
- package/server/src/Support/Analytics/TopDrivers.php +92 -0
- package/server/src/Support/LiveOrderQuery.php +75 -0
- package/server/src/Support/Metrics/AbstractMetric.php +170 -0
- package/server/src/Support/Metrics/ActiveLiveOrdersMetric.php +28 -0
- package/server/src/Support/Metrics/AvgOrderValueMetric.php +53 -0
- package/server/src/Support/Metrics/DriversOnlineMetric.php +30 -0
- package/server/src/Support/Metrics/EarningsMetric.php +30 -0
- package/server/src/Support/Metrics/FuelCostsMetric.php +30 -0
- package/server/src/Support/Metrics/MoneyMetric.php +30 -0
- package/server/src/Support/Metrics/OpenIssuesMetric.php +35 -0
- package/server/src/Support/Metrics/OrdersCanceledMetric.php +35 -0
- package/server/src/Support/Metrics/OrdersCompletedMetric.php +35 -0
- package/server/src/Support/Metrics/OrdersInProgressMetric.php +51 -0
- package/server/src/Support/Metrics/OrdersScheduledMetric.php +37 -0
- package/server/src/Support/Metrics/Registry.php +46 -0
- package/server/src/Support/Metrics/ResolvedIssuesMetric.php +35 -0
- package/server/src/Support/Metrics/TotalCustomersMetric.php +29 -0
- package/server/src/Support/Metrics/TotalDistanceTraveledMetric.php +35 -0
- package/server/src/Support/Metrics/TotalDriversMetric.php +28 -0
- package/server/src/Support/Metrics/TotalTimeTraveledMetric.php +35 -0
- package/server/src/Support/Metrics.php +46 -234
- package/server/src/Support/OSRM.php +11 -6
- package/server/src/Support/OrderTracker.php +7 -582
- package/server/src/Support/Telematics/Providers/AfaqyProvider.php +290 -0
- package/server/src/Support/Telematics/Providers/SafeeProvider.php +333 -0
- package/server/src/Support/Utils.php +1 -1
- package/server/src/Tracking/Contracts/TrackingProviderInterface.php +19 -0
- package/server/src/Tracking/Providers/CalculatedTrackingProvider.php +65 -0
- package/server/src/Tracking/Providers/GoogleRoutesTrackingProvider.php +118 -0
- package/server/src/Tracking/Providers/OsrmTrackingProvider.php +71 -0
- package/server/src/Tracking/README.md +25 -0
- package/server/src/Tracking/Support/FakeTrackingProvider.php +42 -0
- package/server/src/Tracking/TrackingContext.php +63 -0
- package/server/src/Tracking/TrackingContextBuilder.php +204 -0
- package/server/src/Tracking/TrackingIntelligenceService.php +180 -0
- package/server/src/Tracking/TrackingOptions.php +49 -0
- package/server/src/Tracking/TrackingProviderCapabilities.php +30 -0
- package/server/src/Tracking/TrackingProviderManager.php +89 -0
- package/server/src/Tracking/TrackingProviderRegistry.php +35 -0
- package/server/src/Tracking/TrackingProviderResult.php +20 -0
- package/server/src/Tracking/TrackingStop.php +59 -0
- package/server/src/routes.php +27 -0
- package/server/tests/AnalyticsRoutesTest.php +41 -0
- package/server/tests/CapacityAllocationEngineTest.php +108 -0
- package/server/tests/LiveOrderQueryTest.php +34 -0
- package/server/tests/MetricsRegistryTest.php +88 -0
- package/server/tests/OrchestrationPayloadBuilderTest.php +132 -0
- package/server/tests/OrchestratorConsumableApiTest.php +74 -0
- package/server/tests/PingDriverEndpointTest.php +19 -0
- package/server/tests/TrackingIntelligenceTest.php +176 -0
- package/server/tests/VroomOrchestrationEngineTest.php +250 -0
- package/translations/en-us.yaml +41 -0
|
@@ -3,9 +3,80 @@
|
|
|
3
3
|
Configure system-wide routing engine defaults here. Organizations can optionally override these values from their own routing settings.
|
|
4
4
|
</InfoBlock>
|
|
5
5
|
|
|
6
|
+
<ContentPanel @title="Tracking Defaults" @open={{true}} @wrapperClass="bordered-classic">
|
|
7
|
+
<InputGroup @name="Default Tracking Provider" @helpText="Default provider for organization-level tracking intelligence unless an organization overrides it.">
|
|
8
|
+
<Select
|
|
9
|
+
class="w-full"
|
|
10
|
+
@value={{this.trackingProvider}}
|
|
11
|
+
@options={{this.trackingProviderOptions}}
|
|
12
|
+
@optionLabel="label"
|
|
13
|
+
@optionValue="value"
|
|
14
|
+
@placeholder="Select default tracking provider"
|
|
15
|
+
@onSelect={{fn (mut this.trackingProvider)}}
|
|
16
|
+
/>
|
|
17
|
+
</InputGroup>
|
|
18
|
+
<InputGroup @name="Default Fallback Providers" @helpText="Providers used when the selected tracking provider is unavailable.">
|
|
19
|
+
<div class="fleetbase-model-select fleetbase-power-select ember-model-select">
|
|
20
|
+
<PowerSelectMultiple
|
|
21
|
+
@searchEnabled={{true}}
|
|
22
|
+
@options={{this.trackingProviderOptions}}
|
|
23
|
+
@selected={{this.selectedTrackingFallbackOptions}}
|
|
24
|
+
@onChange={{this.setTrackingFallbacks}}
|
|
25
|
+
@placeholder="Select default fallback providers"
|
|
26
|
+
@triggerClass="form-select form-input form-input-sm flex-1"
|
|
27
|
+
as |provider|
|
|
28
|
+
>
|
|
29
|
+
{{provider.label}}
|
|
30
|
+
</PowerSelectMultiple>
|
|
31
|
+
</div>
|
|
32
|
+
</InputGroup>
|
|
33
|
+
<div class="flex justify-end">
|
|
34
|
+
<Button
|
|
35
|
+
@type="default"
|
|
36
|
+
@size="xs"
|
|
37
|
+
@icon={{if this.showTrackingAdvancedSettings "chevron-up" "chevron-down"}}
|
|
38
|
+
@text="Advanced Settings"
|
|
39
|
+
@onClick={{this.toggleTrackingAdvancedSettings}}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
{{#if this.showTrackingAdvancedSettings}}
|
|
43
|
+
<div class="mt-4 space-y-4 rounded-md border border-gray-200 bg-gray-50 p-3 dark:border-gray-700 dark:bg-gray-800">
|
|
44
|
+
<InputGroup @name="Traffic-Aware ETA" @helpText="Use traffic-aware provider calculations when supported.">
|
|
45
|
+
<Toggle @isToggled={{this.trackingTrafficEnabled}} @onToggle={{fn (mut this.trackingTrafficEnabled)}} />
|
|
46
|
+
</InputGroup>
|
|
47
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
48
|
+
<InputGroup @name="Summary Cache TTL">
|
|
49
|
+
<Input @type="number" @value={{this.trackingCacheTtlSeconds}} min="15" max="300" class="form-input w-full" />
|
|
50
|
+
</InputGroup>
|
|
51
|
+
<InputGroup @name="Route Cache TTL">
|
|
52
|
+
<Input @type="number" @value={{this.trackingRouteCacheTtlSeconds}} min="60" max="1800" class="form-input w-full" />
|
|
53
|
+
</InputGroup>
|
|
54
|
+
<InputGroup @name="Stale Location Threshold">
|
|
55
|
+
<Input @type="number" @value={{this.trackingStaleLocationThresholdSeconds}} min="30" max="3600" class="form-input w-full" />
|
|
56
|
+
</InputGroup>
|
|
57
|
+
<InputGroup @name="Fallback Speed">
|
|
58
|
+
<Input @type="number" @value={{this.trackingDefaultVehicleSpeedKph}} min="1" max="160" class="form-input w-full" />
|
|
59
|
+
</InputGroup>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
{{/if}}
|
|
63
|
+
</ContentPanel>
|
|
64
|
+
|
|
6
65
|
<RegistryYield @registry="fleet-ops:component:admin:routing-settings" as |RegistryComponent|>
|
|
7
66
|
<div>
|
|
8
67
|
<RegistryComponent />
|
|
9
68
|
</div>
|
|
10
69
|
</RegistryYield>
|
|
11
70
|
</div>
|
|
71
|
+
|
|
72
|
+
<EmberWormhole @to="next-view-section-subheader-actions">
|
|
73
|
+
<Button
|
|
74
|
+
@type="primary"
|
|
75
|
+
@size="sm"
|
|
76
|
+
@icon="save"
|
|
77
|
+
@text="Save Changes"
|
|
78
|
+
@onClick={{perform this.saveSettings}}
|
|
79
|
+
@isLoading={{or this.saveSettings.isRunning this.loadSettings.isRunning}}
|
|
80
|
+
@disabled={{this.saveSettings.isRunning}}
|
|
81
|
+
/>
|
|
82
|
+
</EmberWormhole>
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
|
|
7
|
+
export default class AdminRoutingSettingsComponent extends Component {
|
|
8
|
+
@service fetch;
|
|
9
|
+
@service notifications;
|
|
10
|
+
@tracked trackingProvider = 'google_routes';
|
|
11
|
+
@tracked trackingFallbacks = ['osrm', 'calculated'];
|
|
12
|
+
@tracked trackingTrafficEnabled = true;
|
|
13
|
+
@tracked trackingCacheTtlSeconds = 60;
|
|
14
|
+
@tracked trackingRouteCacheTtlSeconds = 600;
|
|
15
|
+
@tracked trackingStaleLocationThresholdSeconds = 300;
|
|
16
|
+
@tracked trackingDefaultVehicleSpeedKph = 35;
|
|
17
|
+
@tracked showTrackingAdvancedSettings = false;
|
|
18
|
+
@tracked trackingProviderOptions = [
|
|
19
|
+
{ value: 'google_routes', label: 'Google Routes' },
|
|
20
|
+
{ value: 'osrm', label: 'OSRM' },
|
|
21
|
+
{ value: 'calculated', label: 'Calculated' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
constructor() {
|
|
25
|
+
super(...arguments);
|
|
26
|
+
this.loadSettings.perform();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@task *loadSettings() {
|
|
30
|
+
try {
|
|
31
|
+
const settings = yield this.fetch.get('fleet-ops/settings/admin-tracking-settings');
|
|
32
|
+
this.trackingProvider = settings.provider ?? 'google_routes';
|
|
33
|
+
this.trackingFallbacks = this.normalizeFallbacks(settings.fallbacks);
|
|
34
|
+
this.trackingTrafficEnabled = settings.traffic_enabled ?? true;
|
|
35
|
+
this.trackingCacheTtlSeconds = settings.cache_ttl_seconds ?? 60;
|
|
36
|
+
this.trackingRouteCacheTtlSeconds = settings.route_cache_ttl_seconds ?? 600;
|
|
37
|
+
this.trackingStaleLocationThresholdSeconds = settings.stale_location_threshold_seconds ?? 300;
|
|
38
|
+
this.trackingDefaultVehicleSpeedKph = settings.default_vehicle_speed_kph ?? 35;
|
|
39
|
+
this.trackingProviderOptions = this.normalizeProviderOptions(settings.providers ?? this.trackingProviderOptions);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
this.notifications.serverError(error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@task *saveSettings() {
|
|
46
|
+
try {
|
|
47
|
+
yield this.fetch.post('fleet-ops/settings/admin-tracking-settings', this.trackingSettingsPayload);
|
|
48
|
+
this.notifications.success('Tracking defaults saved.');
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.notifications.serverError(error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get trackingSettingsPayload() {
|
|
55
|
+
return {
|
|
56
|
+
provider: this.trackingProvider,
|
|
57
|
+
fallbacks: this.normalizeFallbacks(this.trackingFallbacks),
|
|
58
|
+
traffic_enabled: this.trackingTrafficEnabled,
|
|
59
|
+
cache_ttl_seconds: Number(this.trackingCacheTtlSeconds) || 60,
|
|
60
|
+
route_cache_ttl_seconds: Number(this.trackingRouteCacheTtlSeconds) || 600,
|
|
61
|
+
stale_location_threshold_seconds: Number(this.trackingStaleLocationThresholdSeconds) || 300,
|
|
62
|
+
default_vehicle_speed_kph: Number(this.trackingDefaultVehicleSpeedKph) || 35,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
normalizeFallbacks(fallbacks) {
|
|
67
|
+
if (Array.isArray(fallbacks)) {
|
|
68
|
+
return fallbacks
|
|
69
|
+
.map((fallback) => this.optionValue(fallback))
|
|
70
|
+
.map((fallback) => String(fallback).trim())
|
|
71
|
+
.filter(Boolean);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return String(fallbacks ?? '')
|
|
75
|
+
.split(',')
|
|
76
|
+
.map((fallback) => fallback.trim())
|
|
77
|
+
.filter(Boolean);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get selectedTrackingFallbackOptions() {
|
|
81
|
+
const selected = new Set(this.normalizeFallbacks(this.trackingFallbacks));
|
|
82
|
+
|
|
83
|
+
return this.trackingProviderOptions.filter((option) => selected.has(this.optionValue(option)));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
normalizeProviderOptions(options = []) {
|
|
87
|
+
return options.map((option) => {
|
|
88
|
+
const value = this.optionValue(option);
|
|
89
|
+
const label = option?.label ?? option?.name ?? this.providerLabel(value);
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
...option,
|
|
93
|
+
key: option?.key ?? value,
|
|
94
|
+
name: option?.name ?? label,
|
|
95
|
+
value,
|
|
96
|
+
label,
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
providerLabel(value) {
|
|
102
|
+
if (value === 'osrm') {
|
|
103
|
+
return 'OSRM';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return String(value ?? '')
|
|
107
|
+
.replace(/[_-]+/g, ' ')
|
|
108
|
+
.replace(/\s+/g, ' ')
|
|
109
|
+
.trim()
|
|
110
|
+
.replace(/\b\w/g, (character) => character.toUpperCase());
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
optionValue(option) {
|
|
114
|
+
return typeof option === 'object' && option !== null ? (option.value ?? option.key) : option;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@action setTrackingFallbacks(options) {
|
|
118
|
+
this.trackingFallbacks = this.normalizeFallbacks(options);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@action toggleTrackingAdvancedSettings() {
|
|
122
|
+
this.showTrackingAdvancedSettings = !this.showTrackingAdvancedSettings;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -138,7 +138,7 @@ export default class CustomerOrdersComponent extends Component {
|
|
|
138
138
|
// start loading order tracking activity
|
|
139
139
|
order.loadTrackingActivity();
|
|
140
140
|
this.urlSearchParams.addParamToCurrentUrl('order', order.public_id);
|
|
141
|
-
const driverCurrentLocation = order.get('tracker_data.
|
|
141
|
+
const driverCurrentLocation = order.get('tracker_data.driver.location');
|
|
142
142
|
if (driverCurrentLocation) {
|
|
143
143
|
this.latitude = driverCurrentLocation.coordinates[1];
|
|
144
144
|
this.longitude = driverCurrentLocation.coordinates[0];
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
</span>
|
|
11
11
|
</div>
|
|
12
12
|
{{else}}
|
|
13
|
-
{{#if
|
|
13
|
+
{{#if @waypointActions}}
|
|
14
14
|
<div class="flex flex-row item-center space-x-2 {{if (or this.place.status_code @eta) 'mb-2'}}">
|
|
15
15
|
{{#unless @hideBadges}}
|
|
16
16
|
{{#if this.place.status_code}}
|
|
@@ -30,6 +30,10 @@
|
|
|
30
30
|
<div class="field-name">{{t "driver.fields.driver-license"}}</div>
|
|
31
31
|
<div class="field-value">{{n-a @resource.drivers_license_number}}</div>
|
|
32
32
|
</div>
|
|
33
|
+
<div class="field-info-container">
|
|
34
|
+
<div class="field-name">{{t "driver.fields.license-expiry"}}</div>
|
|
35
|
+
<div class="field-value">{{n-a @resource.license_expiry}}</div>
|
|
36
|
+
</div>
|
|
33
37
|
<div class="field-info-container">
|
|
34
38
|
<div class="field-name">{{t "resource.vendor"}}</div>
|
|
35
39
|
<div class="field-value">{{n-a @resource.vendor_name}}</div>
|
|
@@ -92,4 +96,4 @@
|
|
|
92
96
|
>
|
|
93
97
|
<MetadataViewer @metadata={{@resource.meta}} />
|
|
94
98
|
</ContentPanel>
|
|
95
|
-
</div>
|
|
99
|
+
</div>
|
|
@@ -93,6 +93,16 @@
|
|
|
93
93
|
/>
|
|
94
94
|
</InputGroup>
|
|
95
95
|
|
|
96
|
+
<InputGroup @name={{t "driver.fields.license-expiry"}}>
|
|
97
|
+
<DatePicker
|
|
98
|
+
@value={{@resource.license_expiry}}
|
|
99
|
+
@onChange={{fn (mut @resource.license_expiry)}}
|
|
100
|
+
@placeholder={{t "driver.fields.license-expiry"}}
|
|
101
|
+
@disabled={{cannot-write @resource}}
|
|
102
|
+
class="w-full form-input"
|
|
103
|
+
/>
|
|
104
|
+
</InputGroup>
|
|
105
|
+
|
|
96
106
|
<InputGroup @name={{t "driver.fields.vendor"}}>
|
|
97
107
|
<ModelSelect
|
|
98
108
|
@modelName="vendor"
|
|
@@ -221,4 +231,4 @@
|
|
|
221
231
|
<ContentPanel @title={{t "common.metadata"}} @open={{true}} @wrapperClass="bordered-top">
|
|
222
232
|
<MetadataEditor @value={{@resource.meta}} @onChange={{fn (mut @resource.meta)}} />
|
|
223
233
|
</ContentPanel>
|
|
224
|
-
</div>
|
|
234
|
+
</div>
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
@dropdownButtonIcon={{@itemDropdownButtonIcon}}
|
|
37
37
|
@dropdownButtonIconPrefix={{@itemDropdownButtonIconPrefix}}
|
|
38
38
|
@dropdownButtonText={{@itemDropdownButtonText}}
|
|
39
|
-
@dropdownButtonCalculatePosition={{
|
|
39
|
+
@dropdownButtonCalculatePosition={{this.calculateDropdownItemPosition}}
|
|
40
40
|
@dropdownButtonMenuLabel={{vehicle.displayName}}
|
|
41
41
|
@dropdownButtonWrapperClass={{@itemDropdownButtonWrapperClass}}
|
|
42
42
|
@dropdownButtonTriggerClass={{@itemDropdownButtonTriggerClass}}
|
|
43
43
|
@registerDropdownButtonAPI={{@itemRegisterDropdownButtonAPI}}
|
|
44
|
-
@permission="fleet-ops view vehicle"
|
|
45
44
|
@dropdownButtonRenderInPlace={{false}}
|
|
45
|
+
@permission="fleet-ops view vehicle"
|
|
46
46
|
>{{vehicle.displayName}}</Layout::Sidebar::Item>
|
|
47
47
|
{{/each}}
|
|
48
48
|
</Layout::Sidebar::Panel>
|
|
@@ -31,4 +31,14 @@ export default class FleetListingPanelComponent extends Component {
|
|
|
31
31
|
this.args.onVehicleClicked(vehicle);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
@action calculateDropdownItemPosition(trigger) {
|
|
36
|
+
let { top, left, width } = trigger.getBoundingClientRect();
|
|
37
|
+
let style = {
|
|
38
|
+
left: 11 + left + width,
|
|
39
|
+
top: top + 2,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return { style };
|
|
43
|
+
}
|
|
34
44
|
}
|
|
@@ -6,73 +6,7 @@ import { action } from '@ember/object';
|
|
|
6
6
|
import { isArray } from '@ember/array';
|
|
7
7
|
import { debug } from '@ember/debug';
|
|
8
8
|
import { guidFor } from '@ember/object/internals';
|
|
9
|
-
|
|
10
|
-
function buildDriverInfoWindowContent(driver) {
|
|
11
|
-
return `
|
|
12
|
-
<div class="fleetops-google-popover fleetops-google-popover--compact">
|
|
13
|
-
<div class="fleetops-google-popover__row">
|
|
14
|
-
<img src="${driver.photoUrl ?? ''}" alt="${driver.name ?? ''}" class="fleetops-google-popover__avatar" />
|
|
15
|
-
<div class="fleetops-google-popover__body">
|
|
16
|
-
<div class="fleetops-google-popover__title">${driver.name ?? '-'}</div>
|
|
17
|
-
<div class="fleetops-google-popover__meta">Phone: ${driver.phone ?? '-'}</div>
|
|
18
|
-
<div class="fleetops-google-popover__meta">Vehicle: ${driver.vehicle_name ?? '-'}</div>
|
|
19
|
-
<div class="fleetops-google-popover__meta">Status:
|
|
20
|
-
<span class="${driver.online ? 'text-green-500' : 'text-red-400'}">${driver.online ? 'Online' : 'Offline'}</span>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
</div>`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function buildDriverTooltipContent(driver) {
|
|
28
|
-
return `
|
|
29
|
-
<div class="fleetops-google-hover-tooltip__title">${driver.name ?? '-'}</div>
|
|
30
|
-
<div class="fleetops-google-hover-tooltip__meta ${driver.online ? 'text-green-400' : 'text-red-400'}">${driver.online ? 'Online' : 'Offline'}</div>
|
|
31
|
-
`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function buildVehicleInfoWindowContent(vehicle) {
|
|
35
|
-
return `
|
|
36
|
-
<div class="fleetops-google-popover">
|
|
37
|
-
<div class="fleetops-google-popover__row">
|
|
38
|
-
<img src="${vehicle.photo_url ?? ''}" alt="${vehicle.display_name ?? ''}" class="fleetops-google-popover__vehicle" />
|
|
39
|
-
<div class="fleetops-google-popover__body">
|
|
40
|
-
<div class="fleetops-google-popover__title">${vehicle.displayName ?? '-'}</div>
|
|
41
|
-
<div class="fleetops-google-popover__meta">ID: ${vehicle.public_id ?? '-'}</div>
|
|
42
|
-
<div class="fleetops-google-popover__meta">Serial: ${vehicle.serial_number ?? vehicle.vin ?? '-'}</div>
|
|
43
|
-
<div class="fleetops-google-popover__meta">Driver: ${vehicle.driver_name ?? '-'}</div>
|
|
44
|
-
<div class="fleetops-google-popover__meta">Status:
|
|
45
|
-
<span class="${vehicle.online ? 'text-green-500' : 'text-red-400'}">${vehicle.online ? 'Online' : 'Offline'}</span>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
</div>`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function buildVehicleTooltipContent(vehicle) {
|
|
53
|
-
return `
|
|
54
|
-
<div class="fleetops-google-hover-tooltip__title">${vehicle.displayName ?? '-'}</div>
|
|
55
|
-
<div class="fleetops-google-hover-tooltip__meta">ID: ${vehicle.public_id ?? '-'}</div>
|
|
56
|
-
<div class="fleetops-google-hover-tooltip__meta ${vehicle.online ? 'text-green-400' : 'text-red-400'}">${vehicle.online ? 'Online' : 'Offline'}</div>
|
|
57
|
-
`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function buildPlaceInfoWindowContent(place) {
|
|
61
|
-
return `
|
|
62
|
-
<div class="fleetops-google-popover fleetops-google-popover--compact">
|
|
63
|
-
<div class="fleetops-google-popover__body">
|
|
64
|
-
<div class="fleetops-google-popover__title">${place.name ?? place.address ?? '-'}</div>
|
|
65
|
-
<div class="fleetops-google-popover__meta">${place.address ?? ''}</div>
|
|
66
|
-
</div>
|
|
67
|
-
</div>`;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function buildPlaceTooltipContent(place) {
|
|
71
|
-
return `
|
|
72
|
-
<div class="fleetops-google-hover-tooltip__title">${place.name ?? place.address ?? '-'}</div>
|
|
73
|
-
<div class="fleetops-google-hover-tooltip__meta">${place.address ?? ''}</div>
|
|
74
|
-
`;
|
|
75
|
-
}
|
|
9
|
+
import { buildDriverLiveMapContent, buildPlaceInfoWindowContent, buildPlaceTooltipContent, buildVehicleLiveMapContent } from '../../utils/live-map-card-content';
|
|
76
10
|
|
|
77
11
|
export default class MapGoogleLiveMapComponent extends Component {
|
|
78
12
|
@service mapManager;
|
|
@@ -100,6 +34,7 @@ export default class MapGoogleLiveMapComponent extends Component {
|
|
|
100
34
|
|
|
101
35
|
this.map = map;
|
|
102
36
|
this.mapManager.on('moveend', () => this.args.onViewportChanged?.());
|
|
37
|
+
this.mapManager.on('click', () => this._closeAllInfoWindows());
|
|
103
38
|
this.mapManager.on('rightclick', (event) => this._showMapContextMenu(event));
|
|
104
39
|
this.args.onLoad?.({ target: map });
|
|
105
40
|
this.syncResources();
|
|
@@ -125,12 +60,12 @@ export default class MapGoogleLiveMapComponent extends Component {
|
|
|
125
60
|
if (!marker) {
|
|
126
61
|
const createdMarker = await this.mapManager.addMarker(driver.id, coords.lat, coords.lng, {
|
|
127
62
|
iconUrl: driver.vehicle_avatar ?? '/engines-dist/images/driver-marker.png',
|
|
128
|
-
iconSize: [
|
|
63
|
+
iconSize: [20, 20],
|
|
129
64
|
title: driver.name,
|
|
130
|
-
tooltip:
|
|
65
|
+
tooltip: buildDriverLiveMapContent(driver),
|
|
131
66
|
tooltipOptions: { html: true },
|
|
132
67
|
rotationAngle: driver.heading,
|
|
133
|
-
onClick: () => this.#openInfoWindow(`driver:${driver.id}`,
|
|
68
|
+
onClick: () => this.#openInfoWindow(`driver:${driver.id}`, buildDriverLiveMapContent(driver, true), driver.id, () => this.args.onDriverClicked?.(driver)),
|
|
134
69
|
onRightClick: (event) => this._showDriverContextMenu(driver, event),
|
|
135
70
|
});
|
|
136
71
|
|
|
@@ -155,12 +90,12 @@ export default class MapGoogleLiveMapComponent extends Component {
|
|
|
155
90
|
if (!marker) {
|
|
156
91
|
const createdMarker = await this.mapManager.addMarker(vehicle.id, coords.lat, coords.lng, {
|
|
157
92
|
iconUrl: vehicle.avatar_url ?? '/engines-dist/images/vehicle-marker.png',
|
|
158
|
-
iconSize: [
|
|
93
|
+
iconSize: [20, 20],
|
|
159
94
|
title: vehicle.displayName,
|
|
160
|
-
tooltip:
|
|
95
|
+
tooltip: buildVehicleLiveMapContent(vehicle),
|
|
161
96
|
tooltipOptions: { html: true },
|
|
162
97
|
rotationAngle: vehicle.heading,
|
|
163
|
-
onClick: () => this.#openInfoWindow(`vehicle:${vehicle.id}`,
|
|
98
|
+
onClick: () => this.#openInfoWindow(`vehicle:${vehicle.id}`, buildVehicleLiveMapContent(vehicle, true), vehicle.id, () => this.args.onVehicleClicked?.(vehicle)),
|
|
164
99
|
onRightClick: (event) => this._showVehicleContextMenu(vehicle, event),
|
|
165
100
|
});
|
|
166
101
|
|
|
@@ -308,6 +243,10 @@ export default class MapGoogleLiveMapComponent extends Component {
|
|
|
308
243
|
if (!infoWindow) {
|
|
309
244
|
infoWindow = new google.maps.InfoWindow({ content });
|
|
310
245
|
this._infoWindows.set(infoId, infoWindow);
|
|
246
|
+
|
|
247
|
+
infoWindow.addListener('domready', () => {
|
|
248
|
+
document.querySelector('[data-fleetops-google-popover-close]')?.addEventListener('click', () => infoWindow.close(), { once: true });
|
|
249
|
+
});
|
|
311
250
|
} else {
|
|
312
251
|
infoWindow.setContent(content);
|
|
313
252
|
}
|