@fleetbase/fleetops-engine 0.3.7 → 0.3.9

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.
Files changed (113) hide show
  1. package/addon/components/contact-form-panel.hbs +4 -1
  2. package/addon/components/contact-panel.hbs +1 -1
  3. package/addon/components/driver-form-panel.hbs +5 -12
  4. package/addon/components/driver-panel.hbs +4 -1
  5. package/addon/components/fleet-form-panel.hbs +4 -1
  6. package/addon/components/fleet-listing-panel.hbs +2 -2
  7. package/addon/components/fleet-panel.hbs +1 -1
  8. package/addon/components/fuel-report-form-panel.hbs +4 -1
  9. package/addon/components/fuel-report-panel.hbs +4 -1
  10. package/addon/components/issue-form-panel.hbs +4 -1
  11. package/addon/components/issue-panel.hbs +4 -1
  12. package/addon/components/layout/fleet-ops-sidebar/driver-listing.hbs +5 -0
  13. package/addon/components/layout/fleet-ops-sidebar/driver-listing.js +122 -0
  14. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.hbs +5 -1
  15. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +118 -1
  16. package/addon/components/layout/fleet-ops-sidebar.hbs +5 -1
  17. package/addon/components/layout/fleet-ops-sidebar.js +4 -2
  18. package/addon/components/live-map.hbs +90 -9
  19. package/addon/components/live-map.js +28 -11
  20. package/addon/components/map-container/toolbar/zones-panel.js +16 -13
  21. package/addon/components/place-form-panel.hbs +4 -1
  22. package/addon/components/place-panel.hbs +4 -1
  23. package/addon/components/settings-window.hbs +1 -1
  24. package/addon/components/vehicle-form-panel.hbs +4 -1
  25. package/addon/components/vehicle-panel.hbs +4 -1
  26. package/addon/components/vendor-form-panel.hbs +4 -1
  27. package/addon/components/vendor-panel.hbs +4 -1
  28. package/addon/controllers/management/drivers/index.js +10 -90
  29. package/addon/controllers/management/vehicles/index.js +11 -21
  30. package/addon/controllers/operations/orders/index/new.js +5 -5
  31. package/addon/controllers/operations/orders/index/view.js +9 -13
  32. package/addon/helpers/format-point.js +5 -2
  33. package/addon/helpers/point-to-coordinates.js +6 -2
  34. package/addon/services/context-panel.js +23 -18
  35. package/addon/services/driver-actions.js +107 -0
  36. package/addon/services/vehicle-actions.js +42 -0
  37. package/addon/styles/fleetops-engine.css +27 -0
  38. package/addon/templates/operations/orders/index/new.hbs +3 -3
  39. package/addon/templates/operations/service-rates/index/new.hbs +1 -1
  40. package/addon/utils/fly-to-leaflet-layer.js +7 -0
  41. package/app/components/layout/fleet-ops-sidebar/driver-listing.js +1 -0
  42. package/app/services/driver-actions.js +1 -0
  43. package/app/services/vehicle-actions.js +1 -0
  44. package/composer.json +2 -2
  45. package/extension.json +1 -1
  46. package/package.json +4 -4
  47. package/server/src/Casts/MultiPolygon.php +14 -3
  48. package/server/src/Casts/Point.php +12 -2
  49. package/server/src/Casts/Polygon.php +19 -4
  50. package/server/src/Exceptions/IntegratedVendorException.php +45 -1
  51. package/server/src/Http/Controllers/Api/v1/DriverController.php +29 -14
  52. package/server/src/Http/Controllers/Api/v1/EntityController.php +36 -1
  53. package/server/src/Http/Controllers/Api/v1/LabelController.php +2 -2
  54. package/server/src/Http/Controllers/Api/v1/OrderController.php +139 -59
  55. package/server/src/Http/Controllers/Api/v1/PayloadController.php +20 -12
  56. package/server/src/Http/Controllers/Api/v1/PlaceController.php +25 -3
  57. package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +1 -1
  58. package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +71 -3
  59. package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +1 -1
  60. package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +3 -2
  61. package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +2 -2
  62. package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +2 -2
  63. package/server/src/Http/Controllers/Api/v1/VehicleController.php +22 -2
  64. package/server/src/Http/Controllers/Api/v1/ZoneController.php +59 -3
  65. package/server/src/Http/Controllers/Internal/v1/DriverController.php +25 -4
  66. package/server/src/Http/Controllers/Internal/v1/LiveController.php +3 -10
  67. package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +1 -1
  68. package/server/src/Http/Controllers/Internal/v1/OrderController.php +11 -1
  69. package/server/src/Http/Filter/TrackingStatusFilter.php +10 -0
  70. package/server/src/Http/Requests/CancelOrderRequest.php +1 -2
  71. package/server/src/Http/Requests/CreateContactRequest.php +5 -4
  72. package/server/src/Http/Requests/CreateDriverRequest.php +13 -11
  73. package/server/src/Http/Requests/CreateEntityRequest.php +7 -4
  74. package/server/src/Http/Requests/CreateOrderRequest.php +2 -2
  75. package/server/src/Http/Requests/CreatePayloadRequest.php +1 -1
  76. package/server/src/Http/Requests/CreatePlaceRequest.php +46 -4
  77. package/server/src/Http/Requests/CreatePurchaseRateRequest.php +3 -2
  78. package/server/src/Http/Requests/CreateServiceAreaRequest.php +24 -4
  79. package/server/src/Http/Requests/CreateServiceRateRequest.php +22 -21
  80. package/server/src/Http/Requests/CreateTrackingStatusRequest.php +9 -8
  81. package/server/src/Http/Requests/CreateVehicleRequest.php +6 -4
  82. package/server/src/Http/Requests/CreateZoneRequest.php +24 -5
  83. package/server/src/Http/Requests/QueryServiceQuotesRequest.php +11 -10
  84. package/server/src/Http/Requests/ScheduleOrderRequest.php +32 -0
  85. package/server/src/Http/Requests/UpdateContactRequest.php +0 -13
  86. package/server/src/Http/Requests/UpdateServiceAreaRequest.php +1 -23
  87. package/server/src/Http/Requests/UpdateServiceQuoteRequest.php +1 -23
  88. package/server/src/Http/Requests/UpdateServiceRateRequest.php +1 -23
  89. package/server/src/Http/Requests/UpdateTrackingStatusRequest.php +1 -26
  90. package/server/src/Http/Resources/v1/DeletedResource.php +2 -9
  91. package/server/src/Http/Resources/v1/Entity.php +47 -44
  92. package/server/src/Http/Resources/v1/Order.php +1 -1
  93. package/server/src/Http/Resources/v1/ServiceArea.php +2 -2
  94. package/server/src/Http/Resources/v1/Vehicle.php +1 -3
  95. package/server/src/Http/Resources/v1/Zone.php +2 -4
  96. package/server/src/Models/Entity.php +99 -3
  97. package/server/src/Models/Order.php +75 -7
  98. package/server/src/Models/Payload.php +104 -33
  99. package/server/src/Models/Place.php +56 -17
  100. package/server/src/Models/ServiceArea.php +285 -18
  101. package/server/src/Models/ServiceRate.php +10 -6
  102. package/server/src/Models/TrackingNumber.php +18 -24
  103. package/server/src/Models/TrackingStatus.php +2 -6
  104. package/server/src/Models/Vehicle.php +2 -2
  105. package/server/src/Models/Waypoint.php +0 -10
  106. package/server/src/Models/Zone.php +132 -5
  107. package/server/src/Support/Flow.php +17 -3
  108. package/server/src/Support/Utils.php +143 -9
  109. package/server/src/routes.php +4 -3
  110. package/addon/helpers/extract-coordinates.js +0 -6
  111. package/addon/utils/extract-coordinates.js +0 -1
  112. package/app/helpers/extract-coordinates.js +0 -1
  113. package/app/utils/extract-coordinates.js +0 -1
