@fleetbase/fleetops-engine 0.2.7 → 0.2.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.
- package/README.md +3 -3
- package/addon/components/context-panel.hbs +5 -0
- package/addon/components/context-panel.js +6 -0
- package/addon/components/driver-form-panel.hbs +22 -22
- package/addon/components/driver-form-panel.js +28 -3
- package/addon/components/driver-panel.hbs +8 -8
- package/addon/components/driver-panel.js +23 -6
- package/addon/components/fleet-vehicle-listing.hbs +1 -1
- package/addon/components/live-map.hbs +20 -9
- package/addon/components/live-map.js +1045 -354
- package/addon/components/settings-window.hbs +1 -1
- package/addon/components/vehicle-form-panel.hbs +24 -24
- package/addon/components/vehicle-form-panel.js +26 -3
- package/addon/components/vehicle-panel.hbs +8 -9
- package/addon/components/vehicle-panel.js +21 -4
- package/addon/controllers/operations/orders/index/new.js +3 -5
- package/addon/controllers/operations/orders/index/view.js +5 -7
- package/addon/controllers/operations/orders/index.js +15 -2
- package/addon/engine.js +6 -0
- package/addon/routes/operations/orders/index/view.js +4 -2
- package/addon/routes/operations/orders/index.js +5 -1
- package/addon/services/context-panel.js +106 -0
- package/addon/services/leaflet-contextmenu-manager.js +311 -0
- package/addon/services/leaflet-map-manager.js +61 -0
- package/addon/services/service-areas.js +242 -32
- package/addon/templates/application.hbs +2 -1
- package/addon/utils/find-leaflet-layer.js +13 -0
- package/addon/utils/fly-to-leaflet-layer.js +25 -0
- package/addon/utils/get-leaflet-layer-by-id.js +12 -0
- package/addon/utils/layer-can-bind-contextmenu.js +3 -0
- package/app/components/context-panel.js +1 -0
- package/app/services/context-panel.js +1 -0
- package/app/services/leaflet-contextmenu-manager.js +1 -0
- package/app/services/leaflet-map-manager.js +1 -0
- package/app/utils/find-leaflet-layer.js +1 -0
- package/app/utils/fly-to-leaflet-layer.js +1 -0
- package/app/utils/get-leaflet-layer-by-id.js +1 -0
- package/app/utils/layer-can-bind-contextmenu.js +1 -0
- package/composer.json +12 -2
- package/extension.json +1 -1
- package/package.json +2 -2
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +7 -4
- package/server/src/Http/Filter/VehicleFilter.php +7 -0
- package/server/src/Http/Resources/v1/Vehicle.php +51 -39
- package/.php-cs-fixer.cache +0 -1
- package/addon/services/map-manager.js +0 -3
- package/app/services/map-manager.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<Overlay @onLoad={{this.onLoad}} @isOpen={{@isOpen}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizable={{true}} @isMaximizable={{true}} @isMinimizable={{true}} as |overlay|>
|
|
1
|
+
<Overlay @onLoad={{this.onLoad}} @isOpen={{@isOpen}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizable={{true}} @isMaximizable={{true}} @isMinimizable={{true}} @width="600px" as |overlay|>
|
|
2
2
|
<Overlay::Header @overlay={{overlay}} @title="FleetOps Settings" @onPressCancel={{@onPressCancel}}>
|
|
3
3
|
<Button @icon="save" @type="primary" @text={{if (media 'isMobile') "" "Save Changes"}} @onClick={{this.saveSettings}} @isLoading={{this.isSaving}} @disabled={{or this.isLoading this.isSaving}} />
|
|
4
4
|
</Overlay::Header>
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
<Overlay @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="
|
|
1
|
+
<Overlay @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizeble={{or this.isResizable @isResizable}} @width={{or this.width @width "600px"}}>
|
|
2
2
|
<Overlay::Header @hideLeftSection={{true}} @actionsWrapperClass="flex-1 flex-col py-3" class="h-auto-i min-h-[127px]">
|
|
3
3
|
<div class="flex flex-row items-center justify-between w-full mb-4">
|
|
4
4
|
<div class="flex flex-1 space-x-2">
|
|
5
|
-
{{#if
|
|
5
|
+
{{#if this.vehicle.id}}
|
|
6
6
|
<Button @type="default" @icon="car" @helpText="View vehicle details" @onClick={{this.viewDetails}} />
|
|
7
7
|
{{/if}}
|
|
8
8
|
</div>
|
|
9
9
|
<div class="flex flex-1 justify-end">
|
|
10
10
|
<div class="mr-2">
|
|
11
|
-
<Button @icon={{if
|
|
11
|
+
<Button @icon={{if this.vehicle.id "save" "check"}} @type="primary" @text={{if this.vehicle.id "Save Vehicle" "Create Vehicle"}} @onClick={{this.save}} />
|
|
12
12
|
</div>
|
|
13
|
-
<Button @type="default" @icon="times" @helpText={{if
|
|
13
|
+
<Button @type="default" @icon="times" @helpText={{if this.vehicle.id "Cancel edit vehicle" "Cancel new vehicle"}} @onClick={{@onPressCancel}} />
|
|
14
14
|
</div>
|
|
15
15
|
</div>
|
|
16
16
|
<div class="flex flex-row justify-between w-full">
|
|
17
17
|
<div class="flex flex-col flex-1 w-3/4">
|
|
18
18
|
<div class="flex flex-row">
|
|
19
19
|
<div class="w-14 flex items-center justify-center">
|
|
20
|
-
<Image src={{
|
|
20
|
+
<Image src={{this.vehicle.photo_url}} @fallbackSrc={{config "defaultValues.vehicleImage"}} alt={{this.vehicle.name}} height="48" width="48" class="h-12 w-12" />
|
|
21
21
|
<Attach::Tooltip @class="clean" @animation="scale" @placement={{"top"}}>
|
|
22
|
-
<InputInfo @text={{
|
|
22
|
+
<InputInfo @text={{this.vehicle.public_id}} />
|
|
23
23
|
</Attach::Tooltip>
|
|
24
24
|
</div>
|
|
25
25
|
<div class="flex flex-col">
|
|
26
26
|
<h1 class="text-gray-900 dark:text-white text-2xl">
|
|
27
|
-
{{#if
|
|
28
|
-
{{
|
|
27
|
+
{{#if this.vehicle.id}}
|
|
28
|
+
{{this.vehicle.displayName}}
|
|
29
29
|
{{else}}
|
|
30
|
-
{{#if
|
|
31
|
-
{{
|
|
30
|
+
{{#if this.vehicle.displayName}}
|
|
31
|
+
{{this.vehicle.displayName}}
|
|
32
32
|
{{else}}
|
|
33
33
|
<span>New Vehicle</span>
|
|
34
34
|
{{/if}}
|
|
35
35
|
{{/if}}
|
|
36
36
|
</h1>
|
|
37
37
|
<div class="-mt-1">
|
|
38
|
-
{{#if
|
|
38
|
+
{{#if this.vehicle.driver}}
|
|
39
39
|
<div class="flex flex-row items-center">
|
|
40
|
-
<span class="text-sm dark:text-gray-500 text-gray-700 mr-3">{{
|
|
40
|
+
<span class="text-sm dark:text-gray-500 text-gray-700 mr-3">{{this.vehicle.driver.name}}</span>
|
|
41
41
|
</div>
|
|
42
42
|
{{else}}
|
|
43
43
|
<div class="flex flex-row items-center">
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
</div>
|
|
50
50
|
</div>
|
|
51
51
|
<div class="flex justify-end w-1/4">
|
|
52
|
-
<Badge @status={{
|
|
52
|
+
<Badge @status={{this.vehicle.status}} />
|
|
53
53
|
</div>
|
|
54
54
|
</div>
|
|
55
55
|
</Overlay::Header>
|
|
@@ -62,50 +62,50 @@
|
|
|
62
62
|
<label>
|
|
63
63
|
Internal ID
|
|
64
64
|
</label>
|
|
65
|
-
<Input @value={{
|
|
65
|
+
<Input @value={{this.vehicle.internal_id}} @type="text" class="w-full form-input" placeholder="Internal ID" />
|
|
66
66
|
</div>
|
|
67
67
|
|
|
68
68
|
<div class="input-group mb-2">
|
|
69
69
|
<label>
|
|
70
70
|
Plate Number
|
|
71
71
|
</label>
|
|
72
|
-
<Input @value={{
|
|
72
|
+
<Input @value={{this.vehicle.plate_number}} @type="text" class="w-full form-input" placeholder="Plate Number" />
|
|
73
73
|
</div>
|
|
74
74
|
|
|
75
75
|
<div class="input-group mb-2">
|
|
76
76
|
<label>
|
|
77
77
|
VIN Number
|
|
78
78
|
</label>
|
|
79
|
-
<Input @value={{
|
|
79
|
+
<Input @value={{this.vehicle.vin}} @type="text" class="w-full form-input" placeholder="VIN Number" />
|
|
80
80
|
</div>
|
|
81
81
|
|
|
82
82
|
<div class="input-group mb-2">
|
|
83
83
|
<label>
|
|
84
84
|
Make
|
|
85
85
|
</label>
|
|
86
|
-
<Input @value={{
|
|
86
|
+
<Input @value={{this.vehicle.make}} @type="text" class="w-full form-input" placeholder="Vehicle Make" />
|
|
87
87
|
</div>
|
|
88
88
|
|
|
89
89
|
<div class="input-group mb-2">
|
|
90
90
|
<label>
|
|
91
91
|
Model
|
|
92
92
|
</label>
|
|
93
|
-
<Input @value={{
|
|
93
|
+
<Input @value={{this.vehicle.model}} @type="text" class="w-full form-input" placeholder="Vehicle Model" />
|
|
94
94
|
</div>
|
|
95
95
|
|
|
96
96
|
<div class="input-group mb-2">
|
|
97
97
|
<label>
|
|
98
98
|
Year
|
|
99
99
|
</label>
|
|
100
|
-
<Input @value={{
|
|
100
|
+
<Input @value={{this.vehicle.year}} @type="text" class="w-full form-input" placeholder="Vehicle Year" />
|
|
101
101
|
</div>
|
|
102
102
|
|
|
103
103
|
<div class="input-group mb-2">
|
|
104
104
|
<label>
|
|
105
105
|
Driver Assigned
|
|
106
106
|
</label>
|
|
107
|
-
<ModelSelect @modelName="driver" @selectedModel={{
|
|
108
|
-
|
|
107
|
+
<ModelSelect @modelName="driver" @selectedModel={{this.vehicle.driver}} @placeholder="Select Driver" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut
|
|
108
|
+
this.vehicle.driver)}} as |model|>
|
|
109
109
|
{{model.name}}
|
|
110
110
|
</ModelSelect>
|
|
111
111
|
</div>
|
|
@@ -116,13 +116,13 @@
|
|
|
116
116
|
<div class="grid grid-cols-1 gap-4 lg:grid-cols-2 lg:gap-2">
|
|
117
117
|
<div class="input-group mb-2">
|
|
118
118
|
<InputLabel @labelText="Select map avatar" @helpText="Select an avatar to be used for rendering on maps when using geolocation tracking features." />
|
|
119
|
-
<FetchSelect class="w-60" @placeholder="Select avatar" @path="vehicles/avatars" @value={{
|
|
120
|
-
|
|
119
|
+
<FetchSelect class="w-60" @placeholder="Select avatar" @path="vehicles/avatars" @value={{this.vehicle.avatar_url}} @onSelect={{fn (mut
|
|
120
|
+
this.vehicle.avatar_url)}} as |option key|>
|
|
121
121
|
{{titleize (humanize key)}}
|
|
122
122
|
</FetchSelect>
|
|
123
123
|
</div>
|
|
124
124
|
<div>
|
|
125
|
-
<img alt={{
|
|
125
|
+
<img alt={{this.vehicle.public_id}} src={{this.vehicle.avatar_url}} class="w-24 h-24" />
|
|
126
126
|
</div>
|
|
127
127
|
</div>
|
|
128
128
|
</ContentPanel>
|
|
@@ -7,9 +7,33 @@ export default class VehicleFormPanelComponent extends Component {
|
|
|
7
7
|
@service notifications;
|
|
8
8
|
@service hostRouter;
|
|
9
9
|
@service loader;
|
|
10
|
+
@service contextPanel;
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
super(...arguments);
|
|
14
|
+
this.vehicle = this.args.vehicle;
|
|
15
|
+
this.applyDynamicArguments();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
applyDynamicArguments() {
|
|
19
|
+
// Apply context if available
|
|
20
|
+
if (this.args.context) {
|
|
21
|
+
this.vehicle = this.args.context;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Apply dynamic arguments if available
|
|
25
|
+
if (this.args.dynamicArgs) {
|
|
26
|
+
const keys = Object.keys(this.args.dynamicArgs);
|
|
27
|
+
|
|
28
|
+
keys.forEach((key) => {
|
|
29
|
+
this[key] = this.args.dynamicArgs[key];
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
10
33
|
|
|
11
34
|
@action save() {
|
|
12
|
-
const {
|
|
35
|
+
const { onAfterSave } = this.args;
|
|
36
|
+
const { vehicle } = this;
|
|
13
37
|
|
|
14
38
|
this.loader.showLoader('.overlay-inner-content', 'Saving vehicle...');
|
|
15
39
|
|
|
@@ -33,7 +57,6 @@ export default class VehicleFormPanelComponent extends Component {
|
|
|
33
57
|
}
|
|
34
58
|
|
|
35
59
|
@action viewDetails() {
|
|
36
|
-
|
|
37
|
-
return this.hostRouter.transitionTo('console.fleet-ops.management.vehicles.index.details', vehicle.public_id);
|
|
60
|
+
this.contextPanel.focus(this.vehicle, 'viewing');
|
|
38
61
|
}
|
|
39
62
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
<Overlay @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="
|
|
1
|
+
<Overlay @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizable={{or this.isResizable @isResizable}} @width={{or this.width @width "600px"}}>
|
|
2
2
|
<Overlay::Header @hideLeftSection={{true}} @actionsWrapperClass="flex-1 flex-col py-3" class="h-auto-i min-h-[127px]">
|
|
3
3
|
<div class="flex flex-row items-center justify-between w-full mb-4">
|
|
4
4
|
<div class="flex flex-1 space-x-2">
|
|
5
|
-
{{!-- <Button @type="default" @icon="location-arrow" @helpText="Locate vehicle" @onClick={{@onPressCancel}} /> --}}
|
|
6
5
|
<Button @type="default" @icon="pen" @helpText="Edit vehicle" @onClick={{this.editVehicle}} />
|
|
7
6
|
</div>
|
|
8
7
|
<div class="flex flex-1 justify-end">
|
|
@@ -13,17 +12,17 @@
|
|
|
13
12
|
<div class="flex flex-col flex-1 w-3/4">
|
|
14
13
|
<div class="flex flex-row">
|
|
15
14
|
<div class="w-14 flex items-center justify-center">
|
|
16
|
-
<Image src={{
|
|
15
|
+
<Image src={{this.vehicle.photo_url}} @fallbackSrc={{this.vehicle.avatar_url}} alt={{this.vehicle.name}} height="48" width="48" class="h-12 w-12" />
|
|
17
16
|
<Attach::Tooltip @class="clean" @animation="scale" @placement={{"top"}}>
|
|
18
|
-
<InputInfo @text={{
|
|
17
|
+
<InputInfo @text={{this.vehicle.public_id}} />
|
|
19
18
|
</Attach::Tooltip>
|
|
20
19
|
</div>
|
|
21
20
|
<div class="flex flex-col">
|
|
22
|
-
<h1 class="text-gray-900 dark:text-white text-2xl">{{
|
|
21
|
+
<h1 class="text-gray-900 dark:text-white text-2xl">{{this.vehicle.display_name}}</h1>
|
|
23
22
|
<div class="-mt-1">
|
|
24
|
-
{{#if
|
|
23
|
+
{{#if this.vehicle.driver}}
|
|
25
24
|
<div class="flex flex-row items-center">
|
|
26
|
-
<span class="text-sm dark:text-gray-500 text-gray-700 mr-3">{{
|
|
25
|
+
<span class="text-sm dark:text-gray-500 text-gray-700 mr-3">{{this.vehicle.driver.name}}</span>
|
|
27
26
|
</div>
|
|
28
27
|
{{else}}
|
|
29
28
|
<div class="flex flex-row items-center">
|
|
@@ -36,7 +35,7 @@
|
|
|
36
35
|
</div>
|
|
37
36
|
</div>
|
|
38
37
|
<div class="flex justify-end w-1/4">
|
|
39
|
-
<Badge @status={{
|
|
38
|
+
<Badge @status={{this.vehicle.status}} />
|
|
40
39
|
</div>
|
|
41
40
|
</div>
|
|
42
41
|
</Overlay::Header>
|
|
@@ -54,7 +53,7 @@
|
|
|
54
53
|
</div>
|
|
55
54
|
</div>
|
|
56
55
|
<div class="tab-content tab-{{this.currentTab}}">
|
|
57
|
-
{{component this.tab.component vehicle
|
|
56
|
+
{{component this.tab.component vehicle=this.vehicle tabOptions=this.tab params=this.tab.componentParams}}
|
|
58
57
|
</div>
|
|
59
58
|
</Overlay::Body>
|
|
60
59
|
</Overlay>
|
|
@@ -11,6 +11,7 @@ export default class VehiclePanelComponent extends Component {
|
|
|
11
11
|
@service universe;
|
|
12
12
|
@service store;
|
|
13
13
|
@service hostRouter;
|
|
14
|
+
@service contextPanel;
|
|
14
15
|
@tracked currentTab;
|
|
15
16
|
@tracked devices = [];
|
|
16
17
|
@tracked deviceApi = {};
|
|
@@ -39,10 +40,27 @@ export default class VehiclePanelComponent extends Component {
|
|
|
39
40
|
constructor() {
|
|
40
41
|
super(...arguments);
|
|
41
42
|
this.vehicle = this.args.vehicle;
|
|
42
|
-
this.changeTab(this.args.tab
|
|
43
|
+
this.changeTab(this.args.tab);
|
|
44
|
+
this.applyDynamicArguments();
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
applyDynamicArguments() {
|
|
48
|
+
// Apply context if available
|
|
49
|
+
if (this.args.context) {
|
|
50
|
+
this.vehicle = this.args.context;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Apply dynamic arguments if available
|
|
54
|
+
if (this.args.dynamicArgs) {
|
|
55
|
+
const keys = Object.keys(this.args.dynamicArgs);
|
|
56
|
+
|
|
57
|
+
keys.forEach((key) => {
|
|
58
|
+
this[key] = this.args.dynamicArgs[key];
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@action async changeTab(tab = 'details') {
|
|
46
64
|
this.currentTab = tab;
|
|
47
65
|
|
|
48
66
|
if (typeof this.args.onTabChanged === 'function') {
|
|
@@ -51,7 +69,6 @@ export default class VehiclePanelComponent extends Component {
|
|
|
51
69
|
}
|
|
52
70
|
|
|
53
71
|
@action editVehicle() {
|
|
54
|
-
|
|
55
|
-
return this.hostRouter.transitionTo('console.fleet-ops.management.vehicles.index.edit', vehicle.public_id);
|
|
72
|
+
this.contextPanel.focus(this.vehicle, 'editing');
|
|
56
73
|
}
|
|
57
74
|
}
|
|
@@ -567,8 +567,7 @@ export default class OperationsOrdersIndexNewController extends Controller {
|
|
|
567
567
|
|
|
568
568
|
@action setupInterface() {
|
|
569
569
|
if (this.leafletMap && this.leafletMap.liveMap) {
|
|
570
|
-
this.leafletMap.liveMap.
|
|
571
|
-
this.leafletMap.liveMap.hideRoutes();
|
|
570
|
+
this.leafletMap.liveMap.hideAll();
|
|
572
571
|
|
|
573
572
|
// track all layers added from this view
|
|
574
573
|
this.leafletMap.on('layeradd', ({ layer }) => {
|
|
@@ -585,7 +584,7 @@ export default class OperationsOrdersIndexNewController extends Controller {
|
|
|
585
584
|
});
|
|
586
585
|
} else {
|
|
587
586
|
// setup interface when livemap is ready
|
|
588
|
-
this.universe.on('livemap.ready', () => {
|
|
587
|
+
this.universe.on('fleetops.livemap.ready', () => {
|
|
589
588
|
this.setupInterface();
|
|
590
589
|
});
|
|
591
590
|
}
|
|
@@ -596,8 +595,7 @@ export default class OperationsOrdersIndexNewController extends Controller {
|
|
|
596
595
|
|
|
597
596
|
@action resetInterface() {
|
|
598
597
|
if (this.leafletMap && this.leafletMap.liveMap) {
|
|
599
|
-
this.leafletMap.liveMap.
|
|
600
|
-
this.leafletMap.liveMap.showRoutes();
|
|
598
|
+
this.leafletMap.liveMap.show(['drivers', 'vehicles', 'routes']);
|
|
601
599
|
}
|
|
602
600
|
}
|
|
603
601
|
|
|
@@ -170,8 +170,7 @@ export default class OperationsOrdersIndexViewController extends Controller {
|
|
|
170
170
|
|
|
171
171
|
@action resetInterface() {
|
|
172
172
|
if (this.leafletMap && this.leafletMap.liveMap) {
|
|
173
|
-
this.leafletMap.liveMap.
|
|
174
|
-
this.leafletMap.liveMap.showRoutes();
|
|
173
|
+
this.leafletMap.liveMap.show(['drivers', 'routes']);
|
|
175
174
|
}
|
|
176
175
|
}
|
|
177
176
|
|
|
@@ -219,8 +218,7 @@ export default class OperationsOrdersIndexViewController extends Controller {
|
|
|
219
218
|
this,
|
|
220
219
|
() => {
|
|
221
220
|
if (this.leafletMap && this.leafletMap.liveMap) {
|
|
222
|
-
this.leafletMap.liveMap.
|
|
223
|
-
this.leafletMap.liveMap.hideRoutes();
|
|
221
|
+
this.leafletMap.liveMap.hideAll();
|
|
224
222
|
}
|
|
225
223
|
|
|
226
224
|
// display order route on map
|
|
@@ -236,14 +234,14 @@ export default class OperationsOrdersIndexViewController extends Controller {
|
|
|
236
234
|
};
|
|
237
235
|
|
|
238
236
|
// re-display order routes when livemap has coordinates
|
|
239
|
-
this.universe.on('livemap.has_coordinates', this, displayOrderRoute);
|
|
237
|
+
this.universe.on('fleetops.livemap.has_coordinates', this, displayOrderRoute);
|
|
240
238
|
|
|
241
239
|
// when transitioning away kill event listener
|
|
242
240
|
this.hostRouter.on('routeWillChange', () => {
|
|
243
|
-
const isListening = this.universe.has('livemap.has_coordinates');
|
|
241
|
+
const isListening = this.universe.has('fleetops.livemap.has_coordinates');
|
|
244
242
|
|
|
245
243
|
if (isListening) {
|
|
246
|
-
this.universe.off('livemap.has_coordinates', this, displayOrderRoute);
|
|
244
|
+
this.universe.off('fleetops.livemap.has_coordinates', this, displayOrderRoute);
|
|
247
245
|
}
|
|
248
246
|
});
|
|
249
247
|
|
|
@@ -113,6 +113,20 @@ export default class OperationsOrdersIndexController extends Controller {
|
|
|
113
113
|
'layout',
|
|
114
114
|
];
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* The current driver being focused.
|
|
118
|
+
*
|
|
119
|
+
* @var {DriverModel|null}
|
|
120
|
+
*/
|
|
121
|
+
@tracked focusedDriver;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The current vehicle being focused.
|
|
125
|
+
*
|
|
126
|
+
* @var {VehicleModel|null}
|
|
127
|
+
*/
|
|
128
|
+
@tracked focusedVehicle;
|
|
129
|
+
|
|
116
130
|
/**
|
|
117
131
|
* The current page of data being viewed
|
|
118
132
|
*
|
|
@@ -628,8 +642,7 @@ export default class OperationsOrdersIndexController extends Controller {
|
|
|
628
642
|
|
|
629
643
|
@action resetView() {
|
|
630
644
|
if (this.leafletMap && this.leafletMap.liveMap) {
|
|
631
|
-
this.leafletMap.liveMap.
|
|
632
|
-
this.leafletMap.liveMap.hideRoutes();
|
|
645
|
+
this.leafletMap.liveMap.hideAll();
|
|
633
646
|
}
|
|
634
647
|
}
|
|
635
648
|
|
package/addon/engine.js
CHANGED
|
@@ -42,6 +42,12 @@ export default class FleetOpsEngine extends Engine {
|
|
|
42
42
|
|
|
43
43
|
// register the driver panel
|
|
44
44
|
universe.createRegistry('component:driver-panel');
|
|
45
|
+
|
|
46
|
+
// register vehicle context menu
|
|
47
|
+
universe.createRegistry('contextmenu:vehicle');
|
|
48
|
+
|
|
49
|
+
// register driver context menu
|
|
50
|
+
universe.createRegistry('contextmenu:driver');
|
|
45
51
|
};
|
|
46
52
|
}
|
|
47
53
|
|
|
@@ -8,8 +8,10 @@ export default class OperationsOrdersIndexViewRoute extends Route {
|
|
|
8
8
|
@service store;
|
|
9
9
|
@service socket;
|
|
10
10
|
|
|
11
|
-
@action willTransition() {
|
|
12
|
-
|
|
11
|
+
@action willTransition(transition) {
|
|
12
|
+
const shouldReset = typeof transition.to.name === 'string' && !transition.to.name.includes('operations.orders');
|
|
13
|
+
|
|
14
|
+
if (this.controller && shouldReset) {
|
|
13
15
|
this.controller.resetView();
|
|
14
16
|
}
|
|
15
17
|
}
|
|
@@ -28,7 +28,11 @@ export default class OperationsOrdersIndexRoute extends Route {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
@action willTransition(transition) {
|
|
31
|
-
|
|
31
|
+
const shouldReset = typeof transition.to.name === 'string' && !transition.to.name.includes('operations.orders');
|
|
32
|
+
|
|
33
|
+
if (this.controller && shouldReset) {
|
|
34
|
+
this.controller.resetView(transition);
|
|
35
|
+
}
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
@action model(params) {
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import Service from '@ember/service';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
import getModelName from '@fleetbase/ember-core/utils/get-model-name';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Service to manage the context panel in the application.
|
|
8
|
+
*/
|
|
9
|
+
export default class ContextPanelService extends Service {
|
|
10
|
+
/**
|
|
11
|
+
* Registry to map models to their corresponding components and arguments.
|
|
12
|
+
*/
|
|
13
|
+
registry = {
|
|
14
|
+
driver: {
|
|
15
|
+
viewing: {
|
|
16
|
+
component: 'driver-panel',
|
|
17
|
+
componentArguments: [{ isResizable: true }, { width: '550px' }],
|
|
18
|
+
},
|
|
19
|
+
editing: {
|
|
20
|
+
component: 'driver-form-panel',
|
|
21
|
+
componentArguments: [{ isResizable: true }, { width: '550px' }],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
vehicle: {
|
|
25
|
+
viewing: {
|
|
26
|
+
component: 'vehicle-panel',
|
|
27
|
+
componentArguments: [{ isResizable: true }, { width: '600px' }],
|
|
28
|
+
},
|
|
29
|
+
editing: {
|
|
30
|
+
component: 'vehicle-form-panel',
|
|
31
|
+
componentArguments: [{ isResizable: true }, { width: '600px' }],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The current context model.
|
|
38
|
+
*/
|
|
39
|
+
@tracked currentContext;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The current context registry.
|
|
43
|
+
*/
|
|
44
|
+
@tracked currentContextRegistry;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The current context component arguments.
|
|
48
|
+
*/
|
|
49
|
+
@tracked currentContextComponentArguments = {};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Focuses on a given model with a specific intent.
|
|
53
|
+
* @param {Object} model - The model to focus on.
|
|
54
|
+
* @param {string} [intent='viewing'] - The intent for focusing (e.g., 'viewing', 'editing').
|
|
55
|
+
*/
|
|
56
|
+
@action focus(model, intent = 'viewing') {
|
|
57
|
+
const modelName = getModelName(model);
|
|
58
|
+
const registry = this.registry[modelName];
|
|
59
|
+
|
|
60
|
+
if (registry && registry[intent]) {
|
|
61
|
+
this.currentContext = model;
|
|
62
|
+
this.currentContextRegistry = registry[intent];
|
|
63
|
+
this.currentContextComponentArguments = this.createDynamicArgsFromRegistry(registry[intent], model);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Clears the current context.
|
|
69
|
+
*/
|
|
70
|
+
@action clear() {
|
|
71
|
+
this.currentContext = null;
|
|
72
|
+
this.currentContextRegistry = null;
|
|
73
|
+
this.currentContextComponentArguments = {};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@action changeIntent(intent) {
|
|
77
|
+
if (this.currentContext) {
|
|
78
|
+
return this.focus(this.currentContext, intent);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Creates dynamic arguments from the registry.
|
|
84
|
+
* @param {Object} registry - The registry for the current context.
|
|
85
|
+
* @param {Object} model - The model to focus on.
|
|
86
|
+
* @returns {Object} The dynamic arguments.
|
|
87
|
+
*/
|
|
88
|
+
createDynamicArgsFromRegistry(registry, model) {
|
|
89
|
+
// Generate dynamic arguments object
|
|
90
|
+
const dynamicArgs = {};
|
|
91
|
+
const componentArguments = registry.componentArguments || [];
|
|
92
|
+
|
|
93
|
+
componentArguments.forEach((arg, index) => {
|
|
94
|
+
if (typeof arg === 'string') {
|
|
95
|
+
dynamicArgs[arg] = model[arg]; // Map string arguments to model properties
|
|
96
|
+
} else if (typeof arg === 'object' && arg !== null) {
|
|
97
|
+
Object.assign(dynamicArgs, arg);
|
|
98
|
+
} else {
|
|
99
|
+
// Handle other types of arguments as needed
|
|
100
|
+
dynamicArgs[`arg${index}`] = arg;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return dynamicArgs;
|
|
105
|
+
}
|
|
106
|
+
}
|