@fleetbase/fleetops-engine 0.6.44 → 0.6.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/components/admin/map-settings.hbs +26 -0
- package/addon/components/admin/map-settings.js +46 -0
- package/addon/components/admin/routing-settings.hbs +11 -0
- package/addon/components/cell/order-route-type.hbs +46 -0
- package/addon/components/cell/order-route-type.js +90 -0
- package/addon/components/cell/place-address.hbs +1 -0
- package/addon/components/display-place.hbs +45 -56
- package/addon/components/display-place.js +21 -0
- package/addon/components/entity/form.hbs +24 -0
- package/addon/components/entity/form.js +30 -0
- package/addon/components/layout/fleet-ops-sidebar/driver-listing.js +5 -5
- package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +5 -5
- package/addon/components/layout/fleet-ops-sidebar.js +8 -0
- package/addon/components/leaflet-draw-control.js +1 -1
- package/addon/components/maintenance-schedule/form.js +2 -1
- package/addon/components/map/drawer/driver-listing.js +5 -5
- package/addon/components/map/drawer/geofence-event-listing.js +5 -2
- package/addon/components/map/drawer/place-listing.js +5 -5
- package/addon/components/map/drawer/position-listing.js +102 -21
- package/addon/components/map/drawer/vehicle-listing.js +5 -5
- package/addon/components/map/google-live-map.hbs +9 -0
- package/addon/components/map/google-live-map.js +445 -0
- package/addon/components/map/leaflet-live-map.hbs +186 -142
- package/addon/components/map/leaflet-live-map.js +121 -41
- package/addon/components/map/toolbar/visibility-control-panel.js +2 -2
- package/addon/components/map/toolbar/zones-panel.hbs +9 -9
- package/addon/components/map/toolbar.hbs +3 -3
- package/addon/components/map/toolbar.js +9 -1
- package/addon/components/modals/map-layer-form.hbs +132 -63
- package/addon/components/modals/orchestrator-import.hbs +4 -11
- package/addon/components/modals/orchestrator-import.js +17 -1
- package/addon/components/modals/update-order-activity.hbs +1 -1
- package/addon/components/orchestrator/order-pool.js +3 -2
- package/addon/components/orchestrator-workbench.js +29 -41
- package/addon/components/order/details/detail.js +2 -2
- package/addon/components/order/details/payload.hbs +5 -5
- package/addon/components/order/details/payload.js +18 -1
- package/addon/components/order/details/route.hbs +2 -2
- package/addon/components/order/details/route.js +76 -3
- package/addon/components/order/form/payload.hbs +33 -0
- package/addon/components/order/form/payload.js +1 -0
- package/addon/components/order/form/route.hbs +8 -8
- package/addon/components/order/form/route.js +78 -18
- package/addon/components/order/form/service-rate.hbs +1 -1
- package/addon/components/order/form.js +2 -2
- package/addon/components/order/route-editor.hbs +209 -147
- package/addon/components/order/route-editor.js +143 -102
- package/addon/components/place/address.hbs +1 -0
- package/addon/components/place/address.js +12 -0
- package/addon/components/route-list.hbs +43 -55
- package/addon/components/route-list.js +47 -0
- package/addon/components/route-optimization-wizard-panel.js +3 -4
- package/addon/components/service-rate/details.hbs +6 -6
- package/addon/components/service-rate/form.hbs +28 -15
- package/addon/components/vehicle/card.hbs +4 -4
- package/addon/controllers/maintenance/schedules/index.js +2 -1
- package/addon/controllers/operations/orders/index/details/virtual.js +5 -0
- package/addon/controllers/operations/orders/index/details.js +113 -15
- package/addon/controllers/operations/orders/index/new.js +1 -1
- package/addon/controllers/operations/orders/index.js +8 -1
- package/addon/controllers/operations/service-rates/index/edit.js +1 -0
- package/addon/controllers/operations/service-rates/index/new.js +1 -0
- package/addon/controllers/settings/map.js +97 -0
- package/addon/controllers/settings/routing.js +47 -12
- package/addon/extension.js +11 -0
- package/addon/helpers/f-to-int.js +6 -0
- package/addon/helpers/place-address-html.js +6 -0
- package/addon/instance-initializers/register-google-routes.js +17 -0
- package/addon/instance-initializers/register-osrm.js +5 -0
- package/addon/routes/application.js +9 -3
- package/addon/routes/operations/orchestrator.js +13 -0
- package/addon/routes/operations/orders/index/details/virtual.js +1 -0
- package/addon/routes/operations/orders/index/details.js +47 -24
- package/addon/routes/operations/orders/index/new.js +9 -0
- package/addon/routes/operations/orders/index.js +0 -1
- package/addon/routes/settings/map.js +3 -0
- package/addon/routes.js +1 -0
- package/addon/services/entity-actions.js +1 -1
- package/addon/services/equipment-actions.js +4 -6
- package/addon/services/geofence-event-bus.js +2 -1
- package/addon/services/geofence.js +204 -168
- package/addon/services/google-routes.js +300 -0
- package/addon/services/leaflet-draw-restriction.js +2 -1
- package/addon/services/leaflet-map-manager.js +21 -0
- package/addon/services/maintenance-actions.js +4 -6
- package/addon/services/map-adapter/google.js +2205 -0
- package/addon/services/map-adapter/leaflet.js +1042 -0
- package/addon/services/map-adapter-interface.js +551 -0
- package/addon/services/map-manager.js +768 -0
- package/addon/services/map-settings.js +75 -0
- package/addon/services/movement-tracker.js +83 -32
- package/addon/services/order-actions.js +11 -1
- package/addon/services/osrm.js +79 -6
- package/addon/services/part-actions.js +4 -6
- package/addon/services/position-playback.js +135 -62
- package/addon/services/route-engine.js +83 -0
- package/addon/services/service-areas.js +8 -1
- package/addon/services/service-rate-actions.js +8 -3
- package/addon/styles/fleetops-engine.css +555 -0
- package/addon/templates/management/vehicles/index.hbs +0 -1
- package/addon/templates/operations/orders/index/details/virtual.hbs +7 -1
- package/addon/templates/operations/orders/index/details.hbs +0 -1
- package/addon/templates/settings/map.hbs +53 -0
- package/addon/templates/settings/routing.hbs +15 -4
- package/addon/utils/fleet-ops-options.js +34 -0
- package/addon/utils/has-valid-coordinates.js +6 -0
- package/addon/utils/map-provider-options.js +6 -0
- package/addon/utils/order-route-editing.js +86 -0
- package/addon/utils/order-route-summary.js +20 -0
- package/addon/utils/place-address-html.js +41 -0
- package/addon/utils/route-colors.js +43 -12
- package/addon/utils/route-visualization.js +93 -0
- package/addon/utils/serialize-payload.js +1 -1
- package/addon/utils/vendor-integration.js +2 -1
- package/app/components/admin/map-settings.js +1 -0
- package/app/components/admin/routing-settings.js +1 -0
- package/app/components/cell/order-route-type.js +1 -0
- package/app/components/cell/place-address.js +1 -0
- package/app/components/map/google-live-map.js +1 -0
- package/app/components/place/address.js +1 -0
- package/app/controllers/operations/orders/index/details/virtual.js +1 -0
- package/app/controllers/settings/map.js +1 -0
- package/app/helpers/f-to-int.js +1 -0
- package/app/helpers/place-address-html.js +1 -0
- package/app/routes/settings/map.js +1 -0
- package/app/services/map-adapter/google.js +1 -0
- package/app/services/map-adapter/leaflet.js +1 -0
- package/app/services/map-adapter-interface.js +1 -0
- package/app/services/map-manager.js +1 -0
- package/app/services/map-settings.js +1 -0
- package/app/templates/settings/map.js +1 -0
- package/app/utils/has-valid-coordinates.js +1 -0
- package/app/utils/order-route-editing.js +2 -0
- package/app/utils/order-route-summary.js +1 -0
- package/app/utils/place-address-html.js +1 -0
- package/app/utils/route-colors.js +1 -1
- package/app/utils/route-visualization.js +1 -0
- package/assets/images/drawing-controls-spritesheet.svg +156 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +3 -3
- package/server/src/Auth/Schemas/FleetOps.php +5 -0
- package/server/src/Http/Controllers/Api/v1/OrderController.php +36 -8
- package/server/src/Http/Controllers/Api/v1/PayloadController.php +14 -1
- package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +11 -3
- package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +2 -0
- package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +7 -2
- package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +6 -1
- package/server/src/Http/Controllers/Api/v1/ZoneController.php +2 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +2 -1
- package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +7 -4
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +61 -34
- package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +3 -2
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +106 -3
- package/server/src/Http/Filter/OrderFilter.php +2 -1
- package/server/src/Http/Requests/CreateServiceRateRequest.php +2 -2
- package/server/src/Http/Resources/v1/Index/Payload.php +9 -7
- package/server/src/Http/Resources/v1/Order.php +20 -2
- package/server/src/Http/Resources/v1/ServiceQuote.php +2 -2
- package/server/src/Models/Entity.php +7 -0
- package/server/src/Models/Order.php +81 -8
- package/server/src/Models/OrderConfig.php +15 -0
- package/server/src/Models/Payload.php +131 -27
- package/server/src/Models/Place.php +182 -48
- package/server/src/Models/ServiceRate.php +125 -32
- package/server/src/Observers/PurchaseRateObserver.php +3 -5
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +59 -23
- package/server/src/Rules/ComputableAlgo.php +1 -3
- package/server/src/Support/Algo.php +87 -1
- package/server/src/Support/Utils.php +69 -0
- package/server/src/routes.php +4 -0
- package/translations/en-us.yaml +1937 -1916
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/* global google */
|
|
2
|
+
import RouteOptimizationInterfaceService from './route-optimization-interface';
|
|
3
|
+
import { isArray } from '@ember/array';
|
|
4
|
+
import { inject as service } from '@ember/service';
|
|
5
|
+
|
|
6
|
+
export default class GoogleRoutesService extends RouteOptimizationInterfaceService {
|
|
7
|
+
@service mapSettings;
|
|
8
|
+
|
|
9
|
+
name = 'Google';
|
|
10
|
+
_apiLoadPromise = null;
|
|
11
|
+
|
|
12
|
+
async computeRoute(waypoints = [], options = {}) {
|
|
13
|
+
const normalizedWaypoints = this.#normalizeWaypoints(waypoints);
|
|
14
|
+
if (normalizedWaypoints.length < 2) {
|
|
15
|
+
throw new Error('At least 2 waypoints are required to compute a route.');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
await this.#ensureApiLoaded(options);
|
|
19
|
+
const { Route, TravelMode, RoutingPreference } = await google.maps.importLibrary('routes');
|
|
20
|
+
const optimizeWaypointOrder = options.optimizeWaypointOrder === true;
|
|
21
|
+
const request = {
|
|
22
|
+
origin: normalizedWaypoints[0],
|
|
23
|
+
destination: normalizedWaypoints[normalizedWaypoints.length - 1],
|
|
24
|
+
travelMode: TravelMode.DRIVING,
|
|
25
|
+
routingPreference: optimizeWaypointOrder ? RoutingPreference.TRAFFIC_AWARE : RoutingPreference.TRAFFIC_AWARE_OPTIMAL,
|
|
26
|
+
fields: ['path', 'viewport', 'distanceMeters', 'durationMillis', 'legs', 'optimizedIntermediateWaypointIndices'],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (normalizedWaypoints.length > 2) {
|
|
30
|
+
request.intermediates = normalizedWaypoints.slice(1, -1).map((waypoint) => ({ location: waypoint, via: false }));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (optimizeWaypointOrder) {
|
|
34
|
+
request.optimizeWaypointOrder = true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const response = await Route.computeRoutes(request);
|
|
38
|
+
const route = response?.routes?.[0];
|
|
39
|
+
|
|
40
|
+
if (!route?.path?.length) {
|
|
41
|
+
throw new Error('Google route computation returned no path.');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const coordinates = route.path.map((point) => [typeof point.lat === 'function' ? point.lat() : point.lat, typeof point.lng === 'function' ? point.lng() : point.lng]);
|
|
45
|
+
const optimizedIndices = isArray(route.optimizedIntermediateWaypointIndices) ? route.optimizedIntermediateWaypointIndices : [];
|
|
46
|
+
const bounds = this.#extractBounds(route.viewport) ?? this.#boundsFromCoordinates(coordinates);
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
engine: 'google',
|
|
50
|
+
waypoints: this.#reorderWaypoints(waypoints, optimizedIndices),
|
|
51
|
+
coordinates,
|
|
52
|
+
bounds,
|
|
53
|
+
summary: {
|
|
54
|
+
totalDistance: route.distanceMeters ?? 0,
|
|
55
|
+
totalTime: route.durationMillis ? route.durationMillis / 1000 : 0,
|
|
56
|
+
},
|
|
57
|
+
legs: isArray(route.legs)
|
|
58
|
+
? route.legs.map((leg) => ({
|
|
59
|
+
distanceMeters: leg.distanceMeters ?? 0,
|
|
60
|
+
durationMillis: leg.durationMillis ?? 0,
|
|
61
|
+
startLocation: leg.startLocation,
|
|
62
|
+
endLocation: leg.endLocation,
|
|
63
|
+
}))
|
|
64
|
+
: [],
|
|
65
|
+
raw: route,
|
|
66
|
+
optimizedIntermediateWaypointIndices: optimizedIndices,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async optimize({ order, waypoints, coordinates, preserveEndpoints = false }, options = {}) {
|
|
71
|
+
const route = await this.computeRoute(this.#normalizeOptimizationCoordinates(order, coordinates), {
|
|
72
|
+
...options,
|
|
73
|
+
optimizeWaypointOrder: true,
|
|
74
|
+
});
|
|
75
|
+
let sortedWaypoints = waypoints;
|
|
76
|
+
|
|
77
|
+
if (isArray(route.waypoints) && route.waypoints.length > 0) {
|
|
78
|
+
sortedWaypoints = this.#reorderModelsByRouteWaypoints(waypoints, route.waypoints, preserveEndpoints);
|
|
79
|
+
} else if (isArray(route.optimizedIntermediateWaypointIndices) && route.optimizedIntermediateWaypointIndices.length > 0) {
|
|
80
|
+
sortedWaypoints = this.#reorderModelWaypoints(waypoints, route.optimizedIntermediateWaypointIndices, preserveEndpoints);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
sortedWaypoints,
|
|
85
|
+
route: route.coordinates,
|
|
86
|
+
trip: {
|
|
87
|
+
distance: route.summary.totalDistance,
|
|
88
|
+
duration: route.summary.totalTime,
|
|
89
|
+
legs: route.legs,
|
|
90
|
+
},
|
|
91
|
+
result: route.raw,
|
|
92
|
+
engine: 'google',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
#normalizeOptimizationCoordinates(order, coordinates = []) {
|
|
97
|
+
const driverPosition = order?.driver_assigned?.location?.coordinates;
|
|
98
|
+
const normalized = (isArray(coordinates) ? coordinates : []).map(([lng, lat]) => [lat, lng]);
|
|
99
|
+
|
|
100
|
+
if (this.#isValidDriverPosition(driverPosition)) {
|
|
101
|
+
return [[driverPosition[1], driverPosition[0]], ...normalized];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return normalized;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#isValidDriverPosition(driverPosition) {
|
|
108
|
+
if (!isArray(driverPosition) || driverPosition.length < 2) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const [lng, lat] = driverPosition.map(Number);
|
|
113
|
+
|
|
114
|
+
if (!Number.isFinite(lat) || !Number.isFinite(lng)) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return lat !== 0 && lng !== 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
#normalizeWaypoints(waypoints = []) {
|
|
122
|
+
return (isArray(waypoints) ? waypoints : [])
|
|
123
|
+
.map((waypoint) => {
|
|
124
|
+
if (isArray(waypoint) && waypoint.length >= 2) {
|
|
125
|
+
return { lat: Number(waypoint[0]), lng: Number(waypoint[1]) };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (Number.isFinite(waypoint?.lat) && Number.isFinite(waypoint?.lng)) {
|
|
129
|
+
return { lat: Number(waypoint.lat), lng: Number(waypoint.lng) };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return null;
|
|
133
|
+
})
|
|
134
|
+
.filter((waypoint) => Number.isFinite(waypoint?.lat) && Number.isFinite(waypoint?.lng));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
#reorderWaypoints(waypoints = [], optimizedIndices = []) {
|
|
138
|
+
if (!isArray(optimizedIndices) || optimizedIndices.length === 0 || waypoints.length < 3) {
|
|
139
|
+
return waypoints;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const start = waypoints[0];
|
|
143
|
+
const end = waypoints[waypoints.length - 1];
|
|
144
|
+
const intermediates = waypoints.slice(1, -1);
|
|
145
|
+
const orderedIntermediates = optimizedIndices.map((index) => intermediates[index]).filter(Boolean);
|
|
146
|
+
|
|
147
|
+
return [start, ...orderedIntermediates, end];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
#reorderModelWaypoints(waypoints = [], optimizedIndices = [], preserveEndpoints = false) {
|
|
151
|
+
if (!isArray(optimizedIndices) || optimizedIndices.length === 0 || !isArray(waypoints) || waypoints.length < 3) {
|
|
152
|
+
return waypoints;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!preserveEndpoints) {
|
|
156
|
+
const start = waypoints[0];
|
|
157
|
+
const end = waypoints[waypoints.length - 1];
|
|
158
|
+
const intermediates = waypoints.slice(1, -1);
|
|
159
|
+
const orderedIntermediates = optimizedIndices.map((index) => intermediates[index]).filter(Boolean);
|
|
160
|
+
|
|
161
|
+
return [start, ...orderedIntermediates, end];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const start = waypoints[0];
|
|
165
|
+
const end = waypoints[waypoints.length - 1];
|
|
166
|
+
const intermediates = waypoints.slice(1, -1);
|
|
167
|
+
const orderedIntermediates = optimizedIndices.map((index) => intermediates[index]).filter(Boolean);
|
|
168
|
+
|
|
169
|
+
return [start, ...orderedIntermediates, end];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
#reorderModelsByRouteWaypoints(waypoints = [], routeWaypoints = [], preserveEndpoints = false) {
|
|
173
|
+
if (!isArray(waypoints) || !waypoints.length || !isArray(routeWaypoints) || !routeWaypoints.length) {
|
|
174
|
+
return waypoints;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const waypointOrder = preserveEndpoints ? routeWaypoints.slice(1, -1) : routeWaypoints;
|
|
178
|
+
const buckets = new Map();
|
|
179
|
+
|
|
180
|
+
for (const waypoint of waypoints) {
|
|
181
|
+
const key = this.#modelCoordinateKey(waypoint);
|
|
182
|
+
|
|
183
|
+
if (!key) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!buckets.has(key)) {
|
|
188
|
+
buckets.set(key, []);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
buckets.get(key).push(waypoint);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const orderedWaypoints = [];
|
|
195
|
+
for (const routeWaypoint of waypointOrder) {
|
|
196
|
+
const key = this.#coordinateKey(routeWaypoint?.lat, routeWaypoint?.lng);
|
|
197
|
+
const bucket = buckets.get(key);
|
|
198
|
+
|
|
199
|
+
if (bucket?.length) {
|
|
200
|
+
orderedWaypoints.push(bucket.shift());
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (orderedWaypoints.length === waypoints.length) {
|
|
205
|
+
return orderedWaypoints;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return waypoints;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#modelCoordinateKey(waypoint) {
|
|
212
|
+
const place = waypoint?.place ?? waypoint;
|
|
213
|
+
return this.#coordinateKey(place?.latitude ?? waypoint?.latitude, place?.longitude ?? waypoint?.longitude);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
#coordinateKey(lat, lng) {
|
|
217
|
+
const normalizedLat = Number(lat);
|
|
218
|
+
const normalizedLng = Number(lng);
|
|
219
|
+
|
|
220
|
+
if (!Number.isFinite(normalizedLat) || !Number.isFinite(normalizedLng)) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return `${normalizedLat.toFixed(6)}:${normalizedLng.toFixed(6)}`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
#boundsFromCoordinates(coordinates = []) {
|
|
228
|
+
if (!coordinates.length) {
|
|
229
|
+
return [
|
|
230
|
+
[0, 0],
|
|
231
|
+
[0, 0],
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const lats = coordinates.map(([lat]) => lat);
|
|
236
|
+
const lngs = coordinates.map(([, lng]) => lng);
|
|
237
|
+
|
|
238
|
+
return [
|
|
239
|
+
[Math.min(...lats), Math.min(...lngs)],
|
|
240
|
+
[Math.max(...lats), Math.max(...lngs)],
|
|
241
|
+
];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#extractBounds(viewport) {
|
|
245
|
+
if (!viewport) return null;
|
|
246
|
+
|
|
247
|
+
if (typeof viewport.getSouthWest === 'function' && typeof viewport.getNorthEast === 'function') {
|
|
248
|
+
const sw = viewport.getSouthWest();
|
|
249
|
+
const ne = viewport.getNorthEast();
|
|
250
|
+
return [
|
|
251
|
+
[sw.lat(), sw.lng()],
|
|
252
|
+
[ne.lat(), ne.lng()],
|
|
253
|
+
];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (Number.isFinite(viewport.south) && Number.isFinite(viewport.west) && Number.isFinite(viewport.north) && Number.isFinite(viewport.east)) {
|
|
257
|
+
return [
|
|
258
|
+
[viewport.south, viewport.west],
|
|
259
|
+
[viewport.north, viewport.east],
|
|
260
|
+
];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async #ensureApiLoaded(options = {}) {
|
|
267
|
+
if (window.google?.maps?.importLibrary) {
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (this._apiLoadPromise) {
|
|
272
|
+
return this._apiLoadPromise;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const apiKey = options.apiKey ?? this.mapSettings.googleMapsApiKey;
|
|
276
|
+
if (!apiKey) {
|
|
277
|
+
throw new Error('Google Maps API key is required for Google route computation.');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
this._apiLoadPromise = new Promise((resolve, reject) => {
|
|
281
|
+
const callbackName = `__fleetopsGoogleRoutesInit_${Date.now().toString(36)}`;
|
|
282
|
+
window[callbackName] = () => {
|
|
283
|
+
delete window[callbackName];
|
|
284
|
+
resolve(true);
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const script = document.createElement('script');
|
|
288
|
+
script.async = true;
|
|
289
|
+
script.defer = true;
|
|
290
|
+
script.onerror = (error) => {
|
|
291
|
+
delete window[callbackName];
|
|
292
|
+
reject(error);
|
|
293
|
+
};
|
|
294
|
+
script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=routes,geometry,marker&callback=${callbackName}&loading=async`;
|
|
295
|
+
document.head.appendChild(script);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
return this._apiLoadPromise;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Service from '@ember/service';
|
|
2
|
+
import { isArray } from '@ember/array';
|
|
2
3
|
import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
|
|
3
4
|
import { point as turfPoint, polygon as turfPolygon } from '@turf/helpers';
|
|
4
5
|
|
|
@@ -124,7 +125,7 @@ export default class LeafletMapManagerService extends Service {
|
|
|
124
125
|
#everyVertexInside(latlngs) {
|
|
125
126
|
// latlngs can be nested (poly: [ring], multi: [[ring]...])
|
|
126
127
|
const walk = (arr) => {
|
|
127
|
-
if (!
|
|
128
|
+
if (!isArray(arr)) return true;
|
|
128
129
|
if (arr.length && arr[0]?.lat != null) {
|
|
129
130
|
return arr.every((ll) => this.#isInside(ll));
|
|
130
131
|
}
|
|
@@ -10,6 +10,7 @@ import isUuid from '@fleetbase/ember-core/utils/is-uuid';
|
|
|
10
10
|
|
|
11
11
|
export default class LeafletMapManagerService extends Service {
|
|
12
12
|
@service leafletRoutingControl;
|
|
13
|
+
@service mapManager;
|
|
13
14
|
@service notifications;
|
|
14
15
|
@tracked map;
|
|
15
16
|
@tracked _livemap;
|
|
@@ -222,6 +223,10 @@ export default class LeafletMapManagerService extends Service {
|
|
|
222
223
|
/** routing methods */
|
|
223
224
|
/* eslint-disable no-empty */
|
|
224
225
|
async addRoutingControl(waypoints, options = {}) {
|
|
226
|
+
if (this.mapManager?.providerName && this.mapManager.providerName !== 'leaflet') {
|
|
227
|
+
return this.mapManager.addRoutingControl(waypoints, options);
|
|
228
|
+
}
|
|
229
|
+
|
|
225
230
|
if (!isArray(waypoints) || waypoints.length === 0) return;
|
|
226
231
|
|
|
227
232
|
const map = await this.ensureInteractive({ timeoutMs: 8000 });
|
|
@@ -270,12 +275,20 @@ export default class LeafletMapManagerService extends Service {
|
|
|
270
275
|
this.route = routes[0];
|
|
271
276
|
});
|
|
272
277
|
|
|
278
|
+
routingControl.on('routingerror', (event) => {
|
|
279
|
+
options?.onRoutingError?.(event);
|
|
280
|
+
});
|
|
281
|
+
|
|
273
282
|
this.positionWaypoints(waypoints);
|
|
274
283
|
|
|
275
284
|
return routingControl;
|
|
276
285
|
}
|
|
277
286
|
|
|
278
287
|
positionWaypoints(waypoints) {
|
|
288
|
+
if (this.mapManager?.providerName && this.mapManager.providerName !== 'leaflet') {
|
|
289
|
+
return this.mapManager.positionWaypoints(waypoints);
|
|
290
|
+
}
|
|
291
|
+
|
|
279
292
|
if (waypoints.length === 1) {
|
|
280
293
|
this.map.flyTo(waypoints[0], 18);
|
|
281
294
|
this.map.once('moveend', () => this.map.panBy([200, 0]));
|
|
@@ -294,6 +307,10 @@ export default class LeafletMapManagerService extends Service {
|
|
|
294
307
|
}
|
|
295
308
|
|
|
296
309
|
async replaceRoutingControl(waypoints, routingControl, options = {}) {
|
|
310
|
+
if (this.mapManager?.providerName && this.mapManager.providerName !== 'leaflet') {
|
|
311
|
+
return this.mapManager.replaceRoutingControl(waypoints, routingControl, options);
|
|
312
|
+
}
|
|
313
|
+
|
|
297
314
|
const removeOptions = options.removeOptions ?? {};
|
|
298
315
|
if (routingControl) {
|
|
299
316
|
await this.removeRoutingControl(routingControl, removeOptions);
|
|
@@ -307,6 +324,10 @@ export default class LeafletMapManagerService extends Service {
|
|
|
307
324
|
|
|
308
325
|
/* eslint-disable no-empty */
|
|
309
326
|
removeRoutingControl(routingControl, options = {}) {
|
|
327
|
+
if (this.mapManager?.providerName && this.mapManager.providerName !== 'leaflet') {
|
|
328
|
+
return Promise.resolve(this.mapManager.removeRoutingControl(routingControl, options));
|
|
329
|
+
}
|
|
330
|
+
|
|
310
331
|
return new Promise((resolve) => {
|
|
311
332
|
let removed = false;
|
|
312
333
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import ResourceActionService
|
|
1
|
+
import ResourceActionService from '@fleetbase/ember-core/services/resource-action';
|
|
2
2
|
|
|
3
3
|
export default class MaintenanceActionsService extends ResourceActionService {
|
|
4
|
-
|
|
4
|
+
get defaultCurrency() {
|
|
5
|
+
return this.currentUser?.company?.currency || this.currentUser.currency || 'USD';
|
|
6
|
+
}
|
|
5
7
|
|
|
6
8
|
constructor() {
|
|
7
9
|
super(...arguments);
|
|
@@ -12,10 +14,6 @@ export default class MaintenanceActionsService extends ResourceActionService {
|
|
|
12
14
|
});
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
get defaultCurrency() {
|
|
16
|
-
return this.currentUser?.company?.currency || 'USD';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
17
|
transition = {
|
|
20
18
|
view: (maintenance) => this.transitionTo('maintenance.maintenances.index.details', maintenance),
|
|
21
19
|
edit: (maintenance) => this.transitionTo('maintenance.maintenances.index.edit', maintenance),
|