@fleetbase/fleetops-engine 0.6.53 → 0.6.55

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 (212) hide show
  1. package/addon/components/admin/routing-settings.hbs +2 -1
  2. package/addon/components/cell/attached-vehicle.hbs +10 -0
  3. package/addon/components/cell/attached-vehicle.js +58 -0
  4. package/addon/components/cell/device-identity.hbs +24 -0
  5. package/addon/components/cell/device-identity.js +129 -0
  6. package/addon/components/cell/driver-identity.hbs +33 -0
  7. package/addon/components/cell/driver-identity.js +143 -0
  8. package/addon/components/cell/equipment-identity.hbs +5 -0
  9. package/addon/components/cell/equipment-identity.js +48 -0
  10. package/addon/components/cell/part-identity.hbs +5 -0
  11. package/addon/components/cell/part-identity.js +63 -0
  12. package/addon/components/cell/telematic-device.hbs +38 -0
  13. package/addon/components/cell/telematic-device.js +44 -0
  14. package/addon/components/cell/telematic-provider.hbs +33 -16
  15. package/addon/components/cell/telematic-provider.js +50 -8
  16. package/addon/components/cell/vehicle-identity.hbs +33 -0
  17. package/addon/components/cell/vehicle-identity.js +138 -0
  18. package/addon/components/device/details.hbs +106 -135
  19. package/addon/components/device/details.js +174 -1
  20. package/addon/components/device/form.hbs +2 -2
  21. package/addon/components/device/form.js +7 -0
  22. package/addon/components/device/panel-header.hbs +46 -21
  23. package/addon/components/device/panel-header.js +49 -1
  24. package/addon/components/device/panel-tabs/events.hbs +30 -0
  25. package/addon/components/device/panel-tabs/events.js +128 -0
  26. package/addon/components/device/panel-tabs/sensors.hbs +30 -0
  27. package/addon/components/device/panel-tabs/sensors.js +93 -0
  28. package/addon/components/device/panel-tabs/vehicle.hbs +68 -0
  29. package/addon/components/device/panel-tabs/vehicle.js +90 -0
  30. package/addon/components/equipment/form.js +8 -1
  31. package/addon/components/layout/fleet-ops-sidebar/operations-monitor.js +76 -11
  32. package/addon/components/layout/fleet-ops-sidebar.hbs +1 -1
  33. package/addon/components/layout/fleet-ops-sidebar.js +101 -17
  34. package/addon/components/map/drawer/device-event-listing.js +2 -0
  35. package/addon/components/map/drawer/driver-listing.js +2 -0
  36. package/addon/components/map/drawer/place-listing.js +2 -0
  37. package/addon/components/map/drawer/position-listing.hbs +11 -6
  38. package/addon/components/map/drawer/position-listing.js +17 -4
  39. package/addon/components/map/drawer/vehicle-listing.js +2 -0
  40. package/addon/components/order/form/details.hbs +1 -43
  41. package/addon/components/order/form/details.js +18 -53
  42. package/addon/components/order/form/orchestrator-constraints.hbs +40 -0
  43. package/addon/components/order/form/orchestrator-constraints.js +61 -0
  44. package/addon/components/order/form/payload.js +48 -2
  45. package/addon/components/order/form/route.js +15 -0
  46. package/addon/components/order/form/service-rate.hbs +62 -11
  47. package/addon/components/order/form/service-rate.js +124 -2
  48. package/addon/components/order/form.hbs +2 -0
  49. package/addon/components/sensor/panel-header.hbs +47 -15
  50. package/addon/components/sensor/panel-header.js +59 -1
  51. package/addon/components/table/cell/dropdown/action-item.hbs +31 -0
  52. package/addon/components/table/cell/dropdown/action-item.js +62 -0
  53. package/addon/components/table/cell/dropdown.hbs +28 -0
  54. package/addon/components/table/cell/dropdown.js +91 -0
  55. package/addon/components/telematic/details.hbs +7 -1
  56. package/addon/components/telematic/form.js +16 -8
  57. package/addon/components/vendor/panel-header.hbs +82 -0
  58. package/addon/components/vendor/panel-header.js +48 -0
  59. package/addon/components/work-order/details.hbs +5 -1
  60. package/addon/components/work-order/form.hbs +26 -4
  61. package/addon/components/work-order/form.js +5 -1
  62. package/addon/controllers/connectivity/devices/index/details/events.js +244 -1
  63. package/addon/controllers/connectivity/devices/index/details/sensors.js +199 -0
  64. package/addon/controllers/connectivity/devices/index/details/vehicle.js +122 -0
  65. package/addon/controllers/connectivity/devices/index/details.js +12 -0
  66. package/addon/controllers/connectivity/devices/index.js +144 -129
  67. package/addon/controllers/connectivity/events/details.js +3 -0
  68. package/addon/controllers/connectivity/events/index.js +187 -11
  69. package/addon/controllers/connectivity/sensors/index.js +156 -14
  70. package/addon/controllers/connectivity/telematics/details/attachments.js +220 -54
  71. package/addon/controllers/connectivity/telematics/details/devices.js +170 -129
  72. package/addon/controllers/connectivity/telematics/details/events.js +39 -11
  73. package/addon/controllers/connectivity/telematics/details/sensors.js +39 -19
  74. package/addon/controllers/maintenance/equipment/index.js +1 -2
  75. package/addon/controllers/maintenance/parts/index.js +1 -2
  76. package/addon/controllers/maintenance/work-orders/index.js +18 -1
  77. package/addon/controllers/management/drivers/index.js +82 -42
  78. package/addon/controllers/management/fuel-reports/index.js +63 -4
  79. package/addon/controllers/management/issues/index.js +63 -4
  80. package/addon/controllers/management/vehicles/index.js +33 -6
  81. package/addon/routes/connectivity/devices/index/details/events.js +37 -1
  82. package/addon/routes/connectivity/devices/index/details/sensors.js +35 -0
  83. package/addon/routes/connectivity/devices/index/details/vehicle.js +29 -0
  84. package/addon/routes/connectivity/devices/index.js +7 -0
  85. package/addon/routes/connectivity/events/details.js +3 -0
  86. package/addon/routes/connectivity/events/index.js +6 -2
  87. package/addon/routes/connectivity/sensors/index.js +7 -2
  88. package/addon/routes/connectivity/telematics/details/attachments.js +72 -9
  89. package/addon/routes/connectivity/telematics/details/devices.js +6 -0
  90. package/addon/routes/connectivity/telematics/details/sensors.js +1 -0
  91. package/addon/routes/connectivity/telematics/details.js +1 -1
  92. package/addon/routes/connectivity/telematics/edit.js +1 -1
  93. package/addon/routes/maintenance/work-orders/index.js +1 -0
  94. package/addon/routes.js +2 -0
  95. package/addon/services/device-actions.js +30 -0
  96. package/addon/services/device-event-actions.js +1 -1
  97. package/addon/services/equipment-actions.js +1 -0
  98. package/addon/services/order-creation.js +54 -1
  99. package/addon/services/order-validation.js +3 -2
  100. package/addon/services/sensor-actions.js +3 -0
  101. package/addon/services/service-rate-actions.js +40 -1
  102. package/addon/services/vehicle-actions.js +24 -12
  103. package/addon/services/vendor-actions.js +3 -0
  104. package/addon/styles/fleetops-engine.css +28 -4
  105. package/addon/templates/connectivity/devices/index/details/events.hbs +85 -1
  106. package/addon/templates/connectivity/devices/index/details/sensors.hbs +73 -0
  107. package/addon/templates/connectivity/devices/index/details/vehicle.hbs +147 -0
  108. package/addon/templates/connectivity/telematics/details/attachments.hbs +198 -121
  109. package/addon/templates/connectivity/telematics/details/devices.hbs +4 -1
  110. package/addon/templates/connectivity/telematics/details/events.hbs +4 -1
  111. package/addon/templates/connectivity/telematics/details/sensors.hbs +3 -0
  112. package/addon/templates/management/vehicles/index/edit.hbs +1 -1
  113. package/addon/templates/management/vendors/index/details.hbs +2 -2
  114. package/addon/templates/settings/notifications.hbs +2 -1
  115. package/addon/templates/settings/routing.hbs +1 -0
  116. package/addon/utils/device-table-columns.js +288 -0
  117. package/addon/utils/fleet-ops-options.js +38 -0
  118. package/addon/utils/identity-cell-resource.js +20 -0
  119. package/addon/utils/map-drawer-dropdown-position.js +47 -0
  120. package/addon/utils/trackable-option.js +93 -0
  121. package/app/components/cell/attached-vehicle.js +1 -0
  122. package/app/components/cell/device-identity.js +1 -0
  123. package/app/components/cell/driver-identity.js +1 -0
  124. package/app/components/cell/equipment-identity.js +1 -0
  125. package/app/components/cell/part-identity.js +1 -0
  126. package/app/components/cell/telematic-device.js +1 -0
  127. package/app/components/cell/vehicle-identity.js +1 -0
  128. package/app/components/device/panel-tabs/events.hbs +30 -0
  129. package/app/components/device/panel-tabs/events.js +128 -0
  130. package/app/components/device/panel-tabs/sensors.hbs +30 -0
  131. package/app/components/device/panel-tabs/sensors.js +93 -0
  132. package/app/components/device/panel-tabs/vehicle.hbs +68 -0
  133. package/app/components/device/panel-tabs/vehicle.js +90 -0
  134. package/app/components/order/form/orchestrator-constraints.js +1 -0
  135. package/app/components/table/cell/dropdown/action-item.js +1 -0
  136. package/app/components/table/cell/dropdown.js +1 -0
  137. package/app/components/vendor/panel-header.js +1 -0
  138. package/app/controllers/connectivity/devices/index/details/sensors.js +1 -0
  139. package/app/controllers/connectivity/devices/index/details/vehicle.js +1 -0
  140. package/app/controllers/connectivity/events/{index/details.js → details.js} +1 -1
  141. package/app/routes/connectivity/devices/index/details/sensors.js +1 -0
  142. package/app/routes/connectivity/devices/index/details/vehicle.js +1 -0
  143. package/app/routes/connectivity/events/{index/details.js → details.js} +1 -1
  144. package/app/templates/connectivity/devices/index/details/sensors.js +1 -0
  145. package/app/templates/connectivity/devices/index/details/vehicle.js +1 -0
  146. package/app/templates/connectivity/events/{index/details.js → details.js} +1 -1
  147. package/app/utils/map-drawer-dropdown-position.js +1 -0
  148. package/app/utils/trackable-option.js +1 -0
  149. package/composer.json +1 -1
  150. package/extension.json +1 -1
  151. package/package.json +4 -4
  152. package/server/migrations/2025_08_28_054930_create_work_orders_table.php +1 -0
  153. package/server/migrations/2026_06_18_000001_add_category_to_work_orders_table.php +32 -0
  154. package/server/seeders/Testing/MaintenanceSeeder.php +5 -4
  155. package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +1 -0
  156. package/server/src/Console/Commands/SyncTelematics.php +89 -0
  157. package/server/src/Exceptions/TelematicProviderException.php +13 -2
  158. package/server/src/Http/Controllers/Api/v1/OrderController.php +6 -21
  159. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +55 -1
  160. package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +17 -6
  161. package/server/src/Http/Controllers/Internal/v1/FleetController.php +9 -0
  162. package/server/src/Http/Controllers/Internal/v1/LiveController.php +178 -1
  163. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +1 -0
  164. package/server/src/Http/Controllers/Internal/v1/OrderController.php +4 -32
  165. package/server/src/Http/Controllers/Internal/v1/SearchController.php +2 -2
  166. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +4 -4
  167. package/server/src/Http/Controllers/Internal/v1/ServiceRateController.php +82 -13
  168. package/server/src/Http/Filter/DeviceEventFilter.php +65 -0
  169. package/server/src/Http/Filter/DeviceFilter.php +80 -0
  170. package/server/src/Http/Filter/SensorFilter.php +125 -0
  171. package/server/src/Http/Filter/VehicleFilter.php +13 -0
  172. package/server/src/Http/Requests/CreateDriverRequest.php +14 -13
  173. package/server/src/Http/Requests/Internal/CreateDriverRequest.php +1 -0
  174. package/server/src/Http/Resources/v1/Driver.php +11 -2
  175. package/server/src/Http/Resources/v1/Index/Vehicle.php +19 -0
  176. package/server/src/Http/Resources/v1/WorkOrder.php +1 -0
  177. package/server/src/Jobs/FinalizeApiOrderCreation.php +47 -0
  178. package/server/src/Jobs/FinalizeInternalOrderCreation.php +35 -0
  179. package/server/src/Jobs/NotifyBulkAssignedDriver.php +47 -0
  180. package/server/src/Jobs/SyncTelematicDevicesJob.php +180 -123
  181. package/server/src/Models/Device.php +17 -1
  182. package/server/src/Models/DeviceEvent.php +82 -1
  183. package/server/src/Models/Driver.php +16 -0
  184. package/server/src/Models/Equipment.php +55 -0
  185. package/server/src/Models/Sensor.php +15 -2
  186. package/server/src/Models/Telematic.php +1 -1
  187. package/server/src/Models/Vehicle.php +5 -1
  188. package/server/src/Models/WorkOrder.php +5 -2
  189. package/server/src/Observers/DriverObserver.php +3 -3
  190. package/server/src/Observers/FleetObserver.php +23 -0
  191. package/server/src/Observers/VehicleObserver.php +3 -3
  192. package/server/src/Providers/FleetOpsServiceProvider.php +2 -0
  193. package/server/src/Support/LiveCacheService.php +1 -1
  194. package/server/src/Support/Telematics/Providers/AfaqyProvider.php +143 -20
  195. package/server/src/Support/Telematics/Providers/FlespiProvider.php +89 -15
  196. package/server/src/Support/Telematics/Providers/GeotabProvider.php +123 -35
  197. package/server/src/Support/Telematics/Providers/SafeeProvider.php +70 -5
  198. package/server/src/Support/Telematics/Providers/SamsaraProvider.php +122 -14
  199. package/server/src/Support/Telematics/TelematicService.php +330 -30
  200. package/server/src/routes.php +1 -1
  201. package/server/tests/DeviceFilterTest.php +45 -0
  202. package/server/tests/DriverVehicleStatusDefaultTest.php +19 -2
  203. package/server/tests/EquipmentAssignmentMorphTypeTest.php +35 -0
  204. package/server/tests/OperationsMonitorEndpointTest.php +38 -0
  205. package/server/tests/OrderQueuedClosureRegressionTest.php +36 -0
  206. package/server/tests/ServiceRateRouteValidationTest.php +101 -0
  207. package/server/tests/TelematicsHardeningTest.php +598 -6
  208. package/server/tests/VehicleDriverAssignmentTest.php +27 -0
  209. package/translations/en-us.yaml +1 -0
  210. package/addon/controllers/connectivity/events/index/details.js +0 -3
  211. package/addon/routes/connectivity/events/index/details.js +0 -3
  212. /package/addon/templates/connectivity/events/{index/details.hbs → details.hbs} +0 -0
