@fleetbase/fleetops-engine 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/components/admin/visibility-controls.js +1 -0
- package/addon/components/contact-form-panel.hbs +28 -6
- package/addon/components/driver-form-panel.hbs +10 -0
- package/addon/components/driver-form-panel.js +51 -0
- package/addon/components/driver-panel/details.hbs +1 -5
- package/addon/components/driver-panel.hbs +21 -3
- package/addon/components/fleet-form-panel.hbs +60 -6
- package/addon/components/fleet-panel/details.hbs +1 -1
- package/addon/components/fuel-report-form-panel.hbs +84 -8
- package/addon/components/fuel-report-form-panel.js +6 -0
- package/addon/components/fuel-report-panel/details.hbs +4 -0
- package/addon/components/issue-form-panel.hbs +99 -11
- package/addon/components/issue-form-panel.js +5 -13
- package/addon/components/layout/fleet-ops-sidebar.js +10 -1
- package/addon/components/live-map-drawer/driver-listing.hbs +6 -0
- package/addon/components/live-map-drawer/driver-listing.js +240 -0
- package/addon/components/live-map-drawer/place-listing.hbs +6 -0
- package/addon/components/live-map-drawer/place-listing.js +204 -0
- package/addon/components/live-map-drawer/vehicle-listing.hbs +6 -0
- package/addon/components/live-map-drawer/vehicle-listing.js +216 -0
- package/addon/components/live-map-drawer.hbs +17 -0
- package/addon/components/live-map-drawer.js +104 -0
- package/addon/components/live-map.hbs +5 -1
- package/addon/components/live-map.js +107 -15
- package/addon/components/map-container/toolbar.hbs +6 -0
- package/addon/components/modals/driver-assign-vehicle.hbs +2 -11
- package/addon/components/modals/driver-assign-vendor.hbs +1 -9
- package/addon/components/modals/fuel-report-details.hbs +4 -0
- package/addon/components/modals/order-event.hbs +1 -1
- package/addon/components/order/schedule-card.hbs +35 -7
- package/addon/components/order/schedule-card.js +163 -6
- package/addon/components/place-form-panel.hbs +14 -7
- package/addon/components/place-form-panel.js +71 -0
- package/addon/components/place-panel/details.hbs +11 -21
- package/addon/components/vehicle-form-panel.hbs +67 -7
- package/addon/components/vehicle-form-panel.js +37 -0
- package/addon/components/vehicle-panel/details.hbs +9 -5
- package/addon/components/vehicle-panel.hbs +18 -4
- package/addon/components/vendor-form-panel/create-form.hbs +72 -11
- package/addon/components/vendor-form-panel/edit-form.hbs +1 -1
- package/addon/components/vendor-form-panel.hbs +70 -30
- package/addon/components/vendor-form-panel.js +4 -40
- package/addon/components/vendor-panel/details.hbs +2 -2
- package/addon/components/vendor-panel.hbs +16 -2
- package/addon/controllers/management/contacts/index.js +42 -3
- package/addon/controllers/management/fleets/index.js +12 -23
- package/addon/controllers/management/fuel-reports/index/new.js +1 -1
- package/addon/controllers/management/fuel-reports/index.js +73 -20
- package/addon/controllers/management/issues/index/new.js +2 -2
- package/addon/controllers/management/issues/index.js +65 -45
- package/addon/controllers/management/places/index.js +59 -18
- package/addon/controllers/management/vehicles/index.js +67 -8
- package/addon/controllers/management/vendors/index.js +63 -8
- package/addon/controllers/operations/orders/index.js +70 -15
- package/addon/controllers/operations/scheduler/index.js +45 -30
- package/addon/routes/management/contacts/index.js +8 -0
- package/addon/routes/management/fleets/index.js +8 -2
- package/addon/routes/management/fuel-reports/index.js +6 -0
- package/addon/routes/management/issues/index.js +9 -1
- package/addon/routes/management/places/index.js +11 -1
- package/addon/routes/management/vehicles/index.js +3 -3
- package/addon/routes/management/vendors/index.js +8 -0
- package/addon/routes/operations/scheduler/index.js +26 -1
- package/addon/styles/fleetops-engine.css +28 -0
- package/addon/templates/operations/orders/index.hbs +2 -2
- package/addon/templates/operations/scheduler/index.hbs +33 -9
- package/addon/utils/create-full-calendar-event-from-order.js +8 -0
- package/addon/utils/get-issue-categories.js +30 -0
- package/addon/utils/get-issue-types.js +3 -0
- package/addon/utils/get-vendor-status-options.js +3 -0
- package/addon/utils/get-vendor-type-options.js +41 -0
- package/app/components/live-map-drawer/driver-listing.js +1 -0
- package/app/components/live-map-drawer/place-listing.js +1 -0
- package/app/components/live-map-drawer/vehicle-listing.js +1 -0
- package/app/components/live-map-drawer.js +1 -0
- package/app/utils/create-full-calendar-event-from-order.js +1 -0
- package/app/utils/get-issue-categories.js +1 -0
- package/app/utils/get-issue-types.js +1 -0
- package/app/utils/get-vendor-categories.js +1 -0
- package/app/utils/get-vendor-status-options.js +1 -0
- package/app/utils/get-vendor-type-options.js +1 -0
- package/app/utils/get-vendor-types.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +4 -4
- package/server/migrations/2023_11_09_041807_add_status_column_to_fuel_reports_table.php +32 -0
- package/server/migrations/2023_11_15_062814_add_comments_column_and_resolved_at_column_to_vehicle_device_events_table.php +33 -0
- package/server/src/Http/Controllers/Api/v1/DriverController.php +2 -2
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +2 -2
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +5 -13
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +1 -3
- package/server/src/Http/Filter/ContactFilter.php +10 -0
- package/server/src/Http/Filter/FleetFilter.php +8 -6
- package/server/src/Http/Filter/FuelReportFilter.php +51 -0
- package/server/src/Http/Filter/IssueFilter.php +61 -5
- package/server/src/Http/Filter/PlaceFilter.php +48 -6
- package/server/src/Http/Filter/VehicleFilter.php +21 -6
- package/server/src/Http/Filter/VendorFilter.php +11 -8
- package/server/src/Http/Middleware/TransformLocationMiddleware.php +1 -1
- package/server/src/Http/Resources/Internal/v1/IntegratedVendorFacilitator.php +17 -18
- package/server/src/Http/Resources/v1/Contact.php +16 -19
- package/server/src/Http/Resources/v1/CurrentJob.php +13 -16
- package/server/src/Http/Resources/v1/Driver.php +59 -57
- package/server/src/Http/Resources/v1/Entity.php +30 -33
- package/server/src/Http/Resources/v1/FuelReport.php +16 -14
- package/server/src/Http/Resources/v1/Order.php +1 -1
- package/server/src/Http/Resources/v1/Payload.php +21 -24
- package/server/src/Http/Resources/v1/Place.php +27 -30
- package/server/src/Http/Resources/v1/Proof.php +13 -16
- package/server/src/Http/Resources/v1/PurchaseRate.php +14 -17
- package/server/src/Http/Resources/v1/ServiceArea.php +13 -16
- package/server/src/Http/Resources/v1/ServiceQuote.php +15 -18
- package/server/src/Http/Resources/v1/ServiceRate.php +33 -36
- package/server/src/Http/Resources/v1/ServiceRateFee.php +14 -17
- package/server/src/Http/Resources/v1/ServiceRateParcelFee.php +9 -12
- package/server/src/Http/Resources/v1/TrackingNumber.php +18 -21
- package/server/src/Http/Resources/v1/TrackingStatus.php +18 -21
- package/server/src/Http/Resources/v1/Vehicle.php +31 -34
- package/server/src/Http/Resources/v1/VehicleDevice.php +23 -25
- package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +38 -32
- package/server/src/Http/Resources/v1/Vendor.php +31 -26
- package/server/src/Http/Resources/v1/Zone.php +14 -17
- package/server/src/Models/Driver.php +7 -1
- package/server/src/Models/FuelReport.php +2 -1
- package/server/src/Models/IntegratedVendor.php +6 -1
- package/server/src/Models/Order.php +24 -2
- package/server/src/Models/Place.php +2 -2
- package/server/src/Models/VehicleDevice.php +1 -1
- package/server/src/Models/VehicleDeviceEvent.php +2 -1
- package/server/src/Models/Vendor.php +1 -1
- package/server/src/Observers/DriverObserver.php +15 -0
- package/server/src/Observers/FleetObserver.php +19 -0
- package/server/src/Providers/FleetOpsServiceProvider.php +1 -0
- package/addon/components/full-calendar/draggable.js +0 -1
- package/addon/components/full-calendar.js +0 -1
- package/app/components/full-calendar/draggable.js +0 -1
- package/app/components/full-calendar.js +0 -1
|
@@ -6,6 +6,8 @@ import { isArray } from '@ember/array';
|
|
|
6
6
|
import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
|
|
7
7
|
import contextComponentCallback from '../utils/context-component-callback';
|
|
8
8
|
import applyContextComponentArguments from '../utils/apply-context-component-arguments';
|
|
9
|
+
import getIssueTypes from '../utils/get-issue-types';
|
|
10
|
+
import getIssueCategories from '../utils/get-issue-categories';
|
|
9
11
|
|
|
10
12
|
export default class IssueFormPanelComponent extends Component {
|
|
11
13
|
/**
|
|
@@ -55,24 +57,14 @@ export default class IssueFormPanelComponent extends Component {
|
|
|
55
57
|
*
|
|
56
58
|
* @var {String}
|
|
57
59
|
*/
|
|
58
|
-
@tracked issueTypes =
|
|
60
|
+
@tracked issueTypes = getIssueTypes();
|
|
59
61
|
|
|
60
62
|
/**
|
|
61
63
|
* The subcategories for issue types.
|
|
62
64
|
*
|
|
63
65
|
* @var {Object}
|
|
64
66
|
*/
|
|
65
|
-
@tracked issueCategoriesByType = {
|
|
66
|
-
vehicle: ['Mechanical Problems', 'Cosmetic Damages', 'Tire Issues', 'Electronics and Instruments', 'Maintenance Alerts', 'Fuel Efficiency Issues'],
|
|
67
|
-
driver: ['Behavior Concerns', 'Documentation', 'Time Management', 'Communication', 'Training Needs', 'Health and Safety Violations'],
|
|
68
|
-
route: ['Inefficient Routes', 'Safety Concerns', 'Blocked Routes', 'Environmental Considerations', 'Unfavorable Weather Conditions'],
|
|
69
|
-
'payload-cargo': ['Damaged Goods', 'Misplaced Goods', 'Documentation Issues', 'Temperature-Sensitive Goods', 'Incorrect Cargo Loading'],
|
|
70
|
-
'software-technical': ['Bugs', 'UI/UX Concerns', 'Integration Failures', 'Performance', 'Feature Requests', 'Security Vulnerabilities'],
|
|
71
|
-
operational: ['Compliance', 'Resource Allocation', 'Cost Overruns', 'Communication', 'Vendor Management Issues'],
|
|
72
|
-
customer: ['Service Quality', 'Billing Discrepancies', 'Communication Breakdown', 'Feedback and Suggestions', 'Order Errors'],
|
|
73
|
-
security: ['Unauthorized Access', 'Data Concerns', 'Physical Security', 'Data Integrity Issues'],
|
|
74
|
-
'environmental-sustainability': ['Fuel Consumption', 'Carbon Footprint', 'Waste Management', 'Green Initiatives Opportunities'],
|
|
75
|
-
};
|
|
67
|
+
@tracked issueCategoriesByType = getIssueCategories({ fullObject: true });
|
|
76
68
|
|
|
77
69
|
/**
|
|
78
70
|
* Selectable issue categories.
|
|
@@ -101,7 +93,7 @@ export default class IssueFormPanelComponent extends Component {
|
|
|
101
93
|
constructor() {
|
|
102
94
|
super(...arguments);
|
|
103
95
|
this.issue = this.args.issue;
|
|
104
|
-
this.issueCategories = getWithDefault(this.issueCategoriesByType, this.issue
|
|
96
|
+
this.issueCategories = getWithDefault(this.issueCategoriesByType, getWithDefault(this.issue, 'type', 'operational'), []);
|
|
105
97
|
applyContextComponentArguments(this);
|
|
106
98
|
}
|
|
107
99
|
|
|
@@ -34,10 +34,11 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
34
34
|
const operationsItems = [
|
|
35
35
|
{ title: 'Dashboard', icon: 'home', route: 'operations.orders' },
|
|
36
36
|
{ title: 'Service Rates', icon: 'file-invoice-dollar', route: 'operations.service-rates' },
|
|
37
|
+
{ title: 'Scheduler', icon: 'calendar-day', route: 'operations.scheduler' },
|
|
37
38
|
];
|
|
38
39
|
|
|
39
40
|
const resourcesItems = [
|
|
40
|
-
{ title: 'Drivers', icon: '
|
|
41
|
+
{ title: 'Drivers', icon: 'id-card', route: 'management.drivers' },
|
|
41
42
|
{ title: 'Vehicles', icon: 'truck', route: 'management.vehicles' },
|
|
42
43
|
{ title: 'Fleets', icon: 'user-group', route: 'management.fleets' },
|
|
43
44
|
{ title: 'Vendors', icon: 'warehouse', route: 'management.vendors' },
|
|
@@ -99,6 +100,14 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
99
100
|
return true;
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
// Check if the route exists in the settings
|
|
104
|
+
const routeExists = visibilitySettings.some((visibilityControl) => (exactMatch ? visibilityControl.route === routePrefix : visibilityControl.route.startsWith(routePrefix)));
|
|
105
|
+
|
|
106
|
+
// If the route doesn't exist in the settings, return true (visible by default)
|
|
107
|
+
if (!routeExists) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
102
111
|
return visibilitySettings.some((visibilityControl) => {
|
|
103
112
|
const match = exactMatch ? visibilityControl.route === routePrefix : visibilityControl.route.startsWith(routePrefix);
|
|
104
113
|
return match && visibilityControl.visible;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<div class="flex flex-row items-center px-5 py-2 border-b border-gray-200 dark:border-gray-700">
|
|
2
|
+
<div>
|
|
3
|
+
<Input @value={{this.query}} {{on "input" this.performSearch}} @type="text" class="form-input form-input-sm w-60" placeholder="Filter drivers by keyword..." />
|
|
4
|
+
</div>
|
|
5
|
+
</div>
|
|
6
|
+
<Table @rows={{this.drivers}} @columns={{this.columns}} @onSetup={{fn (mut this.table)}} />
|
|
@@ -0,0 +1,240 @@
|
|
|
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 { isBlank } from '@ember/utils';
|
|
6
|
+
import { later } from '@ember/runloop';
|
|
7
|
+
import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Represents a live map drawer driver listing component.
|
|
11
|
+
* This component is responsible for displaying and interacting with a list of drivers on a live map.
|
|
12
|
+
*
|
|
13
|
+
* @extends Component
|
|
14
|
+
*/
|
|
15
|
+
export default class LiveMapDrawerDriverListingComponent extends Component {
|
|
16
|
+
/**
|
|
17
|
+
* Service for managing context panels within the application.
|
|
18
|
+
* @service
|
|
19
|
+
*/
|
|
20
|
+
@service contextPanel;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Service for triggering notifications.
|
|
24
|
+
* @service
|
|
25
|
+
*/
|
|
26
|
+
@service notifications;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Service for triggering notifications.
|
|
30
|
+
* @service
|
|
31
|
+
*/
|
|
32
|
+
@service hostRouter;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Service for CRUD operations.
|
|
36
|
+
* @service
|
|
37
|
+
*/
|
|
38
|
+
@service crud;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The list of drivers to display, tracked for reactivity.
|
|
42
|
+
* @tracked
|
|
43
|
+
*/
|
|
44
|
+
@tracked drivers = [];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The internal list of drivers used for searching, tracked for reactivity.
|
|
48
|
+
* @tracked
|
|
49
|
+
*/
|
|
50
|
+
@tracked _drivers = [];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The current search query, tracked for reactivity.
|
|
54
|
+
* @tracked
|
|
55
|
+
*/
|
|
56
|
+
@tracked query = '';
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The table component reference, tracked for reactivity.
|
|
60
|
+
* @tracked
|
|
61
|
+
*/
|
|
62
|
+
@tracked table = null;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The configuration for table columns including details like label, valuePath, and cellComponent,
|
|
66
|
+
* tracked for reactivity.
|
|
67
|
+
* @tracked
|
|
68
|
+
*/
|
|
69
|
+
@tracked columns = [
|
|
70
|
+
{
|
|
71
|
+
label: 'Driver',
|
|
72
|
+
valuePath: 'name',
|
|
73
|
+
photoPath: 'photo_url',
|
|
74
|
+
width: '100px',
|
|
75
|
+
cellComponent: 'cell/driver-name',
|
|
76
|
+
onClick: this.focus,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
label: 'Location',
|
|
80
|
+
valuePath: 'location',
|
|
81
|
+
width: '80px',
|
|
82
|
+
cellComponent: 'table/cell/point',
|
|
83
|
+
onClick: this.locate,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
label: 'Current Job',
|
|
87
|
+
valuePath: 'current_job_id',
|
|
88
|
+
width: '80px',
|
|
89
|
+
cellComponent: 'table/cell/anchor',
|
|
90
|
+
onClick: this.job,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
label: 'Status',
|
|
94
|
+
valuePath: 'status',
|
|
95
|
+
cellComponent: 'table/cell/status',
|
|
96
|
+
width: '60px',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
label: 'Last Seen',
|
|
100
|
+
valuePath: 'updatedAgo',
|
|
101
|
+
width: '60px',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
label: '',
|
|
105
|
+
cellComponent: 'table/cell/dropdown',
|
|
106
|
+
ddButtonText: false,
|
|
107
|
+
ddButtonIcon: 'ellipsis-h',
|
|
108
|
+
ddButtonIconPrefix: 'fas',
|
|
109
|
+
ddMenuLabel: 'Actions',
|
|
110
|
+
cellClassNames: 'overflow-visible',
|
|
111
|
+
wrapperClass: 'flex items-center justify-end mx-2',
|
|
112
|
+
width: '90px',
|
|
113
|
+
actions: [
|
|
114
|
+
{
|
|
115
|
+
label: 'View driver details...',
|
|
116
|
+
fn: this.focus,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
label: 'Edit driver...',
|
|
120
|
+
fn: (driver) => {
|
|
121
|
+
return this.focus(driver, 'editing');
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
label: 'Locate driver...',
|
|
126
|
+
fn: this.locate,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
label: 'Delete driver...',
|
|
130
|
+
fn: this.delete,
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
sortable: false,
|
|
134
|
+
filterable: false,
|
|
135
|
+
resizable: false,
|
|
136
|
+
searchable: false,
|
|
137
|
+
},
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Initializes the component with drivers passed in from `this.args` and sets up the live map reference.
|
|
142
|
+
*/
|
|
143
|
+
constructor() {
|
|
144
|
+
super(...arguments);
|
|
145
|
+
this.drivers = getWithDefault(this.args, 'drivers', []);
|
|
146
|
+
this._drivers = [...this.drivers];
|
|
147
|
+
this.liveMap = this.args.liveMap;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Filters the drivers list based on a query.
|
|
152
|
+
*
|
|
153
|
+
* @param {string} query - The query string to filter the drivers list.
|
|
154
|
+
*/
|
|
155
|
+
search(query) {
|
|
156
|
+
if (typeof query !== 'string' && !isBlank(query)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.drivers = [
|
|
161
|
+
...this._drivers.filter((driver) => {
|
|
162
|
+
return typeof driver.name === 'string' && driver.name.toLowerCase().includes(query.toLowerCase());
|
|
163
|
+
}),
|
|
164
|
+
];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Action to perform a search based on the input event's value.
|
|
169
|
+
*
|
|
170
|
+
* @param {Event} event - The input event containing the search value.
|
|
171
|
+
*/
|
|
172
|
+
@action performSearch({ target: { value } }) {
|
|
173
|
+
this.search(value);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Action to focus on a driver in the live map and context panel.
|
|
178
|
+
*
|
|
179
|
+
* @param {object} driver - The driver object to focus on.
|
|
180
|
+
* @param {string} intent - The intent for focusing, default is 'viewing'.
|
|
181
|
+
*/
|
|
182
|
+
@action focus(driver, intent = 'viewing') {
|
|
183
|
+
if (this.liveMap) {
|
|
184
|
+
this.liveMap.focusLayerByRecord(driver, 16, {
|
|
185
|
+
onAfterFocusWithRecord: () => {
|
|
186
|
+
later(
|
|
187
|
+
this,
|
|
188
|
+
() => {
|
|
189
|
+
this.contextPanel.focus(driver, intent);
|
|
190
|
+
},
|
|
191
|
+
600 * 2
|
|
192
|
+
);
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
} else {
|
|
196
|
+
this.contextPanel.focus(driver, intent);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Action to locate a driver on the live map.
|
|
202
|
+
*
|
|
203
|
+
* @param {object} driver - The driver object to locate.
|
|
204
|
+
*/
|
|
205
|
+
@action locate(driver) {
|
|
206
|
+
if (this.liveMap) {
|
|
207
|
+
this.liveMap.focusLayerByRecord(driver, 18);
|
|
208
|
+
} else {
|
|
209
|
+
this.notifications.warning('Unable to locate driver.');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Transitino to view the drivers current job
|
|
215
|
+
*
|
|
216
|
+
* @param {DriverModel} driver
|
|
217
|
+
* @memberof LiveMapDrawerDriverListingComponent
|
|
218
|
+
*/
|
|
219
|
+
@action job(driver) {
|
|
220
|
+
if (driver.current_job_id) {
|
|
221
|
+
this.hostRouter.transitionTo('console.fleet-ops.operations.orders.index.view', driver.current_job_id);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Action to delete a driver from the list and perform cleanup.
|
|
227
|
+
*
|
|
228
|
+
* @param {object} driver - The driver object to delete.
|
|
229
|
+
* @param {object} options - Additional options for the delete operation.
|
|
230
|
+
*/
|
|
231
|
+
@action delete(driver, options = {}) {
|
|
232
|
+
this.crud.delete(driver, {
|
|
233
|
+
onSuccess: () => {
|
|
234
|
+
this._drivers.removeObject(driver);
|
|
235
|
+
this.drivers.removeObject(driver);
|
|
236
|
+
},
|
|
237
|
+
...options,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<div class="flex flex-row items-center px-5 py-2 border-b border-gray-200 dark:border-gray-700">
|
|
2
|
+
<div>
|
|
3
|
+
<Input @value={{this.query}} {{on "input" this.performSearch}} @type="text" class="form-input form-input-sm w-60" placeholder="Filter places by keyword..." />
|
|
4
|
+
</div>
|
|
5
|
+
</div>
|
|
6
|
+
<Table @rows={{this.places}} @columns={{this.columns}} @onSetup={{fn (mut this.table)}} />
|
|
@@ -0,0 +1,204 @@
|
|
|
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 { isBlank } from '@ember/utils';
|
|
6
|
+
import { later } from '@ember/runloop';
|
|
7
|
+
import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Represents a live map drawer place listing component.
|
|
11
|
+
* This component is responsible for displaying and interacting with a list of places on a live map.
|
|
12
|
+
*
|
|
13
|
+
* @extends Component
|
|
14
|
+
*/
|
|
15
|
+
export default class LiveMapDrawerPlaceListingComponent extends Component {
|
|
16
|
+
/**
|
|
17
|
+
* Service for managing context panels within the application.
|
|
18
|
+
* @service
|
|
19
|
+
*/
|
|
20
|
+
@service contextPanel;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Service for triggering notifications.
|
|
24
|
+
* @service
|
|
25
|
+
*/
|
|
26
|
+
@service notifications;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Service for CRUD operations.
|
|
30
|
+
* @service
|
|
31
|
+
*/
|
|
32
|
+
@service crud;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The list of places to display, tracked for reactivity.
|
|
36
|
+
* @tracked
|
|
37
|
+
*/
|
|
38
|
+
@tracked places = [];
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The internal list of places used for searching, tracked for reactivity.
|
|
42
|
+
* @tracked
|
|
43
|
+
*/
|
|
44
|
+
@tracked _places = [];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The current search query, tracked for reactivity.
|
|
48
|
+
* @tracked
|
|
49
|
+
*/
|
|
50
|
+
@tracked query = '';
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The table component reference, tracked for reactivity.
|
|
54
|
+
* @tracked
|
|
55
|
+
*/
|
|
56
|
+
@tracked table = null;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The configuration for table columns including details like label, valuePath, and cellComponent,
|
|
60
|
+
* tracked for reactivity.
|
|
61
|
+
* @tracked
|
|
62
|
+
*/
|
|
63
|
+
@tracked columns = [
|
|
64
|
+
{
|
|
65
|
+
label: 'Place',
|
|
66
|
+
valuePath: 'address',
|
|
67
|
+
width: '200px',
|
|
68
|
+
cellComponent: 'table/cell/anchor',
|
|
69
|
+
onClick: this.focus,
|
|
70
|
+
showOnlineIndicator: true,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
label: 'Location',
|
|
74
|
+
valuePath: 'location',
|
|
75
|
+
width: '80px',
|
|
76
|
+
cellComponent: 'table/cell/point',
|
|
77
|
+
onClick: this.locate,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
label: '',
|
|
81
|
+
cellComponent: 'table/cell/dropdown',
|
|
82
|
+
ddButtonText: false,
|
|
83
|
+
ddButtonIcon: 'ellipsis-h',
|
|
84
|
+
ddButtonIconPrefix: 'fas',
|
|
85
|
+
ddMenuLabel: 'Actions',
|
|
86
|
+
cellClassNames: 'overflow-visible',
|
|
87
|
+
wrapperClass: 'flex items-center justify-end mx-2',
|
|
88
|
+
width: '90px',
|
|
89
|
+
actions: [
|
|
90
|
+
{
|
|
91
|
+
label: 'View place details...',
|
|
92
|
+
fn: this.focus,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
label: 'Edit place...',
|
|
96
|
+
fn: (place) => {
|
|
97
|
+
return this.focus(place, 'editing');
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
label: 'Locate place...',
|
|
102
|
+
fn: this.locate,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
label: 'Delete place...',
|
|
106
|
+
fn: this.delete,
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
sortable: false,
|
|
110
|
+
filterable: false,
|
|
111
|
+
resizable: false,
|
|
112
|
+
searchable: false,
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Initializes the component with places passed in from `this.args` and sets up the live map reference.
|
|
118
|
+
*/
|
|
119
|
+
constructor() {
|
|
120
|
+
super(...arguments);
|
|
121
|
+
this.places = getWithDefault(this.args, 'places', []);
|
|
122
|
+
this._places = [...this.places];
|
|
123
|
+
this.liveMap = this.args.liveMap;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Filters the places list based on a query.
|
|
128
|
+
*
|
|
129
|
+
* @param {string} query - The query string to filter the places list.
|
|
130
|
+
*/
|
|
131
|
+
search(query) {
|
|
132
|
+
if (typeof query !== 'string' && !isBlank(query)) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
this.places = [
|
|
137
|
+
...this._places.filter((place) => {
|
|
138
|
+
return typeof place.address === 'string' && place.address.toLowerCase().includes(query.toLowerCase());
|
|
139
|
+
}),
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Action to perform a search based on the input event's value.
|
|
145
|
+
*
|
|
146
|
+
* @param {Event} event - The input event containing the search value.
|
|
147
|
+
*/
|
|
148
|
+
@action performSearch({ target: { value } }) {
|
|
149
|
+
this.search(value);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Action to focus on a place in the live map and context panel.
|
|
154
|
+
*
|
|
155
|
+
* @param {object} place - The place object to focus on.
|
|
156
|
+
* @param {string} intent - The intent for focusing, default is 'viewing'.
|
|
157
|
+
*/
|
|
158
|
+
@action focus(place, intent = 'viewing') {
|
|
159
|
+
if (this.liveMap) {
|
|
160
|
+
this.liveMap.focusLayerByRecord(place, 17, {
|
|
161
|
+
onAfterFocusWithRecord: () => {
|
|
162
|
+
later(
|
|
163
|
+
this,
|
|
164
|
+
() => {
|
|
165
|
+
this.contextPanel.focus(place, intent);
|
|
166
|
+
},
|
|
167
|
+
600 * 2
|
|
168
|
+
);
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
} else {
|
|
172
|
+
this.contextPanel.focus(place, intent);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Action to locate a place on the live map.
|
|
178
|
+
*
|
|
179
|
+
* @param {object} place - The place object to locate.
|
|
180
|
+
*/
|
|
181
|
+
@action locate(place) {
|
|
182
|
+
if (this.liveMap) {
|
|
183
|
+
this.liveMap.focusLayerByRecord(place, 18);
|
|
184
|
+
} else {
|
|
185
|
+
this.notifications.warning('Unable to locate place.');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Action to delete a place from the list and perform cleanup.
|
|
191
|
+
*
|
|
192
|
+
* @param {object} place - The place object to delete.
|
|
193
|
+
* @param {object} options - Additional options for the delete operation.
|
|
194
|
+
*/
|
|
195
|
+
@action delete(place, options = {}) {
|
|
196
|
+
this.crud.delete(place, {
|
|
197
|
+
onSuccess: () => {
|
|
198
|
+
this._places.removeObject(place);
|
|
199
|
+
this.places.removeObject(place);
|
|
200
|
+
},
|
|
201
|
+
...options,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<div class="flex flex-row items-center px-5 py-2 border-b border-gray-200 dark:border-gray-700">
|
|
2
|
+
<div>
|
|
3
|
+
<Input @value={{this.query}} {{on "input" this.performSearch}} @type="text" class="form-input form-input-sm w-60" placeholder="Filter vehicles by keyword..." />
|
|
4
|
+
</div>
|
|
5
|
+
</div>
|
|
6
|
+
<Table @rows={{this.vehicles}} @columns={{this.columns}} @onSetup={{fn (mut this.table)}} />
|