@fleetbase/fleetops-engine 0.6.20 → 0.6.21

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 (120) hide show
  1. package/addon/components/custom-entity/form.hbs +14 -14
  2. package/addon/components/device/details.hbs +92 -43
  3. package/addon/components/device/form.hbs +108 -60
  4. package/addon/components/device/form.js +36 -8
  5. package/addon/components/device/panel-header.hbs +32 -0
  6. package/addon/components/device/panel-header.js +3 -0
  7. package/addon/components/driver/form.hbs +1 -1
  8. package/addon/components/driver/form.js +49 -47
  9. package/addon/components/entity/form.hbs +7 -5
  10. package/addon/components/layout/fleet-ops-sidebar.js +12 -12
  11. package/addon/components/map/drawer/device-event-listing.hbs +58 -0
  12. package/addon/components/map/drawer/device-event-listing.js +181 -0
  13. package/addon/components/map/drawer/position-listing.hbs +84 -0
  14. package/addon/components/map/drawer/position-listing.js +289 -0
  15. package/addon/components/map/drawer.js +2 -0
  16. package/addon/components/map/leaflet-live-map.hbs +7 -2
  17. package/addon/components/order/details/payload.hbs +6 -4
  18. package/addon/components/order/details/payload.js +2 -0
  19. package/addon/components/order-config-manager/custom-fields.js +1 -1
  20. package/addon/components/positions-replay.hbs +333 -0
  21. package/addon/components/positions-replay.js +372 -0
  22. package/addon/components/sensor/details.hbs +64 -38
  23. package/addon/components/sensor/form.hbs +112 -63
  24. package/addon/components/sensor/form.js +36 -24
  25. package/addon/components/sensor/panel-header.hbs +32 -0
  26. package/addon/components/sensor/panel-header.js +3 -0
  27. package/addon/components/telematic/details.hbs +40 -16
  28. package/addon/components/telematic/form.hbs +63 -64
  29. package/addon/components/telematic/form.js +73 -4
  30. package/addon/components/vehicle/card.hbs +1 -1
  31. package/addon/controllers/analytics/reports/index/edit.js +1 -1
  32. package/addon/controllers/connectivity/devices/index/details.js +22 -1
  33. package/addon/controllers/connectivity/devices/index/edit.js +66 -1
  34. package/addon/controllers/connectivity/devices/index.js +51 -9
  35. package/addon/controllers/connectivity/events/index.js +65 -16
  36. package/addon/controllers/connectivity/sensors/index/details.js +22 -1
  37. package/addon/controllers/connectivity/sensors/index/edit.js +66 -1
  38. package/addon/controllers/connectivity/sensors/index.js +66 -6
  39. package/addon/controllers/connectivity/telematics/index/details.js +22 -1
  40. package/addon/controllers/connectivity/telematics/index/edit.js +66 -1
  41. package/addon/controllers/connectivity/telematics/index.js +20 -11
  42. package/addon/controllers/management/fleets/index/details.js +26 -21
  43. package/addon/controllers/management/fleets/index/edit.js +9 -6
  44. package/addon/controllers/management/vehicles/index/details.js +21 -13
  45. package/addon/controllers/settings/custom-fields.js +6 -0
  46. package/addon/helpers/get-fleet-ops-option-label.js +11 -0
  47. package/addon/routes/connectivity/devices/index/details.js +27 -1
  48. package/addon/routes/connectivity/devices/index/edit.js +27 -1
  49. package/addon/routes/connectivity/sensors/index/details.js +27 -1
  50. package/addon/routes/connectivity/sensors/index/edit.js +27 -1
  51. package/addon/routes/connectivity/telematics/index/details.js +27 -1
  52. package/addon/routes/connectivity/telematics/index/edit.js +27 -1
  53. package/addon/routes/management/vehicles/index/details/positions.js +3 -0
  54. package/addon/routes.js +1 -0
  55. package/addon/services/movement-tracker.js +81 -30
  56. package/addon/styles/fleetops-engine.css +157 -0
  57. package/addon/templates/connectivity/devices/index/details/index.hbs +2 -2
  58. package/addon/templates/connectivity/devices/index/details.hbs +15 -2
  59. package/addon/templates/connectivity/devices/index/edit.hbs +1 -1
  60. package/addon/templates/connectivity/events/index.hbs +1 -1
  61. package/addon/templates/connectivity/sensors/index/details/index.hbs +2 -2
  62. package/addon/templates/connectivity/sensors/index/details.hbs +15 -2
  63. package/addon/templates/connectivity/sensors/index/edit.hbs +1 -1
  64. package/addon/templates/connectivity/telematics/index/details/index.hbs +2 -2
  65. package/addon/templates/connectivity/telematics/index/details.hbs +14 -2
  66. package/addon/templates/connectivity/telematics/index/edit.hbs +1 -1
  67. package/addon/templates/management/vehicles/index/details/positions.hbs +1 -0
  68. package/addon/utils/fleet-ops-options.js +95 -0
  69. package/app/components/device/panel-header.js +1 -0
  70. package/app/components/map/drawer/device-event-listing.js +1 -0
  71. package/app/components/map/drawer/position-listing.js +1 -0
  72. package/app/components/positions-replay.js +1 -0
  73. package/app/components/sensor/panel-header.js +1 -0
  74. package/app/helpers/get-fleet-ops-option-label.js +1 -0
  75. package/app/routes/management/vehicles/index/details/positions.js +1 -0
  76. package/app/templates/management/vehicles/index/details/positions.js +1 -0
  77. package/composer.json +1 -1
  78. package/extension.json +1 -1
  79. package/package.json +4 -4
  80. package/server/config/telematics.php +111 -0
  81. package/server/migrations/2025_10_27_000001_add_telematics_integration_fields.php +70 -0
  82. package/server/migrations/2025_10_27_171322_fix_device_column_names.php +107 -0
  83. package/server/migrations/2025_10_27_203023_add_company_uuid_to_device_events_table.php +28 -0
  84. package/server/src/Console/Commands/ReplayVehicleLocations.php +225 -0
  85. package/server/src/Contracts/TelematicProviderDescriptor.php +72 -0
  86. package/server/src/Contracts/TelematicProviderInterface.php +119 -0
  87. package/server/src/Exceptions/TelematicProviderException.php +14 -0
  88. package/server/src/Exceptions/TelematicRateLimitExceededException.php +12 -0
  89. package/server/src/Http/Controllers/Api/v1/DriverController.php +24 -14
  90. package/server/src/Http/Controllers/Api/v1/VehicleController.php +27 -7
  91. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +22 -0
  92. package/server/src/Http/Controllers/Internal/v1/PositionController.php +240 -0
  93. package/server/src/Http/Controllers/Internal/v1/SensorController.php +11 -0
  94. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +141 -0
  95. package/server/src/Http/Controllers/Internal/v1/TelematicWebhookController.php +170 -0
  96. package/server/src/Http/Filter/DeviceEventFilter.php +68 -0
  97. package/server/src/Http/Filter/PositionFilter.php +35 -0
  98. package/server/src/Http/Resources/v1/Position.php +44 -0
  99. package/server/src/Jobs/ReplayPositions.php +64 -0
  100. package/server/src/Jobs/SendPositionReplay.php +65 -0
  101. package/server/src/Jobs/SyncTelematicDevicesJob.php +106 -0
  102. package/server/src/Jobs/TestTelematicConnectionJob.php +102 -0
  103. package/server/src/Models/Device.php +72 -10
  104. package/server/src/Models/DeviceEvent.php +7 -0
  105. package/server/src/Models/Driver.php +28 -1
  106. package/server/src/Models/Payload.php +0 -1
  107. package/server/src/Models/Place.php +4 -1
  108. package/server/src/Models/Position.php +17 -17
  109. package/server/src/Models/Sensor.php +78 -13
  110. package/server/src/Models/Telematic.php +116 -6
  111. package/server/src/Models/Vehicle.php +8 -11
  112. package/server/src/Providers/FleetOpsServiceProvider.php +2 -0
  113. package/server/src/Support/Telematics/Providers/AbstractProvider.php +151 -0
  114. package/server/src/Support/Telematics/Providers/FlespiProvider.php +182 -0
  115. package/server/src/Support/Telematics/Providers/GeotabProvider.php +181 -0
  116. package/server/src/Support/Telematics/Providers/SamsaraProvider.php +177 -0
  117. package/server/src/Support/Telematics/TelematicProviderRegistry.php +147 -0
  118. package/server/src/Support/Telematics/TelematicService.php +223 -0
  119. package/server/src/Support/Utils.php +1 -1
  120. package/server/src/routes.php +12 -1