@@ -0,0 +1,147 @@
1
+ <div class="flex flex-col gap-3 p-3">
2
+ <div class="flex items-start justify-between gap-3">
3
+ <div class="min-w-0">
4
+ <h2 class="text-base font-bold text-gray-900 dark:text-gray-100">Vehicle Attachment</h2>
5
+ <p class="mt-0.5 text-xs text-gray-500 dark:text-gray-300">Fleet context for telemetry from this device.</p>
6
+ </div>
7
+
8
+ {{#if this.hasVehicle}}
9
+ <div class="flex flex-nowrap items-center gap-2 whitespace-nowrap">
10
+ {{#if this.canOpenVehicle}}
11
+ <Button @icon="eye" @text="Open Vehicle" @size="xs" @onClick={{this.openVehicle}} />
12
+ {{/if}}
13
+ {{#if this.canLocateVehicle}}
14
+ <Button @icon="location-dot" @text="Locate" @size="xs" @onClick={{this.locateVehicle}} />
15
+ {{/if}}
16
+ <Button @icon="shuffle" @text="Change Vehicle" @size="xs" @onClick={{this.attachToVehicle}} />
17
+ <Button @icon="unlink" @text="Detach" @size="xs" @type="danger" @onClick={{this.detachFromVehicle}} />
18
+ </div>
19
+ {{/if}}
20
+ </div>
21
+
22
+ {{#if this.hasVehicle}}
23
+ <section class="overflow-hidden rounded-md border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800">
24
+ <div class="flex gap-3 p-3">
25
+ <Image
26
+ src={{this.vehiclePhotoUrl}}
27
+ @fallbackSrc={{config "defaultValues.placeholderImage"}}
28
+ alt={{this.vehicleName}}
29
+ class="h-20 w-20 flex-shrink-0 rounded-md object-cover shadow-sm"
30
+ />
31
+
32
+ <div class="min-w-0 flex-1">
33
+ <div class="flex flex-wrap items-center gap-2">
34
+ <h3 class="truncate text-base font-bold text-gray-900 dark:text-gray-100">{{this.vehicleName}}</h3>
35
+ {{#if this.vehicleStatus}}
36
+ <Badge @status={{this.vehicleStatus}}>{{smart-humanize this.vehicleStatus}}</Badge>
37
+ {{/if}}
38
+ </div>
39
+
40
+ <div class="mt-1 grid grid-cols-1 gap-2 text-xs text-gray-500 dark:text-gray-300 sm:grid-cols-2 lg:grid-cols-4">
41
+ <div>
42
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Plate</div>
43
+ <div class="truncate text-gray-800 dark:text-gray-100">{{n-a this.plateNumber}}</div>
44
+ </div>
45
+ <div>
46
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">VIN</div>
47
+ <div class="truncate text-gray-800 dark:text-gray-100">{{n-a this.vin}}</div>
48
+ </div>
49
+ <div>
50
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Call Sign</div>
51
+ <div class="truncate text-gray-800 dark:text-gray-100">{{n-a this.callSign}}</div>
52
+ </div>
53
+ <div>
54
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Driver</div>
55
+ <div class="truncate text-gray-800 dark:text-gray-100">{{n-a this.vehicleDriverName}}</div>
56
+ </div>
57
+ </div>
58
+
59
+ <div class="mt-3 grid grid-cols-1 gap-2 text-xs text-gray-500 dark:text-gray-300 sm:grid-cols-3">
60
+ <div>
61
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Vehicle</div>
62
+ <div class="truncate text-gray-800 dark:text-gray-100">{{n-a this.yearMakeModel}}</div>
63
+ </div>
64
+ <div>
65
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Attached Device</div>
66
+ <div class="truncate text-gray-800 dark:text-gray-100">{{n-a this.device.displayName}}</div>
67
+ </div>
68
+ <div>
69
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Device Last Seen</div>
70
+ <div class="truncate text-gray-800 dark:text-gray-100">{{n-a (format-date-fns this.device.last_online_at "dd MMM yyyy, HH:mm")}}</div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </section>
76
+
77
+ <section class="overflow-hidden rounded-md border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800">
78
+ <div class="flex items-start justify-between gap-3 border-b border-gray-200 px-3 py-2 dark:border-gray-700">
79
+ <div class="min-w-0">
80
+ <h3 class="text-sm font-bold text-gray-900 dark:text-gray-100">Latest Positions</h3>
81
+ <p class="mt-0.5 text-xs text-gray-500 dark:text-gray-300">Recent vehicle coordinates reported through this device attachment.</p>
82
+ </div>
83
+ {{#if this.canOpenVehicle}}
84
+ <Button @icon="route" @text="Full History" @size="xs" @onClick={{this.openVehiclePositions}} />
85
+ {{/if}}
86
+ </div>
87
+
88
+ {{#if this.hasPositions}}
89
+ <div class="grid grid-cols-1 gap-0 divide-y divide-gray-100 dark:divide-gray-700">
90
+ {{#each this.positions as |position index|}}
91
+ <div class="flex flex-wrap items-center justify-between gap-3 px-3 py-2 text-xs">
92
+ <div class="flex min-w-0 items-center gap-2">
93
+ <div class="flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-md bg-blue-50 text-blue-600 dark:bg-blue-900/30 dark:text-blue-300">
94
+ <span class="font-bold">{{add index 1}}</span>
95
+ </div>
96
+ <div class="min-w-0">
97
+ <div class="truncate font-semibold text-gray-900 dark:text-gray-100">{{n-a (format-date-fns position.created_at "dd MMM yyyy, HH:mm")}}</div>
98
+ <div class="truncate text-gray-500 dark:text-gray-400">{{n-a (point-coordinates position.coordinates)}}</div>
99
+ </div>
100
+ </div>
101
+ <div class="grid grid-cols-2 gap-2 text-right text-gray-500 dark:text-gray-400 sm:grid-cols-3">
102
+ <div>
103
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Speed</div>
104
+ <div class="text-gray-800 dark:text-gray-100">{{n-a position.speed}}</div>
105
+ </div>
106
+ <div>
107
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Heading</div>
108
+ <div class="text-gray-800 dark:text-gray-100">{{n-a position.heading position.bearing}}</div>
109
+ </div>
110
+ <div>
111
+ <div class="font-semibold uppercase text-gray-400 dark:text-gray-500">Altitude</div>
112
+ <div class="text-gray-800 dark:text-gray-100">{{n-a position.altitude}}</div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ {{/each}}
117
+ </div>
118
+
119
+ <div class="border-t border-gray-200 dark:border-gray-700">
120
+ <PositionsReplay @resource={{this.vehicle}} @mapHeight={{180}} class="max-h-[360px] overflow-hidden" />
121
+ </div>
122
+ {{else}}
123
+ <div class="p-3">
124
+ <Telematic::TabEmptyState
125
+ @tone="info"
126
+ @icon="location-dot"
127
+ @title="No recent positions"
128
+ @message="This attached vehicle does not have recent position history available yet."
129
+ @primaryText="Locate Vehicle"
130
+ @primaryIcon="location-dot"
131
+ @primaryAction={{this.locateVehicle}}
132
+ />
133
+ </div>
134
+ {{/if}}
135
+ </section>
136
+ {{else}}
137
+ <Telematic::TabEmptyState
138
+ @tone="warning"
139
+ @icon="link-slash"
140
+ @title="No vehicle attached"
141
+ @message="Attach this device to a vehicle so telemetry has fleet context."
142
+ @primaryText="Attach Vehicle"
143
+ @primaryIcon="link"
144
+ @primaryAction={{this.attachToVehicle}}
145
+ />
146
+ {{/if}}
147
+ </div>
@@ -1,55 +1,59 @@
1
1
  <div class="flex flex-col gap-4 p-4 md:p-6">
2
- <div class="flex flex-col gap-1">
3
- <h2 class="text-base font-bold text-gray-900 dark:text-gray-100">Vehicle Attachment Mapping</h2>
4
- <p class="text-sm text-gray-500 dark:text-gray-300">Map synced provider devices to vehicles so telemetry can power vehicle state, maintenance, and operations workflows.</p>
5
- </div>
6
-
7
- <section class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
8
- {{#each this.metrics as |metric|}}
9
- <div class="fleet-ops-widget fleet-ops-kpi-tile fleetops-connectivity-kpi-tile {{metric.accentClass}} relative min-h-[102px] overflow-hidden rounded-md border bg-white shadow-sm dark:bg-gray-800">
10
- <div class="flex h-full items-start justify-between gap-3 p-3">
11
- <div class="min-w-0">
12
- <div class="truncate text-[10px] font-bold uppercase text-gray-500 dark:text-gray-400">{{metric.label}}</div>
13
- <div class="mt-2 text-2xl font-extrabold leading-none text-gray-900 dark:text-gray-50">{{metric.value}}</div>
14
- </div>
15
- <div class="fleetops-connectivity-kpi-icon flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md text-[13px]">
16
- <FaIcon @icon={{metric.icon}} />
2
+ <section class="overflow-hidden rounded-md border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800">
3
+ <div class="border-b border-gray-200 px-4 py-3 dark:border-gray-700">
4
+ <div class="flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between">
5
+ <div class="min-w-0">
6
+ <h3 class="text-sm font-bold text-gray-900 dark:text-gray-100">Attachment Workspace</h3>
7
+ <p class="mt-1 truncate text-xs text-gray-500 dark:text-gray-300">
8
+ Loaded
9
+ {{this.syncedDevices.length}}
10
+ of
11
+ {{this.totalSyncedDevices}}
12
+ synced devices.
13
+ </p>
14
+ </div>
15
+ <div class="flex w-full min-w-0 items-start gap-2 xl:max-w-4xl">
16
+ <div class="grid min-w-0 flex-1 grid-cols-1 gap-2 sm:grid-cols-3">
17
+ <Input
18
+ @value={{this.query}}
19
+ @type="text"
20
+ class="form-input form-input-sm h-10 w-full text-sm"
21
+ placeholder="Search vehicles or devices"
22
+ {{on "input" this.updateQuery}}
23
+ />
24
+ <select class="form-select form-select-sm h-10 w-full text-sm" {{on "change" this.updateStatus}}>
25
+ <option value="" selected={{not this.status}}>Any status</option>
26
+ <option value="active" selected={{eq this.status "active"}}>Active</option>
27
+ <option value="online" selected={{eq this.status "online"}}>Online</option>
28
+ <option value="recently_offline" selected={{eq this.status "recently_offline"}}>Recently offline</option>
29
+ <option value="offline" selected={{eq this.status "offline"}}>Offline</option>
30
+ <option value="long_offline" selected={{eq this.status "long_offline"}}>Long offline</option>
31
+ <option value="never_connected" selected={{eq this.status "never_connected"}}>Never connected</option>
32
+ <option value="inactive" selected={{eq this.status "inactive"}}>Inactive</option>
33
+ </select>
34
+ <div class="min-w-0">
35
+ <ModelSelect
36
+ @modelName="vehicle"
37
+ @query={{hash telematic_uuid=this.telematic.id}}
38
+ @selectedModel={{this.selectedVehicle}}
39
+ @placeholder="Any vehicle"
40
+ @triggerClass="fleetops-attachments-vehicle-filter-trigger form-select form-select-sm h-10 w-full text-sm"
41
+ @infiniteScroll={{false}}
42
+ @renderInPlace={{false}}
43
+ @allowClear={{true}}
44
+ @onChange={{this.updateSelectedVehicle}}
45
+ as |vehicle|
46
+ >
47
+ {{vehicle.displayName}}
48
+ </ModelSelect>
49
+ </div>
17
50
  </div>
51
+ <Button @icon="refresh" @size="xs" @isLoading={{this.isRefreshing}} @disabled={{this.isRefreshing}} @onClick={{this.refresh}} />
18
52
  </div>
19
53
  </div>
20
- {{/each}}
21
- </section>
22
-
23
- <section class="overflow-hidden rounded-md border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800">
24
- <div class="flex flex-col gap-3 border-b border-gray-200 px-4 py-3 dark:border-gray-700 lg:flex-row lg:items-start lg:justify-between">
25
- <div class="max-w-xl">
26
- <h3 class="text-sm font-bold text-gray-900 dark:text-gray-100">Vehicle Groups</h3>
27
- <p class="mt-1 text-xs leading-5 text-gray-500 dark:text-gray-300">Find a vehicle to review its attached devices, or resolve the unattached queue first.</p>
28
- </div>
29
- <div class="flex w-full min-w-0 flex-nowrap items-center justify-end gap-2 overflow-x-auto lg:w-auto lg:flex-shrink-0">
30
- <Input
31
- @value={{this.query}}
32
- @type="text"
33
- class="form-input h-9 min-w-[16rem] flex-shrink-0"
34
- placeholder="Search vehicles or devices"
35
- {{on "input" this.updateQuery}}
36
- />
37
- <select class="form-select h-9 flex-shrink-0" {{on "change" this.updateAttachmentState}}>
38
- <option value="" selected={{not this.attachment_state}}>All mappings</option>
39
- <option value="unattached" selected={{eq this.attachment_state "unattached"}}>Unattached</option>
40
- <option value="attached" selected={{eq this.attachment_state "attached"}}>Attached</option>
41
- </select>
42
- <select class="form-select h-9 flex-shrink-0" {{on "change" this.updateStatus}}>
43
- <option value="" selected={{not this.status}}>Any status</option>
44
- <option value="active" selected={{eq this.status "active"}}>Active</option>
45
- <option value="online" selected={{eq this.status "online"}}>Online</option>
46
- <option value="offline" selected={{eq this.status "offline"}}>Offline</option>
47
- <option value="inactive" selected={{eq this.status "inactive"}}>Inactive</option>
48
- </select>
49
- </div>
50
54
  </div>
51
55
 
52
- {{#if (or (eq this.emptyStateVariant "not_synced") (eq this.emptyStateVariant "filtered_empty"))}}
56
+ {{#if (or (eq this.emptyStateVariant "error") (eq this.emptyStateVariant "not_synced") (eq this.emptyStateVariant "filtered_empty"))}}
53
57
  <div class="p-4">
54
58
  <Telematic::TabEmptyState
55
59
  @tone={{this.emptyStateContent.tone}}
@@ -66,97 +70,170 @@
66
70
  />
67
71
  </div>
68
72
  {{else}}
69
- <div class="divide-y divide-gray-200 dark:divide-gray-700">
70
- {{#if (eq this.emptyStateVariant "empty")}}
71
- <div class="p-4">
72
- <Telematic::TabEmptyState
73
- @tone={{this.emptyStateContent.tone}}
74
- @icon={{this.emptyStateContent.icon}}
75
- @title={{this.emptyStateContent.title}}
76
- @message={{this.emptyStateContent.message}}
77
- @note={{this.emptyStateContent.note}}
78
- />
79
- </div>
80
- {{/if}}
81
-
82
- {{#if (eq this.emptyStateVariant "unattached_only")}}
83
- <div class="p-4">
84
- <Telematic::TabEmptyState
85
- @tone={{this.emptyStateContent.tone}}
86
- @icon={{this.emptyStateContent.icon}}
87
- @title={{this.emptyStateContent.title}}
88
- @message={{this.emptyStateContent.message}}
89
- @note={{this.emptyStateContent.note}}
90
- />
91
- </div>
92
- {{/if}}
93
-
94
- <div class="bg-yellow-50/70 px-4 py-3 dark:bg-yellow-900/10">
95
- <div class="mb-3 flex flex-col gap-2 md:flex-row md:items-center md:justify-between">
96
- <div>
97
- <h4 class="text-sm font-bold text-gray-900 dark:text-gray-100">Unattached Devices</h4>
98
- <p class="text-xs text-yellow-800 dark:text-yellow-300">These devices are synced, but not yet mapped to a vehicle. Attach devices deliberately one at a time.</p>
73
+ <div class="grid grid-cols-1 divide-y divide-gray-200 dark:divide-gray-700 md:grid-cols-2 md:divide-x md:divide-y-0">
74
+ <div class="min-w-0 bg-gray-50/70 dark:bg-gray-900/20">
75
+ <div class="sticky top-0 z-10 border-b border-gray-200 bg-gray-50/95 px-4 py-3 backdrop-blur dark:border-gray-700 dark:bg-gray-800/95">
76
+ <div class="flex items-start justify-between gap-3">
77
+ <div class="min-w-0">
78
+ <div class="flex items-center gap-2">
79
+ <h4 class="text-sm font-bold text-gray-900 dark:text-gray-100">Unattached</h4>
80
+ <span class="text-xs font-semibold text-gray-500 dark:text-gray-400">{{this.filteredUnattachedCount}} devices</span>
81
+ </div>
82
+ {{#if this.selectedDevice}}
83
+ <p class="mt-1 truncate text-xs text-blue-600 dark:text-blue-300">
84
+ Selected:
85
+ {{this.selectedDeviceName}}.
86
+ Choose a vehicle on the right.
87
+ </p>
88
+ {{else}}
89
+ <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Select a device, then choose a vehicle target.</p>
90
+ {{/if}}
91
+ </div>
92
+ {{#if this.selectedDevice}}
93
+ <Button @icon="times" @size="xs" @onClick={{this.clearSelectedDevice}} />
94
+ {{/if}}
95
+ </div>
99
96
  </div>
100
- <Badge @status={{if this.unattachedDevices.length "warning" "success"}} @hideStatusDot={{true}}>
101
- {{this.unattachedDevices.length}} devices
102
- </Badge>
103
- </div>
104
97
 
105
- {{#if this.unattachedDevices.length}}
106
- <div class="grid grid-cols-1 gap-2 xl:grid-cols-2">
107
- {{#each this.unattachedDevices as |device|}}
108
- <div class="flex flex-col gap-3 rounded-md border border-yellow-200 bg-white p-3 dark:border-yellow-700 dark:bg-gray-800 md:flex-row md:items-center md:justify-between">
109
- <div class="min-w-0">
110
- <Device::Pill @device={{device}} />
111
- </div>
112
- <div class="flex flex-shrink-0 items-center gap-2">
113
- <Button @icon="eye" @text="Open" @size="xs" @onClick={{fn this.deviceActions.transition.view device}} />
114
- <Button @icon="link" @text="Attach" @size="xs" @type="primary" @onClick={{fn this.openAttachDeviceModal device}} />
98
+ <div class="h-[calc(100vh-24rem)] min-h-[28rem] overflow-y-auto">
99
+ {{#if this.unattachedDevices.length}}
100
+ <div class="divide-y divide-gray-200 dark:divide-gray-700">
101
+ {{#each this.unattachedDevices as |device|}}
102
+ <div
103
+ class="group flex min-h-[56px] cursor-pointer items-center gap-3 border-l-2 px-3 py-2 transition {{if
104
+ (eq this.selectedDevice device)
105
+ "border-blue-500 bg-blue-50 dark:bg-blue-900/20"
106
+ "border-transparent bg-white hover:border-blue-300 hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700/50"
107
+ }}"
108
+ {{on "click" (fn this.selectUnattachedDevice device)}}
109
+ >
110
+ <div class="flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-md bg-gray-100 text-gray-500 dark:bg-gray-700 dark:text-gray-300">
111
+ <FaIcon @icon="microchip" />
112
+ </div>
113
+ <div class="min-w-0 flex-1">
114
+ <div class="flex min-w-0 items-center gap-2">
115
+ <span class="truncate text-sm font-semibold text-gray-900 dark:text-gray-100">{{or device.displayName device.name device.device_id}}</span>
116
+ <Badge
117
+ @status={{or device.connection_status device.status "default"}}
118
+ @hideIcon={{true}}
119
+ @wrapperClass="text-[9px] px-1 py-0 leading-tight flex-shrink-0"
120
+ >
121
+ {{smart-humanize (or device.connection_status device.status "unknown")}}
122
+ </Badge>
123
+ </div>
124
+ <div class="mt-0.5 flex min-w-0 items-center gap-2 text-xs text-gray-500 dark:text-gray-400">
125
+ <span class="truncate">{{or device.public_id device.device_id device.serial_number device.imei device.id}}</span>
126
+ </div>
127
+ </div>
128
+ <div class="flex flex-shrink-0 items-center gap-1">
129
+ <Button @icon="eye" @size="xs" @onClick={{fn this.deviceActions.transition.view device}} />
130
+ {{#if (eq this.selectedDevice device)}}
131
+ <Button @icon="link" @text="Attach" @size="xs" @type="primary" @onClick={{fn this.openAttachDeviceModal device}} />
132
+ {{else}}
133
+ <Button @icon="link" @size="xs" @type="default" @onClick={{fn this.openAttachDeviceModal device}} />
134
+ {{/if}}
135
+ </div>
136
+ </div>
137
+ {{/each}}
138
+ </div>
139
+ {{else}}
140
+ <div class="p-4">
141
+ <div class="rounded-md border border-green-200 bg-green-50 p-3 text-sm text-green-800 dark:border-green-700 dark:bg-green-900/20 dark:text-green-300">
142
+ All visible synced devices are mapped to vehicles.
115
143
  </div>
116
144
  </div>
117
- {{/each}}
145
+ {{/if}}
118
146
  </div>
119
- {{else}}
120
- <div class="rounded-md border border-green-200 bg-green-50 p-3 text-sm text-green-800 dark:border-green-700 dark:bg-green-900/20 dark:text-green-300">
121
- All synced devices in this view are mapped to vehicles.
122
- </div>
123
- {{/if}}
124
147
  </div>
125
148
 
126
- {{#each this.vehicleGroups as |group|}}
127
- <div class="px-4 py-3">
128
- <div class="mb-3 flex flex-col gap-2 md:flex-row md:items-center md:justify-between">
149
+ <div class="min-w-0">
150
+ <div class="sticky top-0 z-10 border-b border-gray-200 bg-white/95 px-4 py-3 backdrop-blur dark:border-gray-700 dark:bg-gray-800/95">
151
+ <div class="flex items-start justify-between gap-3">
129
152
  <div class="min-w-0">
130
- <h4 class="truncate text-sm font-bold text-gray-900 dark:text-gray-100">{{group.name}}</h4>
131
- <p class="text-xs text-gray-500 dark:text-gray-300">{{group.devices.length}} attached provider devices</p>
153
+ <div class="flex items-center gap-2">
154
+ <h4 class="text-sm font-bold text-gray-900 dark:text-gray-100">Vehicles</h4>
155
+ <span class="text-xs font-semibold text-gray-500 dark:text-gray-400">{{this.vehicleGroups.length}} mapped</span>
156
+ </div>
157
+ {{#if this.selectedDevice}}
158
+ <p class="mt-1 truncate text-xs text-blue-600 dark:text-blue-300">
159
+ Choose a vehicle for
160
+ {{this.selectedDeviceName}}
161
+ </p>
162
+ {{else}}
163
+ <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Attached devices grouped by vehicle.</p>
164
+ {{/if}}
132
165
  </div>
133
- <Badge @status="info" @hideStatusDot={{true}}>Vehicle mapped</Badge>
134
166
  </div>
167
+ </div>
135
168
 
136
- <div class="overflow-hidden rounded-md border border-gray-200 dark:border-gray-700">
137
- {{#each group.devices as |device|}}
138
- <div class="grid grid-cols-1 gap-3 border-b border-gray-200 p-3 last:border-b-0 dark:border-gray-700 lg:grid-cols-[minmax(0,1.5fr)_minmax(0,1fr)_auto] lg:items-center">
139
- <Device::Pill @device={{device}} />
140
- <div class="grid grid-cols-2 gap-2 text-xs">
141
- <div>
142
- <div class="text-gray-400 dark:text-gray-500">Provider ID</div>
143
- <div class="truncate font-semibold text-gray-900 dark:text-gray-100">{{n-a device.device_id}}</div>
169
+ <div class="h-[calc(100vh-24rem)] min-h-[28rem] overflow-y-auto">
170
+ {{#if this.vehicleGroups.length}}
171
+ <div class="divide-y divide-gray-200 dark:divide-gray-700">
172
+ {{#each this.vehicleGroups as |group|}}
173
+ <div class="border-l-2 border-transparent px-4 py-3 transition hover:border-blue-300 hover:bg-blue-50/40 dark:hover:bg-blue-900/10">
174
+ <div class="mb-2 flex items-center justify-between gap-3">
175
+ <div class="flex min-w-0 items-center gap-3">
176
+ <Image
177
+ src={{or group.vehicle.photo_url group.vehicle.avatar_url}}
178
+ @fallbackSrc={{config "defaultValues.vehicleImage"}}
179
+ alt={{group.name}}
180
+ class="h-10 w-9 flex-shrink-0 rounded-md object-cover"
181
+ />
182
+ <div class="min-w-0">
183
+ <div class="truncate text-sm font-bold text-gray-900 dark:text-gray-100">{{or group.vehicle.displayName group.vehicle.display_name group.vehicle.name group.name}}</div>
184
+ <div class="mt-0.5 truncate text-xs text-gray-500 dark:text-gray-400">
185
+ {{n-a (or group.vehicle.plate_number group.vehicle.internal_id group.vehicle.call_sign group.vehicle.vin)}}
186
+ <span class="mx-1">·</span>
187
+ {{group.devices.length}}
188
+ devices
189
+ </div>
190
+ </div>
191
+ </div>
192
+ {{#if this.selectedDevice}}
193
+ <Button @icon="link" @text="Attach here" @size="xs" @type="primary" @onClick={{fn this.attachSelectedDeviceToGroup group}} />
194
+ {{/if}}
144
195
  </div>
145
- <div>
146
- <div class="text-gray-400 dark:text-gray-500">Last seen</div>
147
- <div class="truncate font-semibold text-gray-900 dark:text-gray-100">{{n-a (format-date-fns device.last_online_at "dd MMM HH:mm")}}</div>
196
+
197
+ <div class="overflow-hidden rounded-md border border-gray-200 dark:border-gray-700">
198
+ {{#each group.devices as |device|}}
199
+ <div class="flex min-h-[46px] items-center gap-3 border-b border-gray-200 px-3 py-2 last:border-b-0 dark:border-gray-700">
200
+ <div class="min-w-0 flex-1">
201
+ <div class="flex min-w-0 items-center gap-2">
202
+ <span class="truncate text-sm font-semibold text-gray-800 dark:text-gray-100">{{or device.displayName device.name device.device_id}}</span>
203
+ <Badge
204
+ @status={{or device.connection_status device.status "default"}}
205
+ @hideIcon={{true}}
206
+ @wrapperClass="text-[9px] px-1 py-0 leading-tight flex-shrink-0"
207
+ >
208
+ {{smart-humanize (or device.connection_status device.status "unknown")}}
209
+ </Badge>
210
+ </div>
211
+ <div class="mt-0.5 flex min-w-0 items-center gap-2 text-xs text-gray-500 dark:text-gray-400">
212
+ <span class="truncate">{{or device.public_id device.device_id device.serial_number device.imei device.id}}</span>
213
+ <span class="h-1 w-1 flex-shrink-0 rounded-full bg-gray-400"></span>
214
+ <span class="flex-shrink-0">{{n-a (format-date-fns device.last_online_at "dd MMM HH:mm")}}</span>
215
+ </div>
216
+ </div>
217
+ <div class="flex flex-shrink-0 items-center gap-1">
218
+ <Button @icon="eye" @size="xs" @onClick={{fn this.deviceActions.transition.view device}} />
219
+ <Button @icon="shuffle" @size="xs" @onClick={{fn this.openAttachDeviceModal device}} />
220
+ <Button @icon="unlink" @size="xs" @type="danger" @onClick={{fn this.detachDevice device}} />
221
+ </div>
222
+ </div>
223
+ {{/each}}
148
224
  </div>
149
225
  </div>
150
- <div class="flex items-center gap-2 lg:justify-end">
151
- <Button @icon="eye" @text="Open" @size="xs" @onClick={{fn this.deviceActions.transition.view device}} />
152
- <Button @icon="shuffle" @text="Change" @size="xs" @onClick={{fn this.openAttachDeviceModal device}} />
153
- <Button @icon="unlink" @text="Detach" @size="xs" @type="danger" @onClick={{fn this.detachDevice device}} />
154
- </div>
226
+ {{/each}}
227
+ </div>
228
+ {{else}}
229
+ <div class="p-4">
230
+ <div class="rounded-md border border-gray-200 bg-gray-50 p-4 text-sm text-gray-600 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300">
231
+ No visible vehicle groups. Attach a device from the left pane or adjust the filters.
155
232
  </div>
156
- {{/each}}
157
- </div>
233
+ </div>
234
+ {{/if}}
158
235
  </div>
159
- {{/each}}
236
+ </div>
160
237
  </div>
161
238
  {{/if}}
162
239
  </section>
@@ -26,7 +26,7 @@
26
26
  <h3 class="text-sm font-bold text-gray-900 dark:text-gray-100">Synced Devices</h3>
27
27
  <p class="mt-1 text-xs leading-5 text-gray-500 dark:text-gray-300">Search provider identifiers, filter attachment state, and open devices for troubleshooting.</p>
28
28
  </div>
29
- <div class="fleetops-provider-connections-actions flex min-w-0 flex-wrap items-center gap-2 lg:ml-auto lg:flex-nowrap lg:justify-end">
29
+ <div class="fleetops-provider-connections-actions flex min-w-0 flex-wrap items-center gap-1 lg:ml-auto lg:flex-nowrap lg:justify-end">
30
30
  <Layout::Resource::TabularActions
31
31
  @title="Synced Devices"
32
32
  @searchQuery={{this.query}}
@@ -40,6 +40,8 @@
40
40
  @searchInputClass="fleetops-provider-connections-search"
41
41
  @filterPickerButtonClass="fleetops-provider-connections-action-button"
42
42
  @columnPickerButtonClass="fleetops-provider-connections-action-button"
43
+ @filterPickerSize="sm"
44
+ @columnPickerSize="sm"
43
45
  />
44
46
  </div>
45
47
  </div>
@@ -70,6 +72,7 @@
70
72
  @onPageChange={{fn (mut this.page)}}
71
73
  @controller={{this}}
72
74
  @withoutHeader={{true}}
75
+ @tableWrapperClass="no-table-extra-spacing"
73
76
  @emptyStateComponent={{component
74
77
  "table/empty-state"
75
78
  variant="compact"
@@ -26,7 +26,7 @@
26
26
  <h3 class="text-sm font-bold text-gray-900 dark:text-gray-100">Telemetry Events</h3>
27
27
  <p class="mt-1 text-xs leading-5 text-gray-500 dark:text-gray-300">Filter events by severity, device, type, and processed state before opening details.</p>
28
28
  </div>
29
- <div class="fleetops-provider-connections-actions flex min-w-0 flex-wrap items-center gap-2 lg:ml-auto lg:flex-nowrap lg:justify-end">
29
+ <div class="fleetops-provider-connections-actions flex min-w-0 flex-wrap items-center gap-1 lg:ml-auto lg:flex-nowrap lg:justify-end">
30
30
  <Layout::Resource::TabularActions
31
31
  @title="Telemetry Events"
32
32
  @searchQuery={{this.query}}
@@ -40,6 +40,8 @@
40
40
  @searchInputClass="fleetops-provider-connections-search"
41
41
  @filterPickerButtonClass="fleetops-provider-connections-action-button"
42
42
  @columnPickerButtonClass="fleetops-provider-connections-action-button"
43
+ @filterPickerSize="sm"
44
+ @columnPickerSize="sm"
43
45
  />
44
46
  </div>
45
47
  </div>
@@ -83,6 +85,7 @@
83
85
  @onPageChange={{fn (mut this.page)}}
84
86
  @controller={{this}}
85
87
  @withoutHeader={{true}}
88
+ @tableWrapperClass="no-table-extra-spacing"
86
89
  @emptyStateComponent={{component
87
90
  "table/empty-state"
88
91
  variant="compact"
@@ -40,6 +40,8 @@
40
40
  @searchInputClass="fleetops-provider-connections-search"
41
41
  @filterPickerButtonClass="fleetops-provider-connections-action-button"
42
42
  @columnPickerButtonClass="fleetops-provider-connections-action-button"
43
+ @filterPickerSize="sm"
44
+ @columnPickerSize="sm"
43
45
  />
44
46
  </div>
45
47
  </div>
@@ -70,6 +72,7 @@
70
72
  @onPageChange={{fn (mut this.page)}}
71
73
  @controller={{this}}
72
74
  @withoutHeader={{true}}
75
+ @tableWrapperClass="no-table-extra-spacing"
73
76
  @emptyStateComponent={{component
74
77
  "table/empty-state"
75
78
  variant="compact"
@@ -1,7 +1,7 @@
1
1
  <Layout::Resource::Panel
2
2
  @resource={{@model}}
3
3
  @controller={{this}}
4
- @headerTitle={{t "common.edit-resource-name" resourceName=@model.display_name}}
4
+ @headerTitle={{t "common.edit-resource-name" resourceName=@model.displayName}}
5
5
  @actionButtons={{this.actionButtons}}
6
6
  @saveTask={{this.save}}
7
7
  @onPressCancel={{this.cancel}}
@@ -1,7 +1,7 @@
1
1
  <Layout::Resource::Panel
2
2
  @resource={{@model}}
3
3
  @controller={{this}}
4
- @headerTitle={{or @model.name}}
4
+ @headerComponent={{component "vendor/panel-header"}}
5
5
  @actionButtons={{this.actionButtons}}
6
6
  @onPressCancel={{transition-to "management.vendors.index"}}
7
7
  @onOverlayReady={{fn (mut this.overlay)}}
@@ -11,4 +11,4 @@
11
11
  <TabNavigation @tabs={{this.tabs}} @contentClass="scrollable" @tablistClass="pl-2">
12
12
  {{outlet}}
13
13
  </TabNavigation>
14
- </Layout::Resource::Panel>
14
+ </Layout::Resource::Panel>
@@ -19,6 +19,7 @@
19
19
  <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
20
20
  <PowerSelectMultiple
21
21
  @searchEnabled={{true}}
22
+ @searchField="label"
22
23
  @options={{this.notifiables}}
23
24
  @selected={{get this.notificationSettings (concat (get-notification-key notification.definition notification.name) ".notifiables")}}
24
25
  @onChange={{fn this.onSelectNotifiable notification}}
@@ -35,4 +36,4 @@
35
36
  </div>
36
37
  </div>
37
38
  <Spacer @height="600px" />
38
- </Layout::Section::Body>
39
+ </Layout::Section::Body>