@fleetbase/fleetops-engine 0.3.8 → 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.
- package/addon/components/contact-form-panel.hbs +4 -1
- package/addon/components/contact-panel.hbs +1 -1
- package/addon/components/driver-form-panel.hbs +5 -12
- package/addon/components/driver-panel.hbs +4 -1
- package/addon/components/fleet-form-panel.hbs +4 -1
- package/addon/components/fleet-listing-panel.hbs +2 -2
- package/addon/components/fleet-panel.hbs +1 -1
- package/addon/components/fuel-report-form-panel.hbs +4 -1
- package/addon/components/fuel-report-panel.hbs +4 -1
- package/addon/components/issue-form-panel.hbs +4 -1
- package/addon/components/issue-panel.hbs +4 -1
- package/addon/components/layout/fleet-ops-sidebar/driver-listing.hbs +5 -0
- package/addon/components/layout/fleet-ops-sidebar/driver-listing.js +122 -0
- package/addon/components/layout/fleet-ops-sidebar/fleet-listing.hbs +2 -2
- package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +69 -49
- package/addon/components/layout/fleet-ops-sidebar.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +4 -3
- package/addon/components/live-map.hbs +90 -9
- package/addon/components/live-map.js +28 -11
- package/addon/components/map-container/toolbar/zones-panel.js +16 -13
- package/addon/components/place-form-panel.hbs +4 -1
- package/addon/components/place-panel.hbs +4 -1
- package/addon/components/settings-window.hbs +1 -1
- package/addon/components/vehicle-form-panel.hbs +4 -1
- package/addon/components/vehicle-panel.hbs +4 -1
- package/addon/components/vendor-form-panel.hbs +4 -1
- package/addon/components/vendor-panel.hbs +4 -1
- package/addon/controllers/management/drivers/index.js +10 -90
- package/addon/controllers/management/vehicles/index.js +11 -21
- package/addon/controllers/operations/orders/index/new.js +5 -5
- package/addon/controllers/operations/orders/index/view.js +9 -13
- package/addon/helpers/format-point.js +5 -2
- package/addon/helpers/point-to-coordinates.js +6 -2
- package/addon/services/context-panel.js +23 -18
- package/addon/services/driver-actions.js +107 -0
- package/addon/services/vehicle-actions.js +42 -0
- package/addon/styles/fleetops-engine.css +12 -2
- package/addon/templates/operations/orders/index/new.hbs +3 -3
- package/addon/utils/fly-to-leaflet-layer.js +7 -0
- package/app/components/layout/fleet-ops-sidebar/driver-listing.js +1 -0
- package/app/services/driver-actions.js +1 -0
- package/app/services/vehicle-actions.js +1 -0
- package/composer.json +2 -2
- package/extension.json +1 -1
- package/package.json +4 -4
- package/server/src/Exceptions/IntegratedVendorException.php +45 -1
- package/server/src/Http/Controllers/Api/v1/DriverController.php +2 -2
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +25 -4
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +3 -10
- package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +1 -1
- package/addon/helpers/extract-coordinates.js +0 -6
- package/addon/utils/extract-coordinates.js +0 -1
- package/app/helpers/extract-coordinates.js +0 -1
- package/app/utils/extract-coordinates.js +0 -1
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<Overlay
|
|
2
2
|
@onLoad={{this.setOverlayContext}}
|
|
3
|
+
@onOpen={{this.onOpen}}
|
|
4
|
+
@onClose={{this.onClose}}
|
|
5
|
+
@onToggle={{this.onToggle}}
|
|
3
6
|
@position="right"
|
|
4
7
|
@noBackdrop={{true}}
|
|
5
8
|
@fullHeight={{true}}
|
|
6
9
|
@isResizeble={{or this.isResizable @isResizable}}
|
|
7
|
-
@width={{or this.width @width "
|
|
10
|
+
@width={{or this.width @width "570px"}}
|
|
8
11
|
>
|
|
9
12
|
<Overlay::Header @hideLeftSection={{true}} @actionsWrapperClass="flex-1 flex-col py-3" class="h-auto-i min-h-[127px]">
|
|
10
13
|
<div class="flex flex-row items-center justify-between w-full mb-4">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<Overlay @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizable={{or this.isResizable @isResizable}} @width={{or this.width @width "
|
|
1
|
+
<Overlay @onLoad={{this.setOverlayContext}} @onOpen={{this.onOpen}} @onClose={{this.onClose}} @onToggle={{this.onToggle}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizable={{or this.isResizable @isResizable}} @width={{or this.width @width "570px"}}>
|
|
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">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<Overlay @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizeble={{or this.isResizable @isResizable}} @width={{or this.width @width "
|
|
1
|
+
<Overlay @onLoad={{this.setOverlayContext}} @onOpen={{this.onOpen}} @onClose={{this.onClose}} @onToggle={{this.onToggle}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizeble={{or this.isResizable @isResizable}} @width={{or this.width @width "570px"}}>
|
|
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">
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
<InputGroup @name="Name" @wrapperClass="col-span-2">
|
|
66
66
|
<Input @value={{this.driver.name}} @type="text" class="w-full form-input" placeholder="Name" />
|
|
67
67
|
</InputGroup>
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
<InputGroup @name="Internal ID">
|
|
70
70
|
<Input @value={{this.driver.internal_id}} @type="text" class="w-full form-input" placeholder="Internal ID" />
|
|
71
71
|
</InputGroup>
|
|
@@ -109,16 +109,9 @@
|
|
|
109
109
|
</PowerSelect>
|
|
110
110
|
</div>
|
|
111
111
|
</InputGroup>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
@onChange={{this.onCoordinatesChanged}}
|
|
116
|
-
@onGeocode={{this.onAutocomplete}}
|
|
117
|
-
@onUpdatedFromMap={{this.onCoordinatesChanged}}
|
|
118
|
-
@onInit={{this.setCoordinatesInput}}
|
|
119
|
-
@renderInPlace={{false}}
|
|
120
|
-
/>
|
|
121
|
-
</InputGroup>
|
|
112
|
+
<InputGroup @name="Coordinates" @wrapperClass="col-span-2">
|
|
113
|
+
<CoordinatesInput @value={{this.driver.location}} @onChange={{this.onCoordinatesChanged}} @onGeocode={{this.onAutocomplete}} @onUpdatedFromMap={{this.onCoordinatesChanged}} @onInit={{this.setCoordinatesInput}} @renderInPlace={{false}} />
|
|
114
|
+
</InputGroup>
|
|
122
115
|
</div>
|
|
123
116
|
</div>
|
|
124
117
|
</Overlay::Body>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<Overlay
|
|
2
2
|
@onLoad={{this.setOverlayContext}}
|
|
3
|
+
@onOpen={{this.onOpen}}
|
|
4
|
+
@onClose={{this.onClose}}
|
|
5
|
+
@onToggle={{this.onToggle}}
|
|
3
6
|
@position="right"
|
|
4
7
|
@noBackdrop={{true}}
|
|
5
8
|
@fullHeight={{true}}
|
|
6
9
|
@isResizeble={{or this.isResizable @isResizable}}
|
|
7
|
-
@width={{or this.width @width "
|
|
10
|
+
@width={{or this.width @width "570px"}}
|
|
8
11
|
>
|
|
9
12
|
<Overlay::Header @hideLeftSection={{true}} @actionsWrapperClass="flex-1 flex-col py-3" class="h-auto-i min-h-[127px]">
|
|
10
13
|
<div class="flex flex-row items-center justify-between w-full mb-4">
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<Overlay
|
|
2
2
|
@onLoad={{this.setOverlayContext}}
|
|
3
|
+
@onOpen={{this.onOpen}}
|
|
4
|
+
@onClose={{this.onClose}}
|
|
5
|
+
@onToggle={{this.onToggle}}
|
|
3
6
|
@position="right"
|
|
4
7
|
@noBackdrop={{true}}
|
|
5
8
|
@fullHeight={{true}}
|
|
6
9
|
@isResizeble={{or this.isResizable @isResizable}}
|
|
7
|
-
@width={{or this.width @width "
|
|
10
|
+
@width={{or this.width @width "570px"}}
|
|
8
11
|
>
|
|
9
12
|
<Overlay::Header
|
|
10
13
|
@title={{if this.fleet.public_id this.fleet.name "New Fleet"}}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<Layout::Sidebar::Panel @open={{or @open true}} @title={{this.fleet.name}} @titleStatusRightText={{concat this.fleet.vehicles_online_count "/" this.fleet.vehicles_count}} @titleStatusRight="info" @hideRightTitleStatusDot={{true}} @titleStatusRightContainerClass="-mr-2" @wrapperClass="next-fleet-summary-fleet fleet-depth-{{@depth}}">
|
|
2
2
|
{{#each this.fleet.subfleets as |subFleet|}}
|
|
3
|
-
<FleetListingPanel @fleet={{subFleet}} @onVehicleClicked={{this.onVehicleClicked}} @depth={{add @depth 1}} />
|
|
3
|
+
<FleetListingPanel @fleet={{subFleet}} @onVehicleClicked={{this.onVehicleClicked}} @depth={{add @depth 1}} @itemDropdownButton={{@itemDropdownButton}} @itemDropdownButtonActions={{@itemDropdownButtonActions}} />
|
|
4
4
|
{{/each}}
|
|
5
5
|
{{#each this.fleet.vehicles as |vehicle|}}
|
|
6
|
-
<Layout::Sidebar::Item @icon="circle" @iconSize="2xs" @iconClass={{if vehicle.online "text-green-500" "text-yellow-200"}} @onClick={{fn this.onVehicleClicked vehicle}} @rightSideComponent={{@itemRightSideComponent}} @rightSideComponentContext={{@itemRightSideComponentContext}} @rightSideStatus={{@itemRightSideStatus}} @rightSideStatusText={{@itemRightSideStatusText}} @hideRightSideStatusDot={{@itemHideRightSideStatusDot}} @rightSideStatusClass={{@itemRightSideStatusClass}} @disableRightSideStatusHumanize={{@itemDisableRightSideStatusHumanize}} @dropdownButton={{@itemDropdownButton}} @dropdownButtonActions={{@itemDropdownButtonActions}} @dropdownButtonIcon={{@itemDropdownButtonIcon}} @dropdownButtonIconPrefix={{@itemDropdownButtonIconPrefix}} @dropdownButtonText={{@itemDropdownButtonText}} @dropdownButtonCalculatePosition={{@itemDropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{@itemDropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{
|
|
6
|
+
<Layout::Sidebar::Item @icon="circle" @iconSize="2xs" @iconClass={{if vehicle.online "text-green-500" "text-yellow-200"}} @onClick={{fn this.onVehicleClicked vehicle}} @rightSideComponent={{@itemRightSideComponent}} @rightSideComponentContext={{@itemRightSideComponentContext}} @rightSideStatus={{@itemRightSideStatus}} @rightSideStatusText={{@itemRightSideStatusText}} @hideRightSideStatusDot={{@itemHideRightSideStatusDot}} @rightSideStatusClass={{@itemRightSideStatusClass}} @disableRightSideStatusHumanize={{@itemDisableRightSideStatusHumanize}} @dropdownButton={{@itemDropdownButton}} @dropdownButtonActions={{@itemDropdownButtonActions}} @dropdownContext={{vehicle}} @dropdownButtonIcon={{@itemDropdownButtonIcon}} @dropdownButtonIconPrefix={{@itemDropdownButtonIconPrefix}} @dropdownButtonText={{@itemDropdownButtonText}} @dropdownButtonCalculatePosition={{@itemDropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{@itemDropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{vehicle.displayName}} @dropdownButtonWrapperClass={{@itemDropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{@itemDropdownButtonTriggerClass}} @registerDropdownButtonAPI={{@itemRegisterDropdownButtonAPI}}>{{vehicle.displayName}}</Layout::Sidebar::Item>
|
|
7
7
|
{{/each}}
|
|
8
8
|
</Layout::Sidebar::Panel>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<Overlay @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizeble={{or this.isResizable @isResizable}} @width={{or this.width @width "
|
|
1
|
+
<Overlay @onLoad={{this.setOverlayContext}} @onOpen={{this.onOpen}} @onClose={{this.onClose}} @onToggle={{this.onToggle}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizeble={{or this.isResizable @isResizable}} @width={{or this.width @width "570px"}}>
|
|
2
2
|
<Overlay::Header @title={{this.fleet.name}} @status={{this.fleet.public_id}} @disableBadgeHumanize={{true}} @hideStatusDot={{true}} @createdAt={{this.fleet.createdAt}}>
|
|
3
3
|
<Button @type="default" @icon="pen" @helpText="Edit fleet" @onClick={{this.onEdit}} @wrapperClass="mr-2" />
|
|
4
4
|
<Button @type="default" @icon="times" @helpText={{if this.fleet.id "Cancel edit fleet" "Cancel new fleet"}} @onClick={{this.onPressCancel}} />
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<Overlay
|
|
2
2
|
@onLoad={{this.setOverlayContext}}
|
|
3
|
+
@onOpen={{this.onOpen}}
|
|
4
|
+
@onClose={{this.onClose}}
|
|
5
|
+
@onToggle={{this.onToggle}}
|
|
3
6
|
@position="right"
|
|
4
7
|
@noBackdrop={{true}}
|
|
5
8
|
@fullHeight={{true}}
|
|
6
9
|
@isResizeble={{or this.isResizable @isResizable}}
|
|
7
|
-
@width={{or this.width @width "
|
|
10
|
+
@width={{or this.width @width "570px"}}
|
|
8
11
|
>
|
|
9
12
|
<Overlay::Header
|
|
10
13
|
@title={{if this.fuelReport.public_id this.fuelReport.name "New Fuel Report"}}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<Overlay
|
|
2
2
|
@onLoad={{this.setOverlayContext}}
|
|
3
|
+
@onOpen={{this.onOpen}}
|
|
4
|
+
@onClose={{this.onClose}}
|
|
5
|
+
@onToggle={{this.onToggle}}
|
|
3
6
|
@position="right"
|
|
4
7
|
@noBackdrop={{true}}
|
|
5
8
|
@fullHeight={{true}}
|
|
6
9
|
@isResizable={{or this.isResizable @isResizable}}
|
|
7
|
-
@width={{or this.width @width "
|
|
10
|
+
@width={{or this.width @width "570px"}}
|
|
8
11
|
>
|
|
9
12
|
<Overlay::Header @title="Fuel Report Details" @status={{this.fuelReport.public_id}} @hideStatusDot={{true}} @createdAt={{this.fuelReport.createdAt}}>
|
|
10
13
|
<Button @type="default" @icon="pen" @helpText="Edit fuel report" @onClick={{this.onEdit}} @wrapperClass="mr-2" />
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<Overlay
|
|
2
2
|
@onLoad={{this.setOverlayContext}}
|
|
3
|
+
@onOpen={{this.onOpen}}
|
|
4
|
+
@onClose={{this.onClose}}
|
|
5
|
+
@onToggle={{this.onToggle}}
|
|
3
6
|
@position="right"
|
|
4
7
|
@noBackdrop={{true}}
|
|
5
8
|
@fullHeight={{true}}
|
|
6
9
|
@isResizable={{or this.isResizable @isResizable}}
|
|
7
|
-
@width={{or this.width @width "
|
|
10
|
+
@width={{or this.width @width "570px"}}
|
|
8
11
|
>
|
|
9
12
|
<Overlay::Header
|
|
10
13
|
@title={{if this.issue.public_id this.issue.name "New Issue"}}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<Overlay
|
|
2
2
|
@onLoad={{this.setOverlayContext}}
|
|
3
|
+
@onOpen={{this.onOpen}}
|
|
4
|
+
@onClose={{this.onClose}}
|
|
5
|
+
@onToggle={{this.onToggle}}
|
|
3
6
|
@position="right"
|
|
4
7
|
@noBackdrop={{true}}
|
|
5
8
|
@fullHeight={{true}}
|
|
6
9
|
@isResizable={{or this.isResizable @isResizable}}
|
|
7
|
-
@width={{or this.width @width "
|
|
10
|
+
@width={{or this.width @width "570px"}}
|
|
8
11
|
>
|
|
9
12
|
<Overlay::Header @title="Issue Details" @status={{this.issue.public_id}} @hideStatusDot={{true}} @createdAt={{this.issue.createdAt}}>
|
|
10
13
|
<Button @type="default" @icon="pen" @helpText="Edit Issue" @onClick={{this.onEdit}} @wrapperClass="mr-2" />
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<Layout::Sidebar::Panel @open={{true}} @title={{@title}} @titleIcon={{@icon}} @hideCaret={{true}} @toggleOnCaretOnly={{true}} @onClickPanelTitle={{this.transitionToRoute}} @wrapperClass="next-driver-listing">
|
|
2
|
+
{{#each this.drivers as |driver|}}
|
|
3
|
+
<Layout::Sidebar::Item @icon="circle" @iconSize="2xs" @iconClass={{if driver.online "text-green-500" "text-yellow-200"}} @onClick={{fn this.onDriverClicked driver}} class="driver-nav-item" @dropdownButton={{true}} @dropdownButtonActions={{this.dropdownButtonActions}} @dropdownContext={{driver}} @dropdownButtonIcon={{@itemDropdownButtonIcon}} @dropdownButtonIconPrefix={{@itemDropdownButtonIconPrefix}} @dropdownButtonText={{@itemDropdownButtonText}} @dropdownButtonCalculatePosition={{@itemDropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{true}} @dropdownButtonMenuLabel={{driver.name}} @dropdownButtonWrapperClass={{@itemDropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{@itemDropdownButtonTriggerClass}} @registerDropdownButtonAPI={{@itemRegisterDropdownButtonAPI}} @rightSideComponent={{@itemRightSideComponent}} @rightSideComponentContext={{@itemRightSideComponentContext}} @rightSideStatus={{@itemRightSideStatus}} @rightSideStatusText={{@itemRightSideStatusText}} @hideRightSideStatusDot={{@itemHideRightSideStatusDot}} @rightSideStatusClass={{@itemRightSideStatusClass}} @disableRightSideStatusHumanize={{@itemDisableRightSideStatusHumanize}}>{{driver.name}}</Layout::Sidebar::Item>
|
|
4
|
+
{{/each}}
|
|
5
|
+
</Layout::Sidebar::Panel>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { later } from '@ember/runloop';
|
|
6
|
+
import { task } from 'ember-concurrency-decorators';
|
|
7
|
+
|
|
8
|
+
export default class LayoutFleetOpsSidebarDriverListingComponent extends Component {
|
|
9
|
+
@service store;
|
|
10
|
+
@service universe;
|
|
11
|
+
@service contextPanel;
|
|
12
|
+
@service driverActions;
|
|
13
|
+
@service hostRouter;
|
|
14
|
+
@tracked drivers = [];
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.fetchDrivers.perform();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
dropdownButtonActions = [
|
|
22
|
+
{
|
|
23
|
+
label: 'View driver details...',
|
|
24
|
+
onClick: (driver) => {
|
|
25
|
+
this.contextPanel.focus(driver);
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: 'Edit driver details...',
|
|
30
|
+
onClick: (driver) => {
|
|
31
|
+
this.contextPanel.focus(driver, 'editing');
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
separator: true,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
label: 'Assign order to driver...',
|
|
39
|
+
onClick: (driver) => {
|
|
40
|
+
this.driverActions.assignOrder(driver);
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: 'Assign vehicle to driver...',
|
|
45
|
+
onClick: (driver) => {
|
|
46
|
+
this.driverActions.assignVehicle(driver);
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: 'Locate driver on map...',
|
|
51
|
+
onClick: (driver) => {
|
|
52
|
+
// If currently on the operations dashboard focus driver on the map
|
|
53
|
+
if (typeof this.hostRouter.currentRouteName === 'string' && this.hostRouter.currentRouteName.startsWith('console.fleet-ops.operations.orders')) {
|
|
54
|
+
return this.onDriverClicked(driver);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.driverActions.locate(driver);
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
separator: true,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
label: 'Delete driver...',
|
|
65
|
+
onClick: (driver) => {
|
|
66
|
+
this.driverActions.delete(driver);
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
@action transitionToRoute(toggleApiContext) {
|
|
72
|
+
if (typeof this.args.route === 'string') {
|
|
73
|
+
if (typeof this.hostRouter.currentRouteName === 'string' && this.hostRouter.currentRouteName.startsWith('console.fleet-ops.management.fleets.index')) {
|
|
74
|
+
if (typeof toggleApiContext.toggle === 'function') {
|
|
75
|
+
toggleApiContext.toggle();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.hostRouter.transitionTo(this.args.route);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@action onDriverClicked(driver) {
|
|
84
|
+
// Transition to dashboard/map display
|
|
85
|
+
return this.hostRouter.transitionTo('console.fleet-ops.operations.orders.index', { queryParams: { layout: 'map' } }).then(() => {
|
|
86
|
+
// Focus vehicle on live map
|
|
87
|
+
this.focusDriverOnMap(driver);
|
|
88
|
+
|
|
89
|
+
// Fire callback
|
|
90
|
+
if (typeof this.args.onFocusDriver === 'function') {
|
|
91
|
+
this.args.onFocusDriver(driver);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
focusDriverOnMap(driver) {
|
|
97
|
+
const liveMap = this.universe.get('component:fleet-ops:live-map');
|
|
98
|
+
|
|
99
|
+
if (liveMap) {
|
|
100
|
+
if (liveMap.contextPanel) {
|
|
101
|
+
liveMap.contextPanel.clear();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
liveMap.showAll();
|
|
105
|
+
liveMap.focusLayerByRecord(driver, 16, {
|
|
106
|
+
onAfterFocusWithRecord: function () {
|
|
107
|
+
later(
|
|
108
|
+
this,
|
|
109
|
+
() => {
|
|
110
|
+
liveMap.onDriverClicked(driver);
|
|
111
|
+
},
|
|
112
|
+
1200
|
|
113
|
+
);
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@task *fetchDrivers() {
|
|
120
|
+
this.drivers = yield this.store.query('driver', { limit: 20 });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<Layout::Sidebar::Panel @open={{true}} @titleIcon={{@icon}} @
|
|
1
|
+
<Layout::Sidebar::Panel @open={{true}} @title={{@title}} @titleIcon={{@icon}} @hideCaret={{true}} @toggleOnCaretOnly={{true}} @onClickPanelTitle={{this.transitionToRoute}} @wrapperClass="next-fleet-summary">
|
|
2
2
|
{{#each this.fleets as |fleet|}}
|
|
3
|
-
<FleetListingPanel @fleet={{fleet}} @onVehicleClicked={{this.
|
|
3
|
+
<FleetListingPanel @fleet={{fleet}} @onVehicleClicked={{this.onVehicleClicked}} @depth={{1}} @open={{true}} @itemDropdownButton={{true}} @itemDropdownButtonActions={{this.dropdownButtonActions}} />
|
|
4
4
|
{{/each}}
|
|
5
5
|
</Layout::Sidebar::Panel>
|
|
@@ -2,62 +2,98 @@ import Component from '@glimmer/component';
|
|
|
2
2
|
import { tracked } from '@glimmer/tracking';
|
|
3
3
|
import { inject as service } from '@ember/service';
|
|
4
4
|
import { action } from '@ember/object';
|
|
5
|
-
import { isArray } from '@ember/array';
|
|
6
5
|
import { later } from '@ember/runloop';
|
|
6
|
+
import { task } from 'ember-concurrency-decorators';
|
|
7
7
|
|
|
8
8
|
export default class LayoutFleetOpsSidebarFleetListingComponent extends Component {
|
|
9
9
|
@service store;
|
|
10
|
-
@service notifications;
|
|
11
10
|
@service universe;
|
|
11
|
+
@service contextPanel;
|
|
12
|
+
@service vehicleActions;
|
|
12
13
|
@service hostRouter;
|
|
13
14
|
@tracked fleets = [];
|
|
14
|
-
@tracked isLoading = false;
|
|
15
15
|
|
|
16
16
|
constructor() {
|
|
17
17
|
super(...arguments);
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
18
|
+
this.fetchFleets.perform();
|
|
19
|
+
this.listenForChanges();
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
dropdownButtonActions = [
|
|
23
|
+
{
|
|
24
|
+
label: 'View vehicle details...',
|
|
25
|
+
onClick: (vehicle) => {
|
|
26
|
+
this.contextPanel.focus(vehicle);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
label: 'Edit vehicle...',
|
|
31
|
+
onClick: (vehicle) => {
|
|
32
|
+
this.contextPanel.focus(vehicle, 'editing');
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: 'Locate vehicle...',
|
|
37
|
+
onClick: (vehicle) => {
|
|
38
|
+
// If currently on the operations dashboard focus driver on the map
|
|
39
|
+
if (typeof this.hostRouter.currentRouteName === 'string' && this.hostRouter.currentRouteName.startsWith('console.fleet-ops.operations.orders')) {
|
|
40
|
+
return this.onVehicleClicked(vehicle);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.vehicleActions.locate(vehicle);
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
separator: true,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: 'Delete vehicle...',
|
|
51
|
+
onClick: (vehicle) => {
|
|
52
|
+
this.vehicleActions.delete(vehicle);
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
];
|
|
25
56
|
|
|
26
|
-
@action
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
57
|
+
@action transitionToRoute(toggleApiContext) {
|
|
58
|
+
if (typeof this.args.route === 'string') {
|
|
59
|
+
if (typeof this.hostRouter.currentRouteName === 'string' && this.hostRouter.currentRouteName.startsWith('console.fleet-ops.management.fleets.index')) {
|
|
60
|
+
if (typeof toggleApiContext.toggle === 'function') {
|
|
61
|
+
toggleApiContext.toggle();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
30
64
|
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
await this.hostRouter.transitionTo('console.fleet-ops.operations.orders.index', { queryParams: { layout: 'map' } });
|
|
34
|
-
} catch (error) {
|
|
35
|
-
// silent
|
|
65
|
+
this.hostRouter.transitionTo(this.args.route);
|
|
36
66
|
}
|
|
67
|
+
}
|
|
37
68
|
|
|
38
|
-
|
|
39
|
-
|
|
69
|
+
@action onVehicleClicked(vehicle) {
|
|
70
|
+
// Transition to dashboard/map display
|
|
71
|
+
return this.hostRouter.transitionTo('console.fleet-ops.operations.orders.index', { queryParams: { layout: 'map' } }).then(() => {
|
|
72
|
+
// Focus vehicle on live map
|
|
73
|
+
this.focusVehicleOnMap(vehicle);
|
|
40
74
|
|
|
41
|
-
|
|
42
|
-
onFocusVehicle
|
|
43
|
-
|
|
75
|
+
// Fire callback
|
|
76
|
+
if (typeof this.args.onFocusVehicle === 'function') {
|
|
77
|
+
this.args.onFocusVehicle(vehicle);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
44
80
|
}
|
|
45
81
|
|
|
46
|
-
@action
|
|
47
|
-
const
|
|
82
|
+
@action focusVehicleOnMap(vehicle) {
|
|
83
|
+
const liveMap = this.universe.get('component:fleet-ops:live-map');
|
|
48
84
|
|
|
49
|
-
if (
|
|
50
|
-
if (
|
|
51
|
-
|
|
85
|
+
if (liveMap) {
|
|
86
|
+
if (liveMap.contextPanel) {
|
|
87
|
+
liveMap.contextPanel.clear();
|
|
52
88
|
}
|
|
53
89
|
|
|
54
|
-
|
|
55
|
-
|
|
90
|
+
liveMap.showAll();
|
|
91
|
+
liveMap.focusLayerByRecord(vehicle, 16, {
|
|
56
92
|
onAfterFocusWithRecord: function () {
|
|
57
93
|
later(
|
|
58
94
|
this,
|
|
59
95
|
() => {
|
|
60
|
-
|
|
96
|
+
liveMap.onVehicleClicked(vehicle);
|
|
61
97
|
},
|
|
62
98
|
600 * 2
|
|
63
99
|
);
|
|
@@ -66,7 +102,7 @@ export default class LayoutFleetOpsSidebarFleetListingComponent extends Componen
|
|
|
66
102
|
}
|
|
67
103
|
}
|
|
68
104
|
|
|
69
|
-
|
|
105
|
+
listenForChanges() {
|
|
70
106
|
// when a vehicle is assigned/ or unassigned reload
|
|
71
107
|
this.universe.on('fleet.vehicle.assigned', () => {
|
|
72
108
|
this.loadFleetsWithVehicles();
|
|
@@ -78,23 +114,7 @@ export default class LayoutFleetOpsSidebarFleetListingComponent extends Componen
|
|
|
78
114
|
});
|
|
79
115
|
}
|
|
80
116
|
|
|
81
|
-
|
|
82
|
-
this.
|
|
83
|
-
this.store
|
|
84
|
-
.query('fleet', { with: ['vehicles', 'subfleets'], parents_only: true })
|
|
85
|
-
.then((fleets) => {
|
|
86
|
-
this.fleets = fleets.toArray().map(this.resolveFleetVehicles);
|
|
87
|
-
})
|
|
88
|
-
.catch((error) => {
|
|
89
|
-
this.notifications.serverError(error);
|
|
90
|
-
})
|
|
91
|
-
.finally(() => {
|
|
92
|
-
this.isLoading = false;
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
@action resolveFleetVehicles(fleet) {
|
|
97
|
-
fleet.vehicles = isArray(fleet.vehicles) ? fleet.vehicles.toArray() : [];
|
|
98
|
-
return fleet;
|
|
117
|
+
@task *fetchFleets() {
|
|
118
|
+
this.fleets = yield this.store.query('fleet', { with: ['vehicles', 'subfleets'], parents_only: true });
|
|
99
119
|
}
|
|
100
120
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
|
|
13
13
|
{{#each menuPanel.items as |menuItem|}}
|
|
14
14
|
{{#if menuItem.renderComponentInPlace}}
|
|
15
|
-
{{component menuItem.component menuItem=menuItem title
|
|
15
|
+
{{component menuItem.component menuItem=menuItem title=menuItem.title route=(concat this.routePrefix menuItem.route) icon=menuItem.icon rightSideComponent=menuItem.rightSideComponent rightSideComponentContext=menuItem.rightSideComponentContext rightSideStatus=menuItem.rightSideStatus rightSideStatusText=menuItem.rightSideStatusText hideRightSideStatusDot=menuItem.hideRightSideStatusDot rightSideStatusClass=menuItem.rightSideStatusClass disableRightSideStatusHumanize=menuItem.disableRightSideStatusHumanize dropdownButton=menuItem.dropdownButton dropdownButtonActions=menuItem.dropdownButtonActions dropdownButtonIcon=menuItem.dropdownButtonIcon dropdownButtonIconPrefix=menuItem.dropdownButtonIconPrefix dropdownButtonText=menuItem.dropdownButtonText dropdownButtonCalculatePosition=menuItem.dropdownButtonCalculatePosition dropdownButtonRenderInPlace=menuItem.dropdownButtonRenderInPlace dropdownButtonMenuLabel=menuItem.dropdownButtonMenuLabel dropdownButtonWrapperClass=menuItem.dropdownButtonWrapperClass dropdownButtonTriggerClass=menuItem.dropdownButtonTriggerClass registerDropdownButtonAPI=menuItem.registerDropdownButtonAPI}}
|
|
16
16
|
{{else}}
|
|
17
17
|
<Layout::Sidebar::Item @route={{concat this.routePrefix menuItem.route}} @icon={{menuItem.icon}} @rightSideComponent={{menuItem.rightSideComponent}} @rightSideComponentContext={{menuItem.rightSideComponentContext}} @rightSideStatus={{menuItem.rightSideStatus}} @rightSideStatusText={{menuItem.rightSideStatusText}} @hideRightSideStatusDot={{menuItem.hideRightSideStatusDot}} @rightSideStatusClass={{menuItem.rightSideStatusClass}} @disableRightSideStatusHumanize={{menuItem.disableRightSideStatusHumanize}} @dropdownButton={{menuItem.dropdownButton}} @dropdownButtonActions={{menuItem.dropdownButtonActions}} @dropdownButtonIcon={{menuItem.dropdownButtonIcon}} @dropdownButtonIconPrefix={{menuItem.dropdownButtonIconPrefix}} @dropdownButtonText={{menuItem.dropdownButtonText}} @dropdownButtonCalculatePosition={{menuItem.dropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{menuItem.dropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{menuItem.dropdownButtonMenuLabel}} @dropdownButtonWrapperClass={{menuItem.dropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{menuItem.dropdownButtonTriggerClass}} @registerDropdownButtonAPI={{menuItem.registerDropdownButtonAPI}}>{{menuItem.title}}</Layout::Sidebar::Item>
|
|
18
18
|
{{/if}}
|
|
@@ -3,7 +3,8 @@ import { tracked } from '@glimmer/tracking';
|
|
|
3
3
|
import { inject as service } from '@ember/service';
|
|
4
4
|
import { action } from '@ember/object';
|
|
5
5
|
import { isArray } from '@ember/array';
|
|
6
|
-
|
|
6
|
+
import FleetListingComponent from './fleet-ops-sidebar/fleet-listing';
|
|
7
|
+
import DriverListingComponent from './fleet-ops-sidebar/driver-listing';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* LayoutFleetOpsSidebarComponent
|
|
@@ -41,9 +42,9 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
41
42
|
];
|
|
42
43
|
|
|
43
44
|
const resourcesItems = [
|
|
44
|
-
{ title: 'Drivers', icon: 'id-card', route: 'management.drivers' },
|
|
45
|
+
{ title: 'Drivers', icon: 'id-card', route: 'management.drivers', renderComponentInPlace: true, component: DriverListingComponent },
|
|
45
46
|
{ title: 'Vehicles', icon: 'truck', route: 'management.vehicles' },
|
|
46
|
-
{ title: 'Fleets', icon: 'user-group', route: 'management.fleets' },
|
|
47
|
+
{ title: 'Fleets', icon: 'user-group', route: 'management.fleets', renderComponentInPlace: true, component: FleetListingComponent },
|
|
47
48
|
{ title: 'Vendors', icon: 'warehouse', route: 'management.vendors' },
|
|
48
49
|
{ title: 'Contacts', icon: 'address-book', route: 'management.contacts' },
|
|
49
50
|
{ title: 'Places', icon: 'location-dot', route: 'management.places' },
|