@fleetbase/fleetops-engine 0.2.8 → 0.3.0

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 (88) hide show
  1. package/addon/components/context-panel.hbs +5 -0
  2. package/addon/components/context-panel.js +6 -0
  3. package/addon/components/driver-card-mini.js +34 -13
  4. package/addon/components/driver-form-panel.hbs +23 -23
  5. package/addon/components/driver-form-panel.js +96 -13
  6. package/addon/components/driver-panel.hbs +12 -12
  7. package/addon/components/driver-panel.js +125 -21
  8. package/addon/components/fleet-vehicle-listing.hbs +1 -1
  9. package/addon/components/live-map.hbs +20 -9
  10. package/addon/components/live-map.js +1255 -353
  11. package/addon/components/map-container/toolbar/visibility-control-panel.hbs +66 -0
  12. package/addon/components/map-container/toolbar/visibility-control-panel.js +74 -0
  13. package/addon/components/map-container/toolbar/zones-panel.hbs +10 -10
  14. package/addon/components/map-container/toolbar/zones-panel.js +90 -61
  15. package/addon/components/map-container/toolbar.hbs +12 -7
  16. package/addon/components/modals/vehicle-form.hbs +35 -35
  17. package/addon/components/settings-window.hbs +1 -1
  18. package/addon/components/vehicle-form-panel.hbs +25 -26
  19. package/addon/components/vehicle-form-panel.js +95 -12
  20. package/addon/components/vehicle-panel.hbs +12 -13
  21. package/addon/components/vehicle-panel.js +130 -20
  22. package/addon/controllers/management/drivers/index/details.js +53 -0
  23. package/addon/controllers/management/drivers/index/edit.js +77 -46
  24. package/addon/controllers/management/drivers/index/new.js +39 -79
  25. package/addon/controllers/management/drivers/index.js +17 -221
  26. package/addon/controllers/management/fleets/index/edit.js +1 -1
  27. package/addon/controllers/management/fleets/index/new.js +1 -1
  28. package/addon/controllers/management/fuel-reports/index.js +2 -2
  29. package/addon/controllers/management/vehicles/index/details.js +49 -0
  30. package/addon/controllers/management/vehicles/index/edit.js +104 -1
  31. package/addon/controllers/management/vehicles/index/new.js +71 -0
  32. package/addon/controllers/operations/orders/index/new.js +4 -6
  33. package/addon/controllers/operations/orders/index/view.js +22 -14
  34. package/addon/controllers/operations/orders/index.js +124 -50
  35. package/addon/controllers/operations/service-rates/index/edit.js +1 -1
  36. package/addon/controllers/operations/service-rates/index/new.js +1 -1
  37. package/addon/engine.js +6 -0
  38. package/addon/helpers/is-visibility-control-visible.js +18 -0
  39. package/addon/routes/application.js +1 -1
  40. package/addon/routes/home.js +1 -1
  41. package/addon/routes/management/drivers/index/details.js +5 -0
  42. package/addon/routes/operations/orders/index/view.js +4 -2
  43. package/addon/routes/operations/orders/index.js +5 -1
  44. package/addon/routes/operations/service-rates/index.js +1 -1
  45. package/addon/routes/operations/zones/index.js +1 -1
  46. package/addon/services/context-panel.js +173 -0
  47. package/addon/services/leaflet-contextmenu-manager.js +311 -0
  48. package/addon/services/leaflet-map-manager.js +61 -0
  49. package/addon/services/service-areas.js +242 -32
  50. package/addon/templates/application.hbs +2 -1
  51. package/addon/templates/management/drivers/index/details.hbs +1 -1
  52. package/addon/templates/management/drivers/index/edit.hbs +1 -1
  53. package/addon/templates/management/drivers/index/new.hbs +1 -1
  54. package/addon/templates/management/vehicles/index/details.hbs +1 -1
  55. package/addon/templates/management/vehicles/index/edit.hbs +1 -1
  56. package/addon/templates/management/vehicles/index/new.hbs +1 -1
  57. package/addon/templates/operations/orders/index/view.hbs +2 -2
  58. package/addon/templates/operations/orders/index.hbs +1 -1
  59. package/addon/utils/apply-context-component-arguments.js +31 -0
  60. package/addon/utils/context-component-callback.js +16 -0
  61. package/addon/utils/find-leaflet-layer.js +13 -0
  62. package/addon/utils/fly-to-leaflet-layer.js +25 -0
  63. package/addon/utils/get-leaflet-layer-by-id.js +12 -0
  64. package/addon/utils/layer-can-bind-contextmenu.js +3 -0
  65. package/app/components/context-panel.js +1 -0
  66. package/app/components/map-container/toolbar/visibility-control-panel.js +1 -0
  67. package/app/helpers/is-visibility-control-visible.js +1 -0
  68. package/app/services/context-panel.js +1 -0
  69. package/app/services/leaflet-contextmenu-manager.js +1 -0
  70. package/app/services/leaflet-map-manager.js +1 -0
  71. package/app/utils/apply-context-component-arguments.js +1 -0
  72. package/app/utils/context-component-callback.js +1 -0
  73. package/app/utils/find-leaflet-layer.js +1 -0
  74. package/app/utils/fly-to-leaflet-layer.js +1 -0
  75. package/app/utils/get-leaflet-layer-by-id.js +1 -0
  76. package/app/utils/layer-can-bind-contextmenu.js +1 -0
  77. package/composer.json +11 -1
  78. package/extension.json +1 -1
  79. package/package.json +3 -3
  80. package/server/migrations/2023_09_14_074512_update_vehicles_table.php +89 -88
  81. package/server/migrations/2023_10_25_093014_create_vehicle_device_events_table.php +56 -0
  82. package/server/src/Http/Controllers/Internal/v1/LiveController.php +7 -4
  83. package/server/src/Http/Filter/VehicleFilter.php +7 -0
  84. package/server/src/Http/Resources/v1/Vehicle.php +52 -39
  85. package/server/src/Models/VehicleDevice.php +17 -3
  86. package/server/src/Models/VehicleDeviceEvent.php +90 -0
  87. package/addon/services/map-manager.js +0 -3
  88. package/app/services/map-manager.js +0 -1
