@fleetbase/fleetops-engine 0.2.9 → 0.3.1

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 (70) hide show
  1. package/addon/components/context-panel.hbs +1 -1
  2. package/addon/components/driver-card-mini.js +34 -13
  3. package/addon/components/driver-form-panel.hbs +3 -3
  4. package/addon/components/driver-form-panel.js +87 -29
  5. package/addon/components/driver-panel.hbs +5 -5
  6. package/addon/components/driver-panel.js +118 -31
  7. package/addon/components/live-map.js +221 -10
  8. package/addon/components/map-container/toolbar/visibility-control-panel.hbs +66 -0
  9. package/addon/components/map-container/toolbar/visibility-control-panel.js +74 -0
  10. package/addon/components/map-container/toolbar/zones-panel.hbs +10 -10
  11. package/addon/components/map-container/toolbar/zones-panel.js +90 -61
  12. package/addon/components/map-container/toolbar.hbs +12 -7
  13. package/addon/components/modals/vehicle-form.hbs +35 -35
  14. package/addon/components/vehicle-form-panel.hbs +6 -7
  15. package/addon/components/vehicle-form-panel.js +86 -26
  16. package/addon/components/vehicle-panel.hbs +5 -5
  17. package/addon/components/vehicle-panel.js +124 -31
  18. package/addon/controllers/management/drivers/index/details.js +53 -0
  19. package/addon/controllers/management/drivers/index/edit.js +77 -46
  20. package/addon/controllers/management/drivers/index/new.js +39 -79
  21. package/addon/controllers/management/drivers/index.js +17 -221
  22. package/addon/controllers/management/fleets/index/edit.js +1 -1
  23. package/addon/controllers/management/fleets/index/new.js +1 -1
  24. package/addon/controllers/management/fuel-reports/index.js +2 -2
  25. package/addon/controllers/management/vehicles/index/details.js +49 -0
  26. package/addon/controllers/management/vehicles/index/edit.js +104 -1
  27. package/addon/controllers/management/vehicles/index/new.js +71 -0
  28. package/addon/controllers/operations/orders/index/new.js +1 -1
  29. package/addon/controllers/operations/orders/index/view.js +17 -7
  30. package/addon/controllers/operations/orders/index.js +109 -48
  31. package/addon/controllers/operations/service-rates/index/edit.js +1 -1
  32. package/addon/controllers/operations/service-rates/index/new.js +1 -1
  33. package/addon/helpers/is-visibility-control-visible.js +18 -0
  34. package/addon/routes/application.js +1 -1
  35. package/addon/routes/home.js +1 -1
  36. package/addon/routes/management/drivers/index/details.js +5 -0
  37. package/addon/routes/operations/service-rates/index.js +1 -1
  38. package/addon/routes/operations/zones/index.js +1 -1
  39. package/addon/services/context-panel.js +81 -14
  40. package/addon/templates/management/drivers/index/details.hbs +1 -1
  41. package/addon/templates/management/drivers/index/edit.hbs +1 -1
  42. package/addon/templates/management/drivers/index/new.hbs +1 -1
  43. package/addon/templates/management/vehicles/index/details.hbs +1 -1
  44. package/addon/templates/management/vehicles/index/edit.hbs +1 -1
  45. package/addon/templates/management/vehicles/index/new.hbs +1 -1
  46. package/addon/templates/operations/orders/index/view.hbs +2 -2
  47. package/addon/templates/operations/orders/index.hbs +1 -1
  48. package/addon/utils/apply-context-component-arguments.js +31 -0
  49. package/addon/utils/context-component-callback.js +16 -0
  50. package/app/components/map-container/toolbar/visibility-control-panel.js +1 -0
  51. package/app/helpers/is-visibility-control-visible.js +1 -0
  52. package/app/utils/apply-context-component-arguments.js +1 -0
  53. package/app/utils/context-component-callback.js +1 -0
  54. package/composer.json +2 -2
  55. package/extension.json +1 -1
  56. package/package.json +3 -3
  57. package/server/migrations/2023_09_14_074512_update_vehicles_table.php +89 -88
  58. package/server/migrations/2023_10_25_093014_create_vehicle_device_events_table.php +56 -0
  59. package/server/src/Http/Resources/v1/Vehicle.php +1 -0
  60. package/server/src/Models/Fleet.php +2 -0
  61. package/server/src/Models/VehicleDevice.php +17 -3
  62. package/server/src/Models/VehicleDeviceEvent.php +90 -0
  63. package/server/src/Notifications/OrderAssigned.php +21 -0
  64. package/server/src/Notifications/OrderCanceled.php +21 -0
  65. package/server/src/Notifications/OrderDispatchFailed.php +21 -0
  66. package/server/src/Notifications/OrderDispatched.php +21 -0
  67. package/server/src/Notifications/OrderPing.php +21 -0
  68. package/server/src/Notifications/OrderSplit.php +32 -5
  69. package/server/src/Providers/FleetOpsServiceProvider.php +22 -0
  70. package/server/src/Providers/NotificationServiceProvider.php +43 -0