@@ -1689,3 +1689,160 @@ main.console-fleet-ops-operations-orders-index-index section.next-view-section >
1689
1689
  padding-left: 0.5rem;
1690
1690
  padding-right: 2rem;
1691
1691
  }
1692
+
1693
+ .positions-replay-component {
1694
+ width: 100%;
1695
+ max-width: 100%;
1696
+ }
1697
+
1698
+ .positions-replay-component .metric-card {
1699
+ padding: 0.75rem;
1700
+ border-radius: 0.5rem;
1701
+ background-color: rgba(0, 0, 0, 2%);
1702
+ transition: all 0.2s ease-in-out;
1703
+ }
1704
+
1705
+ .positions-replay-component .metric-card:hover {
1706
+ background-color: rgba(0, 0, 0, 4%);
1707
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 10%);
1708
+ }
1709
+
1710
+ body[data-theme='dark'] .positions-replay-component .metric-card {
1711
+ background-color: rgba(255, 255, 255, 5%);
1712
+ }
1713
+
1714
+ body[data-theme='dark'] .positions-replay-component .metric-card:hover {
1715
+ background-color: rgba(255, 255, 255, 8%);
1716
+ }
1717
+
1718
+ .positions-replay-component .metric-label {
1719
+ font-size: 0.65rem;
1720
+ text-transform: uppercase;
1721
+ letter-spacing: 0.05em;
1722
+ margin-bottom: 0.25rem;
1723
+ }
1724
+
1725
+ .positions-replay-component .metric-value {
1726
+ font-size: 0.85rem;
1727
+ line-height: 1;
1728
+ }
1729
+
1730
+ .positions-replay-component .positions-replay-map-container {
1731
+ overflow: hidden;
1732
+ height: 100%;
1733
+ width: 100%;
1734
+ }
1735
+
1736
+ .positions-replay-component .replay-controls {
1737
+ display: flex;
1738
+ align-items: center;
1739
+ justify-content: space-between;
1740
+ flex-wrap: wrap;
1741
+ gap: 1rem;
1742
+ }
1743
+
1744
+ .positions-replay-component .speed-control {
1745
+ display: flex;
1746
+ align-items: center;
1747
+ }
1748
+
1749
+ .positions-replay-component .speed-control > select.speed-select {
1750
+ height: 1.7rem;
1751
+ font-size: 0.85rem;
1752
+ line-height: 0.85rem;
1753
+ text-align: center;
1754
+ padding: 0 2rem 0 0.75rem;
1755
+ }
1756
+
1757
+ .positions-replay-component .replay-progress {
1758
+ display: flex;
1759
+ align-items: center;
1760
+ gap: 0.5rem;
1761
+ }
1762
+
1763
+ .positions-replay-component .progress-bar {
1764
+ position: relative;
1765
+ overflow: hidden;
1766
+ border-radius: 9999px;
1767
+ }
1768
+
1769
+ .positions-replay-component .progress-fill {
1770
+ height: 100%;
1771
+ background: linear-gradient(90deg, #3b82f6, #2563eb);
1772
+ transition: width 0.3s ease-in-out;
1773
+ }
1774
+
1775
+ .positions-replay-component .map-wrapper {
1776
+ position: relative;
1777
+ width: 100%;
1778
+ }
1779
+
1780
+ .positions-replay-component .positions-replay-map {
1781
+ width: 100%;
1782
+ height: 100%;
1783
+ }
1784
+
1785
+ .positions-replay-component .positions-replay-timeline {
1786
+ margin-top: 1rem;
1787
+ }
1788
+
1789
+ .positions-replay-component .timeline-container {
1790
+ position: relative;
1791
+ }
1792
+
1793
+ .positions-replay-component .timeline-track {
1794
+ display: flex;
1795
+ padding-bottom: 1rem;
1796
+ min-width: min-content;
1797
+ }
1798
+
1799
+ .positions-replay-component .timeline-item {
1800
+ position: relative;
1801
+ min-width: 80px;
1802
+ padding: 0.5rem;
1803
+ border-radius: 0.375rem;
1804
+ transition: all 0.2s ease-in-out;
1805
+ }
1806
+
1807
+ .positions-replay-component .timeline-item:hover {
1808
+ transform: translateY(-2px);
1809
+ }
1810
+
1811
+ .positions-replay-component .timeline-marker {
1812
+ width: 0.75rem;
1813
+ height: 0.75rem;
1814
+ border-radius: 50%;
1815
+ margin: 0 auto 0.25rem;
1816
+ transition: all 0.2s ease-in-out;
1817
+ }
1818
+
1819
+ .positions-replay-component .timeline-item:hover .timeline-marker {
1820
+ transform: scale(1.3);
1821
+ }
1822
+
1823
+ .positions-replay-component .timeline-content {
1824
+ text-align: center;
1825
+ white-space: nowrap;
1826
+ }
1827
+
1828
+ .positions-replay-component .positions-replay-table table {
1829
+ width: 100%;
1830
+ border-collapse: collapse;
1831
+ }
1832
+
1833
+ .positions-replay-component .positions-replay-table th {
1834
+ position: sticky;
1835
+ top: 0;
1836
+ z-index: 10;
1837
+ white-space: nowrap;
1838
+ text-overflow: ellipsis;
1839
+ font-size: 0.65rem;
1840
+ }
1841
+
1842
+ .positions-replay-component .empty-state {
1843
+ display: flex;
1844
+ flex-direction: column;
1845
+ align-items: center;
1846
+ justify-content: center;
1847
+ min-height: 400px;
1848
+ }
@@ -1,2 +1,2 @@
1
-
2
- {{outlet}}
1
+ <Device::Details @resource={{@model}} />
2
+ <Spacer @height="200px" />
@@ -1,2 +1,15 @@
1
-
2
- {{outlet}}
1
+ <Layout::Resource::Panel
2
+ @resource={{@model}}
3
+ @controller={{this}}
4
+ @headerComponent={{component "device/panel-header" resource=@model}}
5
+ @headerTitle={{or @model.name @model.serial_number}}
6
+ @actionButtons={{this.actionButtons}}
7
+ @onPressCancel={{transition-to "connectivity.devices.index"}}
8
+ @onOverlayReady={{fn (mut this.overlay)}}
9
+ @headerClass="no-bottom-border"
10
+ @bodyClass="no-scroll"
11
+ >
12
+ <TabNavigation @tabs={{this.tabs}} @contentClass="scrollable" @tablistClass="pl-2">
13
+ {{outlet}}
14
+ </TabNavigation>
15
+ </Layout::Resource::Panel>
@@ -1,7 +1,7 @@
1
1
  <Layout::Resource::Panel
2
2
  @resource={{@model}}
3
3
  @controller={{this}}
4
- @headerTitle={{concat "Edit: " @model.name}}
4
+ @headerTitle={{concat "Edit: " (or @model.name @model.serial_number)}}
5
5
  @actionButtons={{this.actionButtons}}
6
6
  @saveTask={{this.save}}
7
7
  @onPressCancel={{this.cancel}}
@@ -1,6 +1,6 @@
1
1
  <Layout::Resource::Tabular
2
2
  @resource="device-event"
3
- @title={{t "resource.device-events"}}
3
+ @title="Connectivity Events"
4
4
  @searchQuery={{this.query}}
5
5
  @onSearch={{perform this.deviceEventActions.controllerSearchTask this}}
6
6
  @data={{@model}}
@@ -1,2 +1,2 @@
1
-
2
- {{outlet}}
1
+ <Sensor::Details @resource={{@model}} />
2
+ <Spacer @height="200px" />
@@ -1,2 +1,15 @@
1
-
2
- {{outlet}}
1
+ <Layout::Resource::Panel
2
+ @resource={{@model}}
3
+ @controller={{this}}
4
+ @headerComponent={{component "sensor/panel-header" resource=@model}}
5
+ @headerTitle={{or @model.name @model.serial_number}}
6
+ @actionButtons={{this.actionButtons}}
7
+ @onPressCancel={{transition-to "connectivity.sensors.index"}}
8
+ @onOverlayReady={{fn (mut this.overlay)}}
9
+ @headerClass="no-bottom-border"
10
+ @bodyClass="no-scroll"
11
+ >
12
+ <TabNavigation @tabs={{this.tabs}} @contentClass="scrollable" @tablistClass="pl-2">
13
+ {{outlet}}
14
+ </TabNavigation>
15
+ </Layout::Resource::Panel>
@@ -1,7 +1,7 @@
1
1
  <Layout::Resource::Panel
2
2
  @resource={{@model}}
3
3
  @controller={{this}}
4
- @headerTitle={{concat "Edit: " @model.name}}
4
+ @headerTitle={{concat "Edit: " (or @model.name @model.serial_number)}}
5
5
  @actionButtons={{this.actionButtons}}
6
6
  @saveTask={{this.save}}
7
7
  @onPressCancel={{this.cancel}}
@@ -1,2 +1,2 @@
1
-
2
- {{outlet}}
1
+ <Telematic::Details @resource={{@model}} />
2
+ <Spacer @height="200px" />
@@ -1,2 +1,14 @@
1
-
2
- {{outlet}}
1
+ <Layout::Resource::Panel
2
+ @resource={{@model}}
3
+ @controller={{this}}
4
+ @headerTitle={{or @model.name @model.provider}}
5
+ @actionButtons={{this.actionButtons}}
6
+ @onPressCancel={{transition-to "connectivity.telematics.index"}}
7
+ @onOverlayReady={{fn (mut this.overlay)}}
8
+ @headerClass="no-bottom-border"
9
+ @bodyClass="no-scroll"
10
+ >
11
+ <TabNavigation @tabs={{this.tabs}} @contentClass="scrollable" @tablistClass="pl-2">
12
+ {{outlet}}
13
+ </TabNavigation>
14
+ </Layout::Resource::Panel>
@@ -1,7 +1,7 @@
1
1
  <Layout::Resource::Panel
2
2
  @resource={{@model}}
3
3
  @controller={{this}}
4
- @headerTitle={{concat "Edit: " @model.name}}
4
+ @headerTitle={{concat "Edit: " (or @model.name @model.provider)}}
5
5
  @actionButtons={{this.actionButtons}}
6
6
  @saveTask={{this.save}}
7
7
  @onPressCancel={{this.cancel}}
@@ -0,0 +1 @@
1
+ <PositionsReplay @resource={{@model}} />
@@ -403,6 +403,95 @@ export const serviceAreaTypes = [
403
403
  { label: 'Continent', value: 'continent', description: 'A global landmass encompassing multiple countries (e.g., Asia, Europe, Africa).' },
404
404
  ];
405
405
 
406
+ export const telematicStatuses = [
407
+ { value: 'initialized', label: 'Initialized', description: 'Provider entry has been created but not yet configured.' },
408
+ { value: 'configured', label: 'Configured', description: 'Provider credentials and settings are valid but connection not yet tested.' },
409
+ { value: 'connecting', label: 'Connecting', description: 'Attempting to establish a connection with provider API.' },
410
+ { value: 'connected', label: 'Connected', description: 'Successfully authenticated and connected to provider API.' },
411
+ { value: 'synchronizing', label: 'Synchronizing', description: 'Currently syncing data (devices, vehicles, positions, etc.) from provider.' },
412
+ { value: 'active', label: 'Active', description: 'Integration is healthy and data syncs are occurring normally.' },
413
+ { value: 'degraded', label: 'Degraded', description: 'Integration partially working; intermittent errors or missing data.' },
414
+ { value: 'disconnected', label: 'Disconnected', description: 'Connection lost or failed authentication.' },
415
+ { value: 'error', label: 'Error', description: 'Provider integration encountered a fatal issue.' },
416
+ { value: 'disabled', label: 'Disabled', description: 'Manually disabled by the user.' },
417
+ { value: 'archived', label: 'Archived', description: 'Deprecated or replaced integration, kept for record.' },
418
+ ];
419
+
420
+ export const telematicHealthStates = [
421
+ { value: 'healthy', label: 'Healthy', description: 'Integration tested and stable.' },
422
+ { value: 'warning', label: 'Warning', description: 'Minor issues detected (e.g., slow response, nearing quota).' },
423
+ { value: 'critical', label: 'Critical', description: 'Persistent failure or no data received in X hours.' },
424
+ ];
425
+
426
+ export const deviceTypes = [
427
+ { label: 'GPS Tracker', value: 'gps_tracker', description: 'Standalone GPS tracking device installed in vehicle or asset.' },
428
+ { label: 'OBD-II Plug-in Device', value: 'obd2_plugin', description: 'Plugs into vehicle OBD-II port; reads diagnostics, engine data, and transmits telematics.' },
429
+ { label: 'CAN Bus Module', value: 'can_bus_module', description: 'Hard-wired module connected to vehicle CAN bus for detailed vehicle subsystem data.' },
430
+ { label: 'Dash Camera Telematics Unit', value: 'dashcam_unit', description: 'Camera + integrated telematics module capturing video and vehicle data.' },
431
+ {
432
+ label: 'Battery-Powered Asset Tracker',
433
+ value: 'battery_asset_tracker',
434
+ description: 'Self-powered wireless device for tracking non-powered assets (trailers, containers, equipment).',
435
+ },
436
+ { label: 'Smartphone App Device', value: 'smartphone_app_device', description: 'Mobile device running telematics/tracking app using phone sensors and connectivity.' },
437
+ { label: 'Hard-wired Black Box Module', value: 'hardwired_black_box', description: 'Permanently installed telematics control unit wired to vehicle electrical system for fleet use.' },
438
+ { label: 'Mobile Edge / IoT Gateway', value: 'mobile_edge_gateway', description: 'Multi-sensor/IoT gateway installed in vehicle or asset to aggregate sensor data and telematics.' },
439
+ {
440
+ label: 'Trailer/Container Telematic Sensor Node',
441
+ value: 'trailer_container_node',
442
+ description: 'Specialised telematics node for trailers, containers, intermodal assets, tracking location and status.',
443
+ },
444
+ ];
445
+
446
+ export const sensorTypes = [
447
+ { label: 'GPS / GNSS Receiver', value: 'gps_gnss', description: 'Global positioning sensor providing latitude/longitude, speed and time information.' },
448
+ { label: 'Accelerometer', value: 'accelerometer', description: 'Measures linear acceleration; used to detect harsh braking, rapid acceleration, and movement.' },
449
+ { label: 'Gyroscope / IMU', value: 'gyroscope_imu', description: 'Inertial Measurement Unit estimating orientation, yaw/pitch/roll of vehicle or asset.' },
450
+ { label: 'Fuel Level Sensor', value: 'fuel_level', description: 'Measures remaining fuel in tank; used for fuel monitoring and consumption tracking.' },
451
+ { label: 'Tire Pressure Sensor (TPMS)', value: 'tire_pressure', description: 'Measures pressure (and often temperature) in tires for safety and maintenance.' },
452
+ { label: 'Engine Diagnostic / OBD Sensor', value: 'engine_diagnostic', description: 'Reads engine fault codes, RPM, engine hours, and other diagnostics via OBD or CAN.' },
453
+ { label: 'Temperature Sensor', value: 'temperature', description: 'Monitors ambient or equipment temperature; used for refrigerated cargo, battery health etc.' },
454
+ { label: 'Humidity Sensor', value: 'humidity', description: 'Detects moisture/humidity levels in cargo or enclosed spaces for condition monitoring.' },
455
+ { label: 'Door / Hatch Sensor', value: 'door_hatch', description: 'Monitors open/close status of doors, hatches or compartments for security/tracking.' },
456
+ { label: 'Vibration / Shock Sensor', value: 'vibration_shock', description: 'Measures vibration or shock events; suitable for freight, containers or equipment stability monitoring.' },
457
+ { label: 'Battery Voltage Sensor', value: 'battery_voltage', description: 'Monitors battery or electrical system voltage to detect low power or charging issues.' },
458
+ { label: 'Geofence / Entry-Exit Event Sensor', value: 'geofence_event', description: 'Triggers when asset enters/exits defined geographic zone; used for location-based alerts.' },
459
+ { label: 'Idle Time Sensor', value: 'idle_time', description: 'Tracks engine on with vehicle stationary; used to measure idling and optimize fuel/usage.' },
460
+ { label: 'Driver Behavior Sensor', value: 'driver_behavior', description: 'Aggregates data (speed, braking, cornering) to score driving behavior and safety.' },
461
+ ];
462
+
463
+ export const deviceStatuses = [
464
+ { label: 'Inactive', value: 'inactive', description: 'Device record exists but has not yet been activated or assigned.' },
465
+ { label: 'Active', value: 'active', description: 'Device is online and actively communicating with the platform.' },
466
+ { label: 'Online', value: 'online', description: 'Device is currently connected and transmitting live data.' },
467
+ { label: 'Offline', value: 'offline', description: 'Device is powered off or has not transmitted data within the expected interval.' },
468
+ { label: 'Sleeping', value: 'sleeping', description: 'Device in low-power mode awaiting wake event or scheduled reporting interval.' },
469
+ { label: 'Idle', value: 'idle', description: 'Device is powered and connected but not moving or transmitting new telemetry.' },
470
+ { label: 'Maintenance', value: 'maintenance', description: 'Device is undergoing repair, firmware update, or service maintenance.' },
471
+ { label: 'Degraded', value: 'degraded', description: 'Device is partially functional; intermittent connectivity or incomplete data.' },
472
+ { label: 'Error', value: 'error', description: 'Device reported fault, hardware issue, or repeated communication errors.' },
473
+ { label: 'Disconnected', value: 'disconnected', description: 'Device lost connection to network or telematic gateway.' },
474
+ { label: 'Decommissioned', value: 'decommissioned', description: 'Device permanently retired or removed from active fleet use.' },
475
+ { label: 'Disabled', value: 'disabled', description: 'Device manually disabled by user or admin; data not being accepted.' },
476
+ { label: 'Pending Activation', value: 'pending_activation', description: 'Device provisioned but not yet verified or linked to telematic source.' },
477
+ { label: 'Provisioning', value: 'provisioning', description: 'Device configuration or initialization is in progress.' },
478
+ ];
479
+
480
+ export const sensorStatuses = [
481
+ { label: 'Active', value: 'active', description: 'Sensor is online and transmitting readings as expected.' },
482
+ { label: 'Inactive', value: 'inactive', description: 'Sensor exists but is not currently operational or reporting.' },
483
+ { label: 'Online', value: 'online', description: 'Sensor is connected and sending live data via its parent device.' },
484
+ { label: 'Offline', value: 'offline', description: 'Sensor has stopped sending data or is unreachable.' },
485
+ { label: 'Calibrating', value: 'calibrating', description: 'Sensor undergoing calibration or self-test to ensure measurement accuracy.' },
486
+ { label: 'Faulty', value: 'faulty', description: 'Sensor hardware failure or inconsistent readings detected.' },
487
+ { label: 'Degraded', value: 'degraded', description: 'Sensor partially functional; data irregularities or unstable connection.' },
488
+ { label: 'Maintenance', value: 'maintenance', description: 'Sensor temporarily disabled for maintenance, cleaning, or recalibration.' },
489
+ { label: 'Error', value: 'error', description: 'Critical failure or unrecoverable error reported by sensor or gateway.' },
490
+ { label: 'Disconnected', value: 'disconnected', description: 'Sensor communication link lost with device or telematic gateway.' },
491
+ { label: 'Disabled', value: 'disabled', description: 'Sensor manually disabled; no data being collected.' },
492
+ { label: 'Decommissioned', value: 'decommissioned', description: 'Sensor permanently retired, replaced, or removed from service.' },
493
+ ];
494
+
406
495
  export default function fleetOpsOptions(key) {
407
496
  const allOptions = {
408
497
  driverTypes,
@@ -434,6 +523,12 @@ export default function fleetOpsOptions(key) {
434
523
  dimensionUnits,
435
524
  weightUnits,
436
525
  serviceAreaTypes,
526
+ telematicStatuses,
527
+ telematicHealthStates,
528
+ deviceTypes,
529
+ sensorTypes,
530
+ deviceStatuses,
531
+ sensorStatuses,
437
532
  };
438
533
 
439
534
  return allOptions[key] ?? [];
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/device/panel-header';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/map/drawer/device-event-listing';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/map/drawer/position-listing';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/positions-replay';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/sensor/panel-header';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/helpers/get-fleet-ops-option-label';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/vehicles/index/details/positions';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/vehicles/index/details/positions';
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/fleetops-api",
3
- "version": "0.6.20",
3
+ "version": "0.6.21",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "keywords": [
6
6
  "fleetbase-extension",
package/extension.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Fleet-Ops",
3
- "version": "0.6.20",
3
+ "version": "0.6.21",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "repository": "https://github.com/fleetbase/fleetops",
6
6
  "license": "AGPL-3.0-or-later",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/fleetops-engine",
3
- "version": "0.6.20",
3
+ "version": "0.6.21",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "fleet-ops"
@@ -42,9 +42,9 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@babel/core": "^7.23.2",
45
- "@fleetbase/ember-core": "^0.3.4",
46
- "@fleetbase/ember-ui": "^0.3.6",
47
- "@fleetbase/fleetops-data": "^0.1.20",
45
+ "@fleetbase/ember-core": "^0.3.6",
46
+ "@fleetbase/ember-ui": "^0.3.7",
47
+ "@fleetbase/fleetops-data": "^0.1.21",
48
48
  "@fleetbase/leaflet-routing-machine": "^3.2.17",
49
49
  "@fortawesome/ember-fontawesome": "^2.0.0",
50
50
  "@fortawesome/fontawesome-svg-core": "6.4.0",
@@ -0,0 +1,111 @@
1
+ <?php
2
+
3
+ return [
4
+ 'providers' => [
5
+ [
6
+ 'key' => 'flespi',
7
+ 'label' => 'Flespi',
8
+ 'type' => 'native',
9
+ 'driver_class' => \Fleetbase\FleetOps\Support\Telematics\Providers\FlespiProvider::class,
10
+ 'icon' => 'https://flespi.com/favicon.ico',
11
+ 'description' => 'Flespi is a robust telematics platform offering device management, data processing, and API integration.',
12
+ 'docs_url' => 'https://flespi.com/docs',
13
+ 'required_fields' => [
14
+ [
15
+ 'name' => 'token',
16
+ 'label' => 'Flespi Token',
17
+ 'type' => 'password',
18
+ 'placeholder' => 'Enter your Flespi API token',
19
+ 'required' => true,
20
+ 'validation' => 'required|string|min:20',
21
+ ],
22
+ [
23
+ 'name' => 'webhook_secret',
24
+ 'label' => 'Webhook Secret (Optional)',
25
+ 'type' => 'password',
26
+ 'placeholder' => 'Enter webhook secret for signature validation',
27
+ 'required' => false,
28
+ ],
29
+ ],
30
+ 'supports_webhooks' => true,
31
+ 'supports_discovery' => true,
32
+ 'metadata' => [
33
+ 'rate_limit' => 100,
34
+ 'pagination' => 'offset',
35
+ ],
36
+ ],
37
+
38
+ [
39
+ 'key' => 'geotab',
40
+ 'label' => 'Geotab',
41
+ 'type' => 'native',
42
+ 'driver_class' => \Fleetbase\FleetOps\Support\Telematics\Providers\GeotabProvider::class,
43
+ 'icon' => 'https://www.geotab.com/favicon.ico',
44
+ 'description' => 'Geotab provides fleet management solutions with GPS tracking, driver safety, and compliance features.',
45
+ 'docs_url' => 'https://developers.geotab.com/',
46
+ 'required_fields' => [
47
+ [
48
+ 'name' => 'database',
49
+ 'label' => 'Database Name',
50
+ 'type' => 'text',
51
+ 'placeholder' => 'Enter your Geotab database name',
52
+ 'required' => true,
53
+ ],
54
+ [
55
+ 'name' => 'username',
56
+ 'label' => 'Username',
57
+ 'type' => 'text',
58
+ 'placeholder' => 'Enter your Geotab username',
59
+ 'required' => true,
60
+ ],
61
+ [
62
+ 'name' => 'password',
63
+ 'label' => 'Password',
64
+ 'type' => 'password',
65
+ 'placeholder' => 'Enter your Geotab password',
66
+ 'required' => true,
67
+ ],
68
+ ],
69
+ 'supports_webhooks' => false,
70
+ 'supports_discovery' => true,
71
+ 'metadata' => [
72
+ 'rate_limit' => 50,
73
+ 'auth_type' => 'session',
74
+ ],
75
+ ],
76
+
77
+ [
78
+ 'key' => 'samsara',
79
+ 'label' => 'Samsara',
80
+ 'type' => 'native',
81
+ 'driver_class' => \Fleetbase\FleetOps\Support\Telematics\Providers\SamsaraProvider::class,
82
+ 'icon' => 'https://www.samsara.com/favicon.ico',
83
+ 'description' => 'Samsara offers IoT solutions for fleet operations, including GPS tracking, dashcams, and asset monitoring.',
84
+ 'docs_url' => 'https://developers.samsara.com/',
85
+ 'required_fields' => [
86
+ [
87
+ 'name' => 'api_token',
88
+ 'label' => 'API Token',
89
+ 'type' => 'password',
90
+ 'placeholder' => 'Enter your Samsara API token',
91
+ 'required' => true,
92
+ 'validation' => 'required|string|min:20',
93
+ ],
94
+ [
95
+ 'name' => 'webhook_secret',
96
+ 'label' => 'Webhook Secret (Optional)',
97
+ 'type' => 'password',
98
+ 'placeholder' => 'Enter webhook secret for signature validation',
99
+ 'required' => false,
100
+ ],
101
+ ],
102
+ 'supports_webhooks' => true,
103
+ 'supports_discovery' => true,
104
+ 'metadata' => [
105
+ 'rate_limit' => 60,
106
+ 'pagination' => 'cursor',
107
+ ],
108
+ ],
109
+ ]
110
+ ];
111
+
@@ -0,0 +1,70 @@
1
+ <?php
2
+
3
+ use Illuminate\Database\Migrations\Migration;
4
+ use Illuminate\Database\Schema\Blueprint;
5
+ use Illuminate\Support\Facades\Schema;
6
+
7
+ return new class extends Migration {
8
+ /**
9
+ * Run the migrations.
10
+ *
11
+ * @return void
12
+ */
13
+ public function up()
14
+ {
15
+ // Update telematics table
16
+ Schema::table('telematics', function (Blueprint $table) {
17
+ $table->json('credentials')->after('config');
18
+ $table->string('public_id')->after('uuid')->nullable()->index();
19
+ });
20
+
21
+ // Update devices table
22
+ Schema::table('devices', function (Blueprint $table) {
23
+ $table->string('public_id')->after('uuid')->nullable()->index();
24
+ $table->foreignUuid('company_uuid')->nullable()->after('_key')->constrained('companies', 'uuid')->nullOnDelete();
25
+ $table->foreignUuid('photo_uuid')->nullable()->after('telematic_uuid')->constrained('files', 'uuid')->nullOnDelete();
26
+ });
27
+
28
+ // Update sensors table
29
+ Schema::table('sensors', function (Blueprint $table) {
30
+ $table->string('public_id')->after('uuid')->nullable()->index();
31
+ $table->foreignUuid('photo_uuid')->nullable()->after('company_uuid')->constrained('files', 'uuid')->nullOnDelete();
32
+ });
33
+
34
+ // Update device events table
35
+ Schema::table('device_events', function (Blueprint $table) {
36
+ $table->string('public_id')->after('uuid')->nullable()->index();
37
+ });
38
+ }
39
+
40
+ /**
41
+ * Reverse the migrations.
42
+ *
43
+ * @return void
44
+ */
45
+ public function down()
46
+ {
47
+ // Remove columns from telematics
48
+ Schema::table('telematics', function (Blueprint $table) {
49
+ $table->dropColumn(['credentials', 'public_id']);
50
+ });
51
+
52
+ // Remove columns from devices
53
+ Schema::table('devices', function (Blueprint $table) {
54
+ $table->dropForeign(['company_uuid']);
55
+ $table->dropForeign(['photo_uuid']);
56
+ $table->dropColumn(['public_id', 'photo_uuid', 'company_uuid']);
57
+ });
58
+
59
+ // Remove columns from sensors
60
+ Schema::table('sensors', function (Blueprint $table) {
61
+ $table->dropForeign(['photo_uuid']);
62
+ $table->dropColumn(['public_id', 'photo_uuid']);
63
+ });
64
+
65
+ // Remove columns from device events
66
+ Schema::table('device_events', function (Blueprint $table) {
67
+ $table->dropColumn(['public_id']);
68
+ });
69
+ }
70
+ };