@@ -2,6 +2,7 @@ import Service from '@ember/service';
2
2
  import { tracked } from '@glimmer/tracking';
3
3
  import { action } from '@ember/object';
4
4
  import getModelName from '@fleetbase/ember-core/utils/get-model-name';
5
+ import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
5
6
 
6
7
  /**
7
8
  * Service for managing the state and interactions of the context panel.
@@ -19,81 +20,81 @@ export default class ContextPanelService extends Service {
19
20
  driver: {
20
21
  viewing: {
21
22
  component: 'driver-panel',
22
- componentArguments: [{ isResizable: true }, { width: '600px' }],
23
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
23
24
  },
24
25
  editing: {
25
26
  component: 'driver-form-panel',
26
- componentArguments: [{ isResizable: true }, { width: '600px' }],
27
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
27
28
  },
28
29
  },
29
30
  vehicle: {
30
31
  viewing: {
31
32
  component: 'vehicle-panel',
32
- componentArguments: [{ isResizable: true }, { width: '600px' }],
33
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
33
34
  },
34
35
  editing: {
35
36
  component: 'vehicle-form-panel',
36
- componentArguments: [{ isResizable: true }, { width: '600px' }],
37
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
37
38
  },
38
39
  },
39
40
  fleet: {
40
41
  viewing: {
41
42
  component: 'fleet-panel',
42
- componentArguments: [{ isResizable: true }, { width: '600px' }],
43
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
43
44
  },
44
45
  editing: {
45
46
  component: 'fleet-form-panel',
46
- componentArguments: [{ isResizable: true }, { width: '600px' }],
47
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
47
48
  },
48
49
  },
49
50
  fuelReport: {
50
51
  viewing: {
51
52
  component: 'fuel-report-panel',
52
- componentArguments: [{ isResizable: true }, { width: '600px' }],
53
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
53
54
  },
54
55
  editing: {
55
56
  component: 'fuel-report-form-panel',
56
- componentArguments: [{ isResizable: true }, { width: '600px' }],
57
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
57
58
  },
58
59
  },
59
60
  vendor: {
60
61
  viewing: {
61
62
  component: 'vendor-panel',
62
- componentArguments: [{ isResizable: true }, { width: '600px' }],
63
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
63
64
  },
64
65
  editing: {
65
66
  component: 'vendor-form-panel',
66
- componentArguments: [{ isResizable: true }, { width: '600px' }],
67
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
67
68
  },
68
69
  },
69
70
  contact: {
70
71
  viewing: {
71
72
  component: 'contact-panel',
72
- componentArguments: [{ isResizable: true }, { width: '600px' }],
73
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
73
74
  },
74
75
  editing: {
75
76
  component: 'contact-form-panel',
76
- componentArguments: [{ isResizable: true }, { width: '600px' }],
77
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
77
78
  },
78
79
  },
79
80
  place: {
80
81
  viewing: {
81
82
  component: 'place-panel',
82
- componentArguments: [{ isResizable: true }, { width: '600px' }],
83
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
83
84
  },
84
85
  editing: {
85
86
  component: 'place-form-panel',
86
- componentArguments: [{ isResizable: true }, { width: '600px' }],
87
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
87
88
  },
88
89
  },
89
90
  issue: {
90
91
  viewing: {
91
92
  component: 'issue-panel',
92
- componentArguments: [{ isResizable: true }, { width: '600px' }],
93
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
93
94
  },
94
95
  editing: {
95
96
  component: 'issue-form-panel',
96
- componentArguments: [{ isResizable: true }, { width: '600px' }],
97
+ componentArguments: [{ isResizable: true }, { width: '500px' }],
97
98
  },
98
99
  },
99
100
  };
@@ -137,11 +138,12 @@ export default class ContextPanelService extends Service {
137
138
  @action focus(model, intent = 'viewing', options = {}) {
138
139
  const modelName = getModelName(model);
139
140
  const registry = this.registry[modelName];
141
+ const dynamicArgs = getWithDefault(options, 'args', {});
140
142
 
141
143
  if (registry && registry[intent]) {
142
144
  this.currentContext = model;
143
145
  this.currentContextRegistry = registry[intent];
144
- this.currentContextComponentArguments = this.createDynamicArgsFromRegistry(registry[intent], model);
146
+ this.currentContextComponentArguments = this.createDynamicArgsFromRegistry(registry[intent], model, dynamicArgs);
145
147
  this.contextOptions = options;
146
148
  }
147
149
  }
@@ -212,7 +214,7 @@ export default class ContextPanelService extends Service {
212
214
  * @param {Object} model - The model object.
213
215
  * @returns {Object} The dynamic arguments.
214
216
  */