@@ -1,128 +1,88 @@
1
- import Controller, { inject as controller } from '@ember/controller';
2
- import { inject as service } from '@ember/service';
1
+ import Controller from '@ember/controller';
3
2
  import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
4
  import { action } from '@ember/object';
5
- import generateSlug from '@fleetbase/ember-core/utils/generate-slug';
6
5
 
7
6
  export default class ManagementDriversIndexNewController extends Controller {
8
7
  /**
9
- * Inject the `management.drivers.index` controller
8
+ * Inject the `store` service
10
9
  *
11
- * @var {Controller}
12
- */
13
- @controller('management.drivers.index') index;
14
-
15
- /**
16
- * Inject the `currentUser` service
17
- *
18
- * @var {Service}
10
+ * @memberof ManagementDriversIndexNewController
19
11
  */
20
12
  @service store;
21
13
 
22
14
  /**
23
15
  * Inject the `hostRouter` service
24
16
  *
25
- * @var {Service}
17
+ * @memberof ManagementDriversIndexNewController
26
18
  */
27
19
  @service hostRouter;
28
20
 
29
21
  /**
30
- * Inject the `notifications` service
22
+ * Inject the `hostRouter` service
31
23
  *
32
- * @var {Service}
24
+ * @memberof ManagementDriversIndexNewController
33
25
  */
34
- @service notifications;
26
+ @service modalsManager;
35
27
 
36
28
  /**
37
- * Inject the `loader` service
29
+ * The overlay component context.
38
30
  *
39
- * @var {Service}
31
+ * @memberof ManagementDriversIndexNewController
40
32
  */
41
- @service loader;
33
+ @tracked overlay;
42
34
 
43
35
  /**
44
36
  * The driver being created.
45
37
  *
46
38
  * @var {DriverModel}
47
39
  */
48
- @tracked driver = this.store.createRecord('driver', {
49
- status: `active`,
50
- slug: generateSlug(),
51
- });
52
-
53
- /**
54
- * Different service types available, based on order type.
55
- *
56
- * @var {Array}
57
- */
58
- @tracked serviceTypes = [];
59
-
60
- /**
61
- * Service areas.
62
- *
63
- * @var {Array}
64
- */
65
- @tracked serviceAreas = [];
40
+ @tracked driver = this.store.createRecord('driver');
66
41
 
67
42
  /**
68
- * Zones.
43
+ * Set the overlay component context object.
69
44
  *
70
- * @var {Array}
45
+ * @param {OverlayContext} overlay
46
+ * @memberof ManagementDriversIndexNewController
71
47
  */
72
- @tracked zones = [];
48
+ @action setOverlayContext(overlay) {
49
+ this.overlay = overlay;
50
+ }
73
51
 
74
52
  /**
75
- * True if creating driver.
53
+ * When exiting the overlay.
76
54
  *
77
- * @var {Boolean}
55
+ * @return {Transition}
56
+ * @memberof ManagementDriversIndexNewController
78
57
  */
79
- @tracked isCreatingDriver = false;
58
+ @action transitionBack() {
59
+ return this.transitionToRoute('management.drivers.index');
60
+ }
80
61
 
81
62
  /**
82
- * Saves the driver to server
63
+ * Trigger a route refresh and focus the new driver created.
83
64
  *
84
- * @void
65
+ * @param {DriverModel} driver
66
+ * @return {Promise}
67
+ * @memberof ManagementDriversIndexNewController
85
68
  */
86
- @action createDriver() {
87
- const { driver } = this;
88
-
89
- this.isCreatingDriver = true;
90
- this.loader.showLoader('.overlay-inner-content', 'Creating driver...');
91
-
92
- try {
93
- return driver
94
- .save()
95
- .then((driver) => {
96
- return this.transitionToRoute('management.drivers.index').then(() => {
97
- this.notifications.success(`New Driver ${driver.name} Created`);
98
- this.resetForm();
99
- this.hostRouter.refresh();
100
- });
101
- })
102
- .catch((error) => {
103
- console.log(error);
104
- this.notifications.serverError(error);
105
- })
106
- .finally(() => {
107
- this.isCreatingDriver = false;
108
- this.loader.removeLoader();
109
- });
110
- } catch (error) {
111
- this.isCreatingDriver = false;
112
- this.loader.removeLoader();
69
+ @action onAfterSave(driver) {
70
+ if (this.overlay) {
71
+ this.overlay.close();
113
72
  }
73
+
74
+ this.hostRouter.refresh();
75
+ return this.transitionToRoute('management.drivers.index.details', driver).then(() => {
76
+ this.resetForm();
77
+ });
114
78
  }
115
79
 
116
80
  /**
117
- * Resets the driver form
81
+ * Resets the form with a new driver record
118
82
  *
119
- * @void
83
+ * @memberof ManagementDriversIndexNewController
120
84
  */
121
- @action resetForm() {
85
+ resetForm() {
122
86
  this.driver = this.store.createRecord('driver');
123
87
  }
124
-
125
- @action transitionBack() {
126
- return this.transitionToRoute('management.drivers.index');
127
- }
128
88
  }
@@ -88,6 +88,13 @@ export default class ManagementDriversIndexController extends Controller {
88
88
  */
89
89
  @service currentUser;
90
90
 
91
+ /**
92
+ * Inject the `contextPanel` service
93
+ *
94
+ * @var {Service}
95
+ */
96
+ @service contextPanel;
97
+
91
98
  /**
92
99
  * Queryable parameters for this controller's model
93
100
  *
@@ -275,7 +282,16 @@ export default class ManagementDriversIndexController extends Controller {
275
282
  {
276
283
  label: 'Vehicle',
277
284
  cellComponent: 'table/cell/anchor',
278
- action: this.viewDriverVehicle,
285
+ onClick: (driver) => {
286
+ return driver
287
+ .loadVehicle()
288
+ .then((vehicle) => {
289
+ return this.contextPanel.focus(vehicle);
290
+ })
291
+ .catch((error) => {
292
+ this.notifications.serverError(error);
293
+ });
294
+ },
279
295
  valuePath: 'vehicle.display_name',
280
296
  modelNamePath: 'display_name',
281
297
  resizable: true,
@@ -498,132 +514,6 @@ export default class ManagementDriversIndexController extends Controller {
498
514
  @action viewDriver(driver) {
499
515
  return this.transitionToRoute('management.drivers.index.details', driver);
500
516
  }
501
-
502
- // @action viewDriver(driver, options = {}) {
503
- // const viewDriverOnMap = () => {
504
- // this.modalsManager.done().then(() => {
505
- // return this.viewOnMap(driver, {
506
- // onFinish: () => {
507
- // this.viewDriver(driver);
508
- // },
509
- // });
510
- // });
511
- // };
512
-
513
- // this.modalsManager.show('modals/driver-details', {
514
- // title: driver.name,
515
- // titleComponent: 'modal/title-with-buttons',
516
- // acceptButtonText: 'Done',
517
- // acceptButtonIcon: 'check',
518
- // acceptButtonIconPrefix: 'fas',
519
- // hideDeclineButton: true,
520
- // declineButtonIcon: 'times',
521
- // declineButtonIconPrefix: 'fas',
522
- // headerStatus: driver.status,
523
- // headerButtons: [
524
- // {
525
- // icon: 'cog',
526
- // iconPrefix: 'fas',
527
- // type: 'link',
528
- // size: 'xs',
529
- // ddMenuLabel: 'Driver Actions',
530
- // options: [
531
- // {
532
- // title: 'Edit Driver',
533
- // icon: 'edit',
534
- // action: () => {
535
- // this.modalsManager.done().then(() => {
536
- // return this.editDriver(driver, {
537
- // onFinish: () => {
538
- // this.viewDriver(driver);
539
- // },
540
- // });
541
- // });
542
- // },
543
- // },
544
- // {
545
- // separator: true,
546
- // },
547
- // {
548
- // title: 'Assign Order to Driver',
549
- // icon: 'user-check',
550
- // action: () => {
551
- // this.modalsManager.done().then(() => {
552
- // return this.assignOrder(driver, {
553
- // onFinish: () => {
554
- // this.viewDriver(driver);
555
- // },
556
- // });
557
- // });
558
- // },
559
- // },
560
- // {
561
- // title: 'Assign Vehicle to Driver',
562
- // icon: 'car',
563
- // action: () => {
564
- // this.modalsManager.done().then(() => {
565
- // return this.assignVehicle(driver, {
566
- // onFinish: () => {
567
- // this.viewDriver(driver);
568
- // },
569
- // });
570
- // });
571
- // },
572
- // },
573
- // {
574
- // title: 'Locate Driver',
575
- // icon: 'map-pin',
576
- // action: viewDriverOnMap,
577
- // },
578
- // {
579
- // separator: true,
580
- // },
581
- // {
582
- // title: 'Listen to socket channel',
583
- // icon: 'headphones',
584
- // action: () => {
585
- // this.modalsManager.done().then(() => {
586
- // this.hostRouter.transitionTo('console.developers.sockets.view', `driver.${driver.public_id}`);
587
- // });
588
- // },
589
- // },
590
- // {
591
- // separator: true,
592
- // },
593
- // {
594
- // title: 'Delete Driver',
595
- // icon: 'trash',
596
- // action: () => {
597
- // this.modalsManager.done().then(() => {
598
- // return this.deleteDriver(driver, {
599
- // onDecline: () => {
600
- // this.viewDriver(driver);
601
- // },
602
- // });
603
- // });
604
- // },
605
- // },
606
- // ],
607
- // },
608
- // ],
609
- // viewVendor: () =>
610
- // this.viewDriverVendor(driver, {
611
- // onFinish: () => {
612
- // this.viewDriver(driver);
613
- // },
614
- // }),
615
- // viewVehicle: () =>
616
- // this.viewDriverVehicle(driver, {
617
- // onFinish: () => {
618
- // this.viewDriver(driver);
619
- // },
620
- // }),
621
- // viewDriverOnMap,
622
- // driver,
623
- // ...options,
624
- // });
625
- // }
626
-
627
517
  /**
628
518
  * Create a new `driver` in modal
629
519
  *
@@ -632,85 +522,8 @@ export default class ManagementDriversIndexController extends Controller {
632
522
  */
633
523
  @action createDriver() {
634
524
  return this.transitionToRoute('management.drivers.index.new');
635
-
636
- // return this.editDriver(driver, {
637
- // title: 'New Driver',
638
- // acceptButtonText: 'Create',
639
- // acceptButtonIcon: 'check',
640
- // acceptButtonIconPrefix: 'fas',
641
- // successNotification: (driver) => `New driver (${driver.name}) created.`,
642
- // onConfirm: () => {
643
- // return this.hostRouter.refresh();
644
- // },
645
- // });
646
525
  }
647
526
 
648
- // /**
649
- // * Edit a `driver` details
650
- // *
651
- // * @param {DriverModel} driver
652
- // * @param {Object} options
653
- // * @void
654
- // */
655
- // @action editDriver(driver, options = {}) {
656
- // // make sure vehicle is loaded
657
- // driver.loadVehicle();
658
-
659
- // this.modalsManager.show('modals/driver-form', {
660
- // title: 'Edit Driver',
661
- // acceptButtonText: 'Save Changes',
662
- // acceptButtonIcon: 'save',
663
- // declineButtonIcon: 'times',
664
- // declineButtonIconPrefix: 'fas',
665
- // driver,
666
- // uploadNewPhoto: (file) => {
667
- // this.fetch.uploadFile.perform(
668
- // file,
669
- // {
670
- // path: `uploads/${this.currentUser.companyId}/drivers/${driver.slug}`,
671
- // subject_uuid: driver.id,
672
- // subject_type: `driver`,
673
- // type: `driver_photo`,
674
- // },
675
- // (uploadedFile) => {
676
- // driver.setProperties({
677
- // photo_uuid: uploadedFile.id,
678
- // photo_url: uploadedFile.url,
679
- // photo: uploadedFile,
680
- // });
681
- // }
682
- // );
683
- // },
684
- // confirm: (modal, done) => {
685
- // modal.startLoading();
686
-
687
- // if (isBlank(driver.location)) {
688
- // // set default location from currentUser service
689
- // const { latitude, longitude } = this.currentUser;
690
- // driver.set('location', new Point(latitude, longitude));
691
- // }
692
-
693
- // driver
694
- // .save()
695
- // .then((driver) => {
696
- // if (typeof options.successNotification === 'function') {
697
- // this.notifications.success(options.successNotification(driver));
698
- // } else {
699
- // this.notifications.success(options.successNotification || `${driver.name} details updated.`);
700
- // }
701
-
702
- // done();
703
- // })
704
- // .catch((error) => {
705
- // // driver.rollbackAttributes();
706
- // modal.stopLoading();
707
- // this.notifications.serverError(error);
708
- // });
709
- // },
710
- // ...options,
711
- // });
712
- // }
713
-
714
527
  /**
715
528
  * View a `driver` details in modal
716
529
  *
@@ -847,23 +660,6 @@ export default class ManagementDriversIndexController extends Controller {
847
660
  });
848
661
  }
849
662
 
850
- /**
851
- * View information about the drivers assigned vehicle
852
- *
853
- * @param {DriverModel} driver
854
- * @param {Object} options
855
- * @void
856
- */
857
- @action async viewDriverVehicle(driver, options = {}) {
858
- this.modalsManager.displayLoader();
859
-
860
- const vehicle = await this.store.queryRecord('vehicle', driver.vehicle_uuid);
861
-
862
- this.modalsManager.done().then(() => {
863
- return this.vehicles.viewVehicle(vehicle, options);
864
- });
865
- }
866
-
867
663
  /**
868
664
  * View information about the driver vendor
869
665
  *
@@ -49,7 +49,7 @@ export default class ManagementFleetsIndexEditController extends Controller {
49
49
 
50
50
  console.log(model, model);
51
51
  this.isUpdatingFleet = true;
52
- this.loader.showLoader('.overlay-inner-content', 'Updating fleet...');
52
+ this.loader.showLoader('.overlay-inner-content', { loadingMessage: 'Updating fleet...' });
53
53
 
54
54
  try {
55
55
  return model
@@ -62,7 +62,7 @@ export default class ManagementFleetsIndexNewController extends Controller {
62
62
  const { fleet } = this;
63
63
 
64
64
  this.isCreatingFleet = true;
65
- this.loader.showLoader('.overlay-inner-content', 'Creating fleet...');
65
+ this.loader.showLoader('.overlay-inner-content', { loadingMessage: 'Creating fleet...' });
66
66
 
67
67
  try {
68
68
  return fleet
@@ -319,7 +319,7 @@ export default class ManagementFuelReportsIndexController extends Controller {
319
319
  return this.notifications.warning('No driver attributed to fuel report.');
320
320
  }
321
321
 
322
- this.loader.show('Loading...');
322
+ this.loader.show({ loadingMessage: 'Loading...' });
323
323
  const driver = await this.store.findRecord('driver', fuelReport.driver_uuid);
324
324
  this.loader.removeLoader();
325
325
 
@@ -332,7 +332,7 @@ export default class ManagementFuelReportsIndexController extends Controller {
332
332
  return this.notifications.warning('No vehicle attributed to fuel report.');
333
333
  }
334
334
 
335
- this.loader.show('Loading...');
335
+ this.loader.show({ loadingMessage: 'Loading...' });
336
336
  const vehicle = await this.store.findRecord('vehicle', fuelReport.vehicle_uuid);
337
337
  this.loader.remove();
338
338
 
@@ -2,11 +2,60 @@ import Controller from '@ember/controller';
2
2
  import { tracked } from '@glimmer/tracking';
3
3
  import { action } from '@ember/object';
4
4
 
5
+ /**
6
+ * Controller for managing the details view within the "Management -> Vehicles -> Index" route.
7
+ *
8
+ * @class ManagementVehiclesIndexDetailsController
9
+ * @extends Controller
10
+ */
5
11
  export default class ManagementVehiclesIndexDetailsController extends Controller {
12
+ /**
13
+ * The currently active view tab ('details' by default).
14
+ *
15
+ * @type {String}
16
+ * @tracked
17
+ */
6
18
  @tracked view = 'details';
19
+
20
+ /**
21
+ * An array of query parameters to be serialized in the URL.
22
+ *
23
+ * @type {String[]}
24
+ * @tracked
25
+ */
7
26
  @tracked queryParams = ['view'];
8
27
 
28
+ /**
29
+ * Transitions back to the "management.vehicles.index" route.
30
+ *
31
+ * @method
32
+ * @action
33
+ * @returns {Transition} The transition object representing the route change.
34
+ */
9
35
  @action transitionBack() {
10
36
  return this.transitionToRoute('management.vehicles.index');
11
37
  }
38
+
39
+ /**
40
+ * Transitions to the edit view for a specific vehicle.
41
+ *
42
+ * @method
43
+ * @param {VehicleModel} vehicle - The vehicle to be edited.
44
+ * @action
45
+ * @returns {Transition} The transition object representing the route change.
46
+ */
47
+ @action onEdit(vehicle) {
48
+ return this.transitionToRoute('management.vehicles.index.edit', vehicle);
49
+ }
50
+
51
+ /**
52
+ * Updates the active view tab.
53
+ *
54
+ * @method
55
+ * @param {String} tab - The name of the tab to activate.
56
+ * @action
57
+ */
58
+ @action onTabChanged(tab) {
59
+ this.view = tab;
60
+ }
12
61
  }
@@ -1,8 +1,111 @@
1
1
  import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
2
4
  import { action } from '@ember/object';
3
5
 
4
6
  export default class ManagementVehiclesIndexEditController extends Controller {
5
- @action transitionBack() {
7
+ /**
8
+ * Inject the `hostRouter` service
9
+ *
10
+ * @memberof ManagementVehiclesIndexEditController
11
+ */
12
+ @service hostRouter;
13
+
14
+ /**
15
+ * Inject the `hostRouter` service
16
+ *
17
+ * @memberof ManagementVehiclesIndexEditController
18
+ */
19
+ @service modalsManager;
20
+
21
+ /**
22
+ * The overlay component context.
23
+ *
24
+ * @memberof ManagementVehiclesIndexEditController
25
+ */
26
+ @tracked overlay;
27
+
28
+ /**
29
+ * When exiting the overlay.
30
+ *
31
+ * @return {Transition}
32
+ * @memberof ManagementVehiclesIndexEditController
33
+ */
34
+ @action transitionBack(vehicle) {
35
+ // check if vehicle record has been edited and prompt for confirmation
36
+ if (vehicle.hasDirtyAttributes) {
37
+ return this.confirmContinueWithUnsavedChanges(vehicle, {
38
+ confirm: () => {
39
+ vehicle.rollbackAttributes();
40
+ return this.transitionToRoute('management.vehicles.index');
41
+ },
42
+ });
43
+ }
44
+
6
45
  return this.transitionToRoute('management.vehicles.index');
7
46
  }
47
+
48
+ /**
49
+ * Set the overlay component context object.
50
+ *
51
+ * @param {OverlayContext} overlay
52
+ * @memberof ManagementVehiclesIndexEditController
53
+ */
54
+ @action setOverlayContext(overlay) {
55
+ this.overlay = overlay;
56
+ }
57
+
58
+ /**
59
+ * When vehicle details button is clicked in overlay.
60
+ *
61
+ * @param {VehicleModel} vehicle
62
+ * @return {Promise}
63
+ * @memberof ManagementVehiclesIndexEditController
64
+ */
65
+ @action onViewDetails(vehicle) {
66
+ // check if vehicle record has been edited and prompt for confirmation
67
+ if (vehicle.hasDirtyAttributes) {
68
+ return this.confirmContinueWithUnsavedChanges(vehicle);
69
+ }
70
+
71
+ return this.transitionToRoute('management.vehicles.index.details', vehicle);
72
+ }
73
+
74
+ /**
75
+ * Trigger a route refresh and focus the new vehicle created.
76
+ *
77
+ * @param {VehicleModel} vehicle
78
+ * @return {Promise}
79
+ * @memberof ManagementVehiclesIndexEditController
80
+ */
81
+ @action onAfterSave(vehicle) {
82
+ if (this.overlay) {
83
+ this.overlay.close();
84
+ }
85
+
86
+ this.hostRouter.refresh();
87
+ return this.transitionToRoute('management.vehicles.index.details', vehicle);
88
+ }
89
+
90
+ /**
91
+ * Prompts the user to confirm if they wish to continue with unsaved changes.
92
+ *
93
+ * @method
94
+ * @param {VehicleModel} vehicle - The vehicle object with unsaved changes.
95
+ * @param {Object} [options={}] - Additional options for configuring the modal.
96
+ * @returns {Promise} A promise that resolves when the user confirms, and transitions to a new route.
97
+ * @memberof ManagementVehiclesIndexEditController
98
+ */
99
+ confirmContinueWithUnsavedChanges(vehicle, options = {}) {
100
+ return this.modalsManager.confirm({
101
+ title: 'Continue Without Saving?',
102
+ body: 'Unsaved changes to this vehicle will be lost. Click continue to proceed.',
103
+ acceptButtonText: 'Continue without saving',
104
+ confirm: () => {
105
+ vehicle.rollbackAttributes();
106
+ return this.transitionToRoute('management.vehicles.index.details', vehicle);
107
+ },
108
+ ...options,
109
+ });
110
+ }
8
111
  }