@@ -0,0 +1,311 @@
1
+ import Service from '@ember/service';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { camelize } from '@ember/string';
4
+ import { later } from '@ember/runloop';
5
+ import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
6
+
7
+ /**
8
+ * Service for managing context menus in Leaflet maps.
9
+ *
10
+ * This service provides functions to toggle context menu items, create context menus for specific
11
+ * layers, and manage the context menu registry. It also includes utility functions for internal use.
12
+ *
13
+ * @class
14
+ */
15
+ export default class LeafletContextmenuManagerService extends Service {
16
+ /**
17
+ * Registry for context menus associated with specific layers.
18
+ *
19
+ * @type {Object}
20
+ */
21
+ @tracked contextMenuRegistry = {};
22
+
23
+ /**
24
+ * Creates a context menu for a specific layer with the given items.
25
+ *
26
+ * @param {string} registryName - The name of the context menu registry.
27
+ * @param {Object} layer - The Leaflet layer associated with the context menu.
28
+ * @param {Array} items - An array of context menu items to add.
29
+ * @returns {Object} The created context menu registry.
30
+ */
31
+ createContextMenu(registryName, layer, contextmenuItems = [], additionalContext = {}) {
32
+ // create internal registry name
33
+ const internalRegistryName = this.createInternalRegistryName(registryName);
34
+
35
+ // get layer contextmenu api
36
+ const contextmenuApi = layer.contextmenu;
37
+
38
+ // bind contextmenu first
39
+ if (typeof layer.bindContextMenu === 'function') {
40
+ layer.bindContextMenu({
41
+ contextmenu: true,
42
+ contextmenuItems,
43
+ });
44
+ }
45
+
46
+ // setup context menu
47
+ if (contextmenuApi) {
48
+ // remove all items first
49
+ contextmenuApi.removeAllItems();
50
+
51
+ // add items
52
+ for (let i = 0; i < contextmenuItems.length; i++) {
53
+ const item = contextmenuItems.objectAt(i);
54
+ contextmenuApi.addItem(item);
55
+ }
56
+
57
+ // enable contextmenu
58
+ contextmenuApi.enable();
59
+ }
60
+
61
+ // create contextmenu registry
62
+ this.contextMenuRegistry[internalRegistryName] = {
63
+ contextmenuItems,
64
+ layer,
65
+ contextmenuApi,
66
+ ...additionalContext,
67
+ };
68
+
69
+ return this.contextMenuRegistry[internalRegistryName];
70
+ }
71
+
72
+ /**
73
+ * Retrieves a context menu registry by its name.
74
+ *
75
+ * @param {string} registryName - The name of the context menu registry to retrieve.
76
+ * @returns {Object|null} The context menu registry or null if not found.
77
+ */
78
+ getRegistry(registryName) {
79
+ const internalRegistryName = this.createInternalRegistryName(registryName);
80
+
81
+ if (this.contextMenuRegistry[internalRegistryName]) {
82
+ return this.contextMenuRegistry[internalRegistryName];
83
+ }
84
+
85
+ return null;
86
+ }
87
+
88
+ /**
89
+ * Creates an internal registry name by camelizing the provided registry name and appending "ConextmenuRegistry" to it.
90
+ *
91
+ * @method createInternalRegistryName
92
+ * @public
93
+ * @memberof LeafletContextmenuManagerService
94
+ * @param {String} registryName - The name of the registry to be camelized and formatted.
95
+ * @returns {String} The formatted internal registry name.
96
+ */
97
+ createInternalRegistryName(registryName) {
98
+ return `${camelize(registryName.replace(/[^a-zA-Z0-9]/g, '-'))}ConextmenuRegistry`;
99
+ }
100
+
101
+ /**
102
+ * Toggles a context menu item in the specified registry.
103
+ *
104
+ * @method createInternalRegistryName
105
+ * @public
106
+ * @param {string} registryName - The name of the context menu registry to toggle the item in.
107
+ * @param {string|Function} selector - The selector or callback for the item to toggle.
108
+ * @param {Object} options - Additional options for toggling the item (optional).
109
+ */
110
+ toggleContextMenuItem(registryName, selector, options = {}) {
111
+ const registry = this.getRegistry(registryName);
112
+
113
+ // get the context menu api
114
+ const { contextmenuApi } = registry;
115
+
116
+ // if just toggling text
117
+ const toggle = getWithDefault(options, 'toggle', true);
118
+ const onText = getWithDefault(options, 'onText');
119
+ const offText = getWithDefault(options, 'offText');
120
+ const callback = getWithDefault(options, 'callback');
121
+
122
+ if (registry) {
123
+ const index = registry.contextmenuItems.findIndex((item) => {
124
+ if (typeof selector === 'string' && typeof item.text === 'string') {
125
+ return item.text.includes(selector);
126
+ }
127
+
128
+ if (typeof selector === 'function') {
129
+ return selector(item);
130
+ }
131
+ });
132
+
133
+ if (index > 0) {
134
+ const item = registry.contextmenuItems.objectAt(index);
135
+
136
+ if (item) {
137
+ item.text = toggle ? onText : offText;
138
+ }
139
+
140
+ if (typeof callback === 'function') {
141
+ callback(toggle, item, registry);
142
+ }
143
+
144
+ // insert back into contextmenu
145
+ if (contextmenuApi) {
146
+ contextmenuApi.removeItem(index);
147
+ contextmenuApi.insertItem(item, index);
148
+ }
149
+ }
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Change the text of a context menu item within a specified registry.
155
+ *
156
+ * @param {string} registryName - The name of the context menu registry.
157
+ * @param {string|function} selector - A string or function to select the menu item to change.
158
+ * @param {string} newText - The new text to set for the menu item.
159
+ * @param {Object} [options={}] - Additional options.
160
+ * @param {function} [options.callback] - A callback function to execute.
161
+ * @memberof LeafletContextmenuManagerService
162
+ */
163
+ changeMenuItemText(registryName, selector, newText, options = {}) {
164
+ const registry = this.getRegistry(registryName);
165
+
166
+ // get the context menu api
167
+ const { contextmenuApi } = registry;
168
+
169
+ // if just toggling text
170
+ const callback = getWithDefault(options, 'callback');
171
+
172
+ if (registry) {
173
+ const index = registry.contextmenuItems.findIndex((item) => {
174
+ if (typeof selector === 'string' && typeof item.text === 'string') {
175
+ return item.text.includes(selector);
176
+ }
177
+
178
+ if (typeof selector === 'function') {
179
+ return selector(item);
180
+ }
181
+ });
182
+
183
+ if (index > 0) {
184
+ const item = registry.contextmenuItems.objectAt(index);
185
+
186
+ if (item) {
187
+ item.text = newText;
188
+ }
189
+
190
+ if (typeof callback === 'function') {
191
+ callback(item, registry);
192
+ }
193
+
194
+ // insert back into contextmenu
195
+ if (contextmenuApi) {
196
+ contextmenuApi.removeItem(index);
197
+ contextmenuApi.insertItem(item, index);
198
+ }
199
+ }
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Removes a specific item from the context menu associated with the given registry name.
205
+ *
206
+ * @method createInternalRegistryName
207
+ * @public
208
+ * @param {string} registryName - The name of the context menu registry to target.
209
+ * @param {string|Function} selector - A string or function used to identify the item to remove.
210
+ * @param {Object} options - Additional options for removing the item.
211
+ * @param {Function} options.callback - A callback function to execute after item removal.
212
+ */
213
+ removeItemFromContextMenu(registryName, selector, options = {}) {
214
+ const registry = this.getRegistry(registryName);
215
+
216
+ // get the context menu api
217
+ const { contextmenuApi } = registry;
218
+
219
+ // if just toggling text
220
+ const callback = getWithDefault(options, 'callback');
221
+
222
+ if (registry) {
223
+ const index = registry.contextmenuItems.findIndex((item) => {
224
+ if (typeof selector === 'string' && typeof item.text === 'string') {
225
+ return item.text.includes(selector);
226
+ }
227
+
228
+ if (typeof selector === 'function') {
229
+ return selector(item);
230
+ }
231
+ });
232
+
233
+ if (index > 0) {
234
+ const item = registry.contextmenuItems.objectAt(index);
235
+
236
+ if (typeof callback === 'function') {
237
+ callback(item, registry);
238
+ }
239
+
240
+ // remove from context menu
241
+ if (contextmenuApi) {
242
+ contextmenuApi.removeItem(index);
243
+ }
244
+ }
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Find a context menu registry by layer.
250
+ *
251
+ * @param {Layer} layer - The layer for which to find the registry.
252
+ * @returns {Object|null} The context menu registry associated with the provided layer, or null if not found.
253
+ */
254
+ findRegistryByLayer(layer) {
255
+ for (const registryName in this.contextMenuRegistry) {
256
+ const registry = this.contextMenuRegistry[registryName];
257
+ if (registry.layer === layer) {
258
+ return registry;
259
+ }
260
+ }
261
+
262
+ // If no matching registry is found, return null or handle the case accordingly.
263
+ return null;
264
+ }
265
+
266
+ /**
267
+ * Rebind the context menu for a layer and update the registry if it exists.
268
+ *
269
+ * @param {Layer} layer - The layer to rebind the context menu for.
270
+ * @param {Array} contextmenuItems - An array of context menu items to bind.
271
+ */
272
+ rebindContextMenu(layer, contextmenuItems = []) {
273
+ // make sure layer is instance of leaflet
274
+ if (!(layer instanceof L.Layer)) {
275
+ return;
276
+ }
277
+
278
+ const registry = this.findRegistryByLayer(layer);
279
+
280
+ if (registry) {
281
+ later(
282
+ this,
283
+ () => {
284
+ try {
285
+ if (typeof layer.unbindContextMenu === 'function') {
286
+ layer.unbindContextMenu().bindContextMenu({
287
+ contextmenu: true,
288
+ contextmenuItems,
289
+ });
290
+ } else {
291
+ // just bind
292
+ layer.bindContextMenu({
293
+ contextmenu: true,
294
+ contextmenuItems,
295
+ });
296
+ }
297
+ } catch (error) {
298
+ // silence
299
+ }
300
+
301
+ // if found registry update layer and contextmenu api
302
+ if (registry) {
303
+ registry.layer = layer;
304
+ registry.contextmenuApi = layer.contextmenu;
305
+ }
306
+ },
307
+ 300
308
+ );
309
+ }
310
+ }
311
+ }
@@ -0,0 +1,61 @@
1
+ import Service from '@ember/service';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import getLeafletLayerById from '../utils/get-leaflet-layer-by-id';
4
+ import findLeafletLayer from '../utils/find-leaflet-layer';
5
+ import flyToLeafletLayer from '../utils/fly-to-leaflet-layer';
6
+
7
+ /**
8
+ * Service for managing Leaflet maps and layers.
9
+ *
10
+ * This service provides functions to work with Leaflet maps, including accessing layers by ID,
11
+ * finding layers based on a custom callback, and flying to specific layers with optional zoom and options.
12
+ *
13
+ * @class
14
+ */
15
+ export default class LeafletMapManagerService extends Service {
16
+ /**
17
+ * An array of editable layers on the map.
18
+ *
19
+ * @memberof LeafletMapManagerService
20
+ * @type {Array}
21
+ */
22
+ @tracked editableLayers = [];
23
+
24
+ /**
25
+ * Get a Leaflet layer by its ID from the given map.
26
+ *
27
+ * @memberof LeafletMapManagerService
28
+ * @param {Object} map - The Leaflet map instance.
29
+ * @param {string} layerId - The ID of the layer to retrieve.
30
+ * @returns {Object|null} The Leaflet layer with the specified ID, or null if not found.
31
+ */
32
+ getLeafletLayerById(map, layerId) {
33
+ return getLeafletLayerById(map, layerId);
34
+ }
35
+
36
+ /**
37
+ * Find a Leaflet layer in the given map using a custom callback.
38
+ *
39
+ * @memberof LeafletMapManagerService
40
+ * @param {Object} map - The Leaflet map instance.
41
+ * @param {Function} findCallback - A custom callback function to find the desired layer.
42
+ * @returns {Object|null} The found Leaflet layer, or null if not found.
43
+ */
44
+ findLeafletLayer(map, findCallback) {
45
+ return findLeafletLayer(map, findCallback);
46
+ }
47
+
48
+ /**
49
+ * Fly to a specific Leaflet layer on the map with optional zoom and options.
50
+ *
51
+ * @memberof LeafletMapManagerService
52
+ * @param {Object} map - The Leaflet map instance.
53
+ * @param {Object} layer - The Leaflet layer to fly to.
54
+ * @param {number} zoom - The zoom level to apply (optional).
55
+ * @param {Object} options - Additional options for the fly animation (optional).
56
+ * @returns {Object} The Leaflet map instance.
57
+ */
58
+ flyToLayer(map, layer, zoom, options = {}) {
59
+ return flyToLeafletLayer(map, layer, zoom, options);
60
+ }
61
+ }