215
- createDynamicArgsFromRegistry(registry, model) {
217
+ createDynamicArgsFromRegistry(registry, model, additionalArgs = {}) {
216
218
  // Generate dynamic arguments object
217
219
  const dynamicArgs = {};
218
220
  const componentArguments = registry.componentArguments || [];
@@ -228,6 +230,9 @@ export default class ContextPanelService extends Service {
228
230
  }
229
231
  });
230
232
 
233
+ // Merge additional args
234
+ Object.assign(dynamicArgs, additionalArgs);
235
+
231
236
  return dynamicArgs;
232
237
  }
233
238
  }
@@ -0,0 +1,107 @@
1
+ import Service, { inject as service } from '@ember/service';
2
+ import leafletIcon from '@fleetbase/ember-core/utils/leaflet-icon';
3
+ import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
4
+ import config from '../config/environment';
5
+
6
+ export default class DriverActionsService extends Service {
7
+ @service modalsManager;
8
+ @service universe;
9
+ @service crud;
10
+
11
+ assignOrder(driver, options = {}) {
12
+ this.modalsManager.show('modals/driver-assign-order', {
13
+ title: `Assign Order to this Driver`,
14
+ acceptButtonText: 'Assign Order',
15
+ acceptButtonIcon: 'check',
16
+ acceptButtonIconPrefix: 'fas',
17
+ acceptButtonDisabled: true,
18
+ hideDeclineButton: true,
19
+ selectedOrder: null,
20
+ selectOrder: (order) => {
21
+ this.modalsManager.setOption('selectedOrder', order);
22
+ this.modalsManager.setOption('acceptButtonDisabled', false);
23
+ },
24
+ driver,
25
+ confirm: (modal) => {
26
+ const selectedOrder = modal.getOption('selectedOrder');
27
+ if (!selectedOrder) {
28
+ this.notifications.warning('No order selected!');
29
+ return;
30
+ }
31
+
32
+ modal.startLoading();
33
+ driver.set('current_job_uuid', selectedOrder.id);
34
+
35
+ return driver
36
+ .save()
37
+ .then(() => {
38
+ this.notifications.success(`${driver.name} assigned to order.`);
39
+ })
40
+ .catch((error) => {
41
+ driver.rollbackAttributes();
42
+ modal.stopLoading();
43
+ this.notifications.serverError(error);
44
+ });
45
+ },
46
+ ...options,
47
+ });
48
+ }
49
+
50
+ assignVehicle(driver, options = {}) {
51
+ this.modalsManager.show('modals/driver-assign-vehicle', {
52
+ title: `Assign Vehicle to this Driver`,
53
+ acceptButtonText: 'Confirm & Create',
54
+ acceptButtonIcon: 'check',
55
+ acceptButtonIconPrefix: 'fas',
56
+ hideDeclineButton: true,
57
+ driver,
58
+ confirm: (modal) => {
59
+ modal.startLoading();
60
+
61
+ return driver
62
+ .save()
63
+ .then((driver) => {
64
+ this.notifications.success(`${driver.name} assigned to vehicle.`);
65
+ })
66
+ .catch((error) => {
67
+ driver.rollbackAttributes();
68
+ modal.stopLoading();
69
+ this.notifications.serverError(error);
70
+ });
71
+ },
72
+ ...options,
73
+ });
74
+ }
75
+
76
+ locate(driver, options = {}) {
77
+ const { location } = driver;
78
+ const [latitude, longitude] = location.coordinates;
79
+
80
+ this.modalsManager.show('modals/point-map', {
81
+ title: `Current Location of ${driver.name}`,
82
+ acceptButtonText: 'Done',
83
+ acceptButtonIcon: 'check',
84
+ acceptButtonIconPrefix: 'fas',
85
+ modalClass: 'modal-md',
86
+ hideDeclineButton: true,
87
+ latitude,
88
+ longitude,
89
+ location,
90
+ popupText: `${driver.name} (${driver.public_id})`,
91
+ icon: leafletIcon({
92
+ iconUrl: getWithDefault(driver, 'vehicle_avatar', getWithDefault(config, 'defaultValues.vehicleAvatar')),
93
+ iconSize: [40, 40],
94
+ }),
95
+ ...options,
96
+ });
97
+ }
98
+
99
+ delete(driver, options = {}) {
100
+ this.crud.delete(driver, {
101
+ onSuccess: () => {
102
+ this.universe.trigger('fleet-ops.driver.deleted', driver);
103
+ },
104
+ ...options,
105
+ });
106
+ }
107
+ }
@@ -0,0 +1,42 @@
1
+ import Service, { inject as service } from '@ember/service';
2
+ import leafletIcon from '@fleetbase/ember-core/utils/leaflet-icon';
3
+ import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
4
+ import config from '../config/environment';
5
+
6
+ export default class VehicleActionsService extends Service {
7
+ @service modalsManager;
8
+ @service universe;
9
+ @service crud;
10
+
11
+ locate(vehicle, options = {}) {
12
+ const { location } = vehicle;
13
+ const [latitude, longitude] = location.coordinates;
14
+
15
+ this.modalsManager.show('modals/point-map', {
16
+ title: `Current Location of ${vehicle.displayName}`,
17
+ acceptButtonText: 'Done',
18
+ acceptButtonIcon: 'check',
19
+ acceptButtonIconPrefix: 'fas',
20
+ modalClass: 'modal-md',
21
+ hideDeclineButton: true,
22
+ latitude,
23
+ longitude,
24
+ location,
25
+ popupText: `${vehicle.displayName} (${vehicle.public_id})`,
26
+ icon: leafletIcon({
27
+ iconUrl: getWithDefault(vehicle, 'avatar', getWithDefault(config, 'defaultValues.vehicleAvatar')),
28
+ iconSize: [40, 40],
29
+ }),
30
+ ...options,
31
+ });
32
+ }
33
+
34
+ delete(vehicle, options = {}) {
35
+ this.crud.delete(vehicle, {
36
+ onSuccess: () => {
37
+ this.universe.trigger('fleet-ops.vehicle.deleted', vehicle);
38
+ },
39
+ ...options,
40
+ });
41
+ }
42
+ }
@@ -33,3 +33,30 @@ body[data-theme='dark'] .scheduler-left-sidebar {
33
33
  .fleetbase-console .dragSortList {
34
34
  overflow: visible !important;
35
35
  }
36
+
37
+ .next-content-panel-body > .next-content-panel-body-inner > a.next-nav-item > .next-nav-item-icon-container > svg.online-status,
38
+ .next-content-panel-body > .next-content-panel-body-inner > a.next-nav-item > .next-nav-item-icon-container > svg.text-green-500,
39
+ .next-fleet-summary-fleet .next-content-panel-body > .next-content-panel-body-inner > a.next-nav-item > .next-nav-item-icon-container > svg.text-green-500 {
40
+ color: rgb(34 197 94) !important;
41
+ }
42
+
43
+ .next-content-panel-body > .next-content-panel-body-inner > a.next-nav-item > .next-nav-item-icon-container > svg.idle-status,
44
+ .next-content-panel-body > .next-content-panel-body-inner > a.next-nav-item > .next-nav-item-icon-container > svg.text-yellow-200,
45
+ .next-fleet-summary-fleet .next-content-panel-body > .next-content-panel-body-inner > a.next-nav-item > .next-nav-item-icon-container > svg.text-yellow-200 {
46
+ color: rgb(254 240 138) !important;
47
+ }
48
+
49
+ .next-fleet-summary {
50
+ --fleet-summary-toggle-base-padding: 1.5rem;
51
+ --fleet-summary-nav-item-base-padding: 1.5rem;
52
+ }
53
+
54
+ .next-sidebar-panel-container.next-driver-listing > .next-sidebar-panel > .next-content-panel > .next-sidebar-panel-toggle,
55
+ .next-sidebar .next-sidebar-panel-container.next-fleet-summary > .next-sidebar-panel > .next-content-panel > .next-sidebar-panel-toggle {
56
+ padding-left: 2rem;
57
+ }
58
+
59
+ .next-sidebar-panel-container.next-driver-listing > .next-sidebar-panel > .next-content-panel > .next-content-panel-body .next-nav-item,
60
+ .next-sidebar .next-sidebar-panel-container.next-driver-listing > .next-sidebar-panel > .next-content-panel > .next-sidebar-panel-body .next-nav-item.driver-nav-item {
61
+ padding-left: 3.5rem;
62
+ }
@@ -256,7 +256,7 @@
256
256
 
257
257
  <div class="flex-row space-x-2 pr-0.5">
258
258
  {{#if this.payload.pickup}}
259
- <a href="javascript:;" {{on "click" (fn this.placesController.editPlace this.payload.pickup)}}>
259
+ <a href="javascript:;" {{on "click" (fn this.editPlace this.payload.pickup)}}>
260
260
  <FaIcon @icon="edit" />
261
261
  </a>
262
262
  <a href="javascript:;" {{on "click" (fn this.setPayloadPlace "pickup" null)}}>
@@ -287,7 +287,7 @@
287
287
 
288
288
  <div class="flex-row space-x-2 pr-0.5">
289
289
  {{#if this.payload.dropoff}}
290
- <a href="javascript:;" {{on "click" (fn this.placesController.editPlace this.payload.dropoff)}}>
290
+ <a href="javascript:;" {{on "click" (fn this.editPlace this.payload.dropoff)}}>
291
291
  <FaIcon @icon="edit" />
292
292
  </a>
293
293
  <a href="javascript:;" {{on "click" (fn this.setPayloadPlace "dropoff" null)}}>
@@ -317,7 +317,7 @@
317
317
  <label>Return</label>
318
318
 
319
319
  {{#if this.payload.return}}
320
- <a href="javascript:;" {{on "click" (fn this.placesController.editPlace this.payload.return)}}>Edit Address</a>
320
+ <a href="javascript:;" {{on "click" (fn this.editPlace this.payload.return)}}>Edit Address</a>
321
321
  {{/if}}
322
322
  </div>
323
323
 
@@ -1,4 +1,4 @@
1
- <Overlay @position="right" @noBackdrop={{true}} @isResizable={{true}} @fullHeight={{true}} @width="800px">
1
+ <Overlay @position="right" @noBackdrop={{true}} @isResizable={{true}} @fullHeight={{true}} @width="570px">
2
2
  <Overlay::Header @title={{if this.serviceRate.id this.serviceRate.service_name "New service rate"}} @status={{this.serviceRate.public_id}} @hideStatusDot={{true}} @createdAt={{this.serviceRate.createdAt}} @onPressCancel={{this.transitionBack}}>
3
3
  {{#if this.serviceRate.id}}
4
4
  <Button @icon="save" @type="primary" @text="Save Service Rate" @onClick={{this.updateServiceRate}} @isLoading={{this.isUpdatingServiceRate}} />
@@ -1,3 +1,5 @@
1
+ import { isBlank } from '@ember/utils';
2
+
1
3
  export default function flyToLeafletLayer(map, layer, zoom, options = {}) {
2
4
  if (!map || !layer) {
3
5
  return;
@@ -18,6 +20,11 @@ export default function flyToLeafletLayer(map, layer, zoom, options = {}) {
18
20
  }
19
21
  }
20
22
 
23
+ // set `flyTo` duration
24
+ if (isBlank(options.duration)) {
25
+ options.duration = 5.5;
26
+ }
27
+
21
28
  // Check if we have a valid LatLng
22
29
  if (targetLatLng) {
23
30
  map.flyTo(targetLatLng, zoom, options);
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/layout/fleet-ops-sidebar/driver-listing';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/services/driver-actions';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/services/vehicle-actions';
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/fleetops-api",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "keywords": [
6
6
  "fleetbase-extension",
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "require": {
24
24
  "php": "^7.4|^8.0",
25
- "fleetbase/core-api": "^1.3.4",
25
+ "fleetbase/core-api": "^1.3.7",
26
26
  "barryvdh/laravel-dompdf": "^2.0",
27
27
  "brick/geo": "0.7.2",
28
28
  "cknow/laravel-money": "^7.1",
package/extension.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Fleet-Ops",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "repository": "https://github.com/fleetbase/fleetops",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/fleetops-engine",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "fleet-ops",
@@ -42,9 +42,9 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@babel/core": "^7.23.2",
45
- "@fleetbase/ember-core": "^0.1.9",
46
- "@fleetbase/ember-ui": "^0.2.8",
47
- "@fleetbase/fleetops-data": "^0.1.6",
45
+ "@fleetbase/ember-core": "^0.2.0",
46
+ "@fleetbase/ember-ui": "^0.2.9",
47
+ "@fleetbase/fleetops-data": "^0.1.7",
48
48
  "@fleetbase/leaflet-routing-machine": "^3.2.16",
49
49
  "@fortawesome/ember-fontawesome": "^0.4.1",
50
50
  "@fortawesome/fontawesome-svg-core": "^6.4.0",
@@ -5,7 +5,7 @@ namespace Fleetbase\FleetOps\Casts;
5
5
  use Fleetbase\FleetOps\Support\Utils;
6
6
  use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression;
7
7
  use Grimzy\LaravelMysqlSpatial\Types\GeometryInterface;
8
- use Grimzy\LaravelMysqlSpatial\Types\MultiPolygon as MultiPolygonType;
8
+ use Grimzy\LaravelMysqlSpatial\Types\MultiPolygon as SpatialMultiPolygon;
9
9
  use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
10
10
 
11
11
  class MultiPolygon implements CastsAttributes
@@ -37,14 +37,25 @@ class MultiPolygon implements CastsAttributes
37
37
  return new SpatialExpression($value);
38
38
  }
39
39
 
40
+ if ($value instanceof SpatialMultiPolygon) {
41
+ $model->geometries[$key] = $value;
42
+
43
+ return $value;
44
+ }
45
+
40
46
  if (Utils::isGeoJson($value)) {
41
- return Utils::createSpatialExpressionFromGeoJson($value);
47
+ $value = Utils::createGeometryObjectFromGeoJson($value);
48
+ $model->geometries[$key] = $value;
49
+
50
+ return $value;
42
51
  }
43
52
 
44
53
  if ($value instanceof SpatialExpression) {
54
+ $model->geometries[$key] = $value;
55
+
45
56
  return $value;
46
57
  }
47
58
 
48
- return new SpatialExpression(new MultiPolygonType([]));
59
+ throw new \Exception('Invalid MultiPolygon provided for ' . $key);
49
60
  }
50
61
  }
@@ -50,15 +50,25 @@ class Point implements CastsAttributes
50
50
  }
51
51
 
52
52
  if (Utils::isGeoJson($value)) {
53
- return Utils::createSpatialExpressionFromGeoJson($value);
53
+ $value = Utils::createSpatialExpressionFromGeoJson($value);
54
+ $model->geometries[$key] = $value;
55
+
56
+ return $value;
54
57
  }
55
58
 
56
59
  if (Utils::isCoordinates($value)) {
57
- $point = Utils::getPointFromCoordinates($value);
60
+ $point = Utils::getPointFromCoordinates($value);
61
+ $model->geometries[$key] = $point;
58
62
 
59
63
  return $point;
60
64
  }
61
65
 
66
+ if ($value instanceof SpatialExpression) {
67
+ $model->geometries[$key] = $value;
68
+
69
+ return $value;
70
+ }
71
+
62
72
  return static::createEmptySpatialExpression();
63
73
  }
64
74
 
@@ -5,7 +5,7 @@ namespace Fleetbase\FleetOps\Casts;
5
5
  use Fleetbase\FleetOps\Support\Utils;
6
6
  use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression;
7
7
  use Grimzy\LaravelMysqlSpatial\Types\GeometryInterface;
8
- use Grimzy\LaravelMysqlSpatial\Types\Polygon as PolygonType;
8
+ use Grimzy\LaravelMysqlSpatial\Types\Polygon as SpatialPolygon;
9
9
  use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
10
10
 
11
11
  class Polygon implements CastsAttributes
@@ -34,13 +34,28 @@ class Polygon implements CastsAttributes
34
34
  if ($value instanceof GeometryInterface) {
35
35
  $model->geometries[$key] = $value;
36
36
 
37
- return new SpatialExpression($value);
37
+ return $value;
38
+ }
39
+
40
+ if ($value instanceof SpatialPolygon) {
41
+ $model->geometries[$key] = $value;
42
+
43
+ return $value;
38
44
  }
39
45
 
40
46
  if (Utils::isGeoJson($value)) {
41
- return Utils::createSpatialExpressionFromGeoJson($value);
47
+ $value = Utils::createGeometryObjectFromGeoJson($value);
48
+ $model->geometries[$key] = $value;
49
+
50
+ return $value;
51
+ }
52
+
53
+ if ($value instanceof SpatialExpression) {
54
+ $model->geometries[$key] = $value;
55
+
56
+ return $value;
42
57
  }
43
58
 
44
- return new SpatialExpression(new PolygonType([]));
59
+ throw new \Exception('Invalid Polygon provided for ' . $key);
45
60
  }
46
61
  }
@@ -3,16 +3,60 @@
3
3
  namespace Fleetbase\FleetOps\Exceptions;
4
4
 
5
5
  use Fleetbase\FleetOps\Models\IntegratedVendor;
6
+ use Illuminate\Contracts\Support\Responsable;
7
+ use Illuminate\Http\JsonResponse;
6
8
 
7
- class IntegratedVendorException extends \Exception
9
+ /**
10
+ * Class IntegratedVendorException
11
+ *
12
+ * Custom exception class for IntegratedVendor-related exceptions.
13
+ *
14
+ * @package Fleetbase\FleetOps\Exceptions
15
+ */
16
+ class IntegratedVendorException extends \Exception implements Responsable
8
17
  {
18
+ /**
19
+ * @var IntegratedVendor|null The IntegratedVendor instance associated with the exception.
20
+ */
9
21
  public ?IntegratedVendor $integratedVendor;
22
+
23
+ /**
24
+ * @var string The trigger method that caused the exception.
25
+ */
10
26
  public string $triggerMethod;
11
27
 
28
+ /**
29
+ * IntegratedVendorException constructor.
30
+ *
31
+ * @param string $message The exception message.
32
+ * @param IntegratedVendor|null $integratedVendor The IntegratedVendor instance associated with the exception.
33
+ * @param string|null $triggerMethod The trigger method that caused the exception.
34
+ * @param int $code The exception code.
35
+ * @param \Throwable|null $previous The previous throwable used for the exception chaining.
36
+ */
12
37
  public function __construct(string $message = '', IntegratedVendor $integratedVendor = null, string $triggerMethod = null, int $code = 400, \Throwable $previous = null)
13
38
  {
14
39
  parent::__construct($message, $code, $previous);
15
40
  $this->integratedVendor = $integratedVendor;
16
41
  $this->triggerMethod = $triggerMethod;
17
42
  }
43
+
44
+ /**
45
+ * Get the response representing the exception.
46
+ *
47
+ * @param \Illuminate\Http\Request $request
48
+ * @return \Illuminate\Http\JsonResponse
49
+ */
50
+ public function toResponse($request)
51
+ {
52
+ $errorMessage = $this->getMessage();
53
+
54
+ return new JsonResponse(
55
+ [
56
+ 'errors' => [$errorMessage],
57
+ 'integratedVendorId' => data_get($this->integratedVendor, 'uuid')
58
+ ],
59
+ 400
60
+ );
61
+ }
18
62
  }