@fleetbase/fleetops-engine 0.3.0 → 0.3.2

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 (235) hide show
  1. package/addon/components/contact-form-panel.hbs +82 -0
  2. package/addon/components/contact-form-panel.js +195 -0
  3. package/addon/components/contact-panel/details.hbs +36 -0
  4. package/addon/components/contact-panel/details.js +3 -0
  5. package/addon/components/contact-panel.hbs +52 -0
  6. package/addon/components/contact-panel.js +161 -0
  7. package/addon/components/driver-form-panel.hbs +39 -55
  8. package/addon/components/driver-form-panel.js +41 -0
  9. package/addon/components/driver-panel/details.hbs +2 -2
  10. package/addon/components/driver-panel.hbs +12 -10
  11. package/addon/components/driver-panel.js +13 -0
  12. package/addon/components/fleet-form-panel.hbs +28 -28
  13. package/addon/components/fleet-form-panel.js +150 -1
  14. package/addon/components/fleet-listing-panel.hbs +8 -0
  15. package/addon/components/fleet-listing-panel.js +34 -0
  16. package/addon/components/fleet-panel/details.hbs +30 -0
  17. package/addon/components/fleet-panel/driver-listing.hbs +72 -0
  18. package/addon/components/fleet-panel/driver-listing.js +149 -0
  19. package/addon/components/fleet-panel/vehicle-listing.hbs +72 -0
  20. package/addon/components/fleet-panel/vehicle-listing.js +149 -0
  21. package/addon/components/fleet-panel.hbs +12 -58
  22. package/addon/components/fleet-panel.js +148 -26
  23. package/addon/components/fleet-vehicle-listing.hbs +0 -1
  24. package/addon/components/fuel-report-form-panel.hbs +41 -0
  25. package/addon/components/fuel-report-form-panel.js +122 -0
  26. package/addon/components/fuel-report-panel/details.hbs +38 -0
  27. package/addon/components/fuel-report-panel.hbs +30 -0
  28. package/addon/components/fuel-report-panel.js +161 -0
  29. package/addon/components/issue-form-panel.hbs +85 -0
  30. package/addon/components/issue-form-panel.js +211 -0
  31. package/addon/components/issue-panel/details.hbs +48 -0
  32. package/addon/components/issue-panel.hbs +30 -0
  33. package/addon/components/issue-panel.js +160 -0
  34. package/addon/components/layout/fleet-ops-sidebar.hbs +2 -2
  35. package/addon/components/live-map.js +2 -0
  36. package/addon/components/map-container/toolbar.hbs +9 -9
  37. package/addon/components/map-container/topbar.hbs +1 -1
  38. package/addon/components/modals/issue-details.hbs +38 -0
  39. package/addon/components/modals/issue-from.hbs +138 -0
  40. package/addon/components/place-form-panel.hbs +50 -0
  41. package/addon/components/place-form-panel.js +134 -0
  42. package/addon/components/place-panel/details.hbs +95 -0
  43. package/addon/components/place-panel.hbs +30 -0
  44. package/addon/components/place-panel.js +161 -0
  45. package/addon/components/vehicle-form-panel.hbs +35 -44
  46. package/addon/components/vehicle-form-panel.js +41 -0
  47. package/addon/components/vehicle-panel/details.hbs +8 -2
  48. package/addon/components/vehicle-panel.hbs +8 -6
  49. package/addon/components/vendor-form-panel/create-form.hbs +114 -0
  50. package/addon/components/vendor-form-panel/create-form.js +158 -0
  51. package/addon/components/vendor-form-panel/edit-form.hbs +98 -0
  52. package/addon/components/vendor-form-panel/edit-form.js +51 -0
  53. package/addon/components/vendor-form-panel.hbs +48 -0
  54. package/addon/components/vendor-form-panel.js +226 -0
  55. package/addon/components/vendor-panel/details.hbs +77 -0
  56. package/addon/components/vendor-panel/details.js +12 -0
  57. package/addon/components/vendor-panel.hbs +58 -0
  58. package/addon/components/vendor-panel.js +161 -0
  59. package/addon/controllers/management/contacts/index/details.js +55 -0
  60. package/addon/controllers/management/contacts/index/edit.js +111 -0
  61. package/addon/controllers/management/contacts/index/new.js +88 -0
  62. package/addon/controllers/management/contacts/index.js +23 -128
  63. package/addon/controllers/management/drivers/index/new.js +2 -2
  64. package/addon/controllers/management/drivers/index.js +18 -32
  65. package/addon/controllers/management/fleets/index/details.js +53 -0
  66. package/addon/controllers/management/fleets/index/edit.js +75 -41
  67. package/addon/controllers/management/fleets/index/new.js +42 -57
  68. package/addon/controllers/management/fleets/index.js +0 -1
  69. package/addon/controllers/management/fuel-reports/index/details.js +63 -0
  70. package/addon/controllers/management/fuel-reports/index/edit.js +111 -0
  71. package/addon/controllers/management/fuel-reports/index/new.js +95 -0
  72. package/addon/controllers/management/fuel-reports/index.js +57 -127
  73. package/addon/controllers/management/issues/index/details.js +54 -0
  74. package/addon/controllers/management/issues/index/edit.js +111 -0
  75. package/addon/controllers/management/issues/index/new.js +94 -0
  76. package/addon/controllers/management/issues/index.js +131 -26
  77. package/addon/controllers/management/places/index/details.js +55 -0
  78. package/addon/controllers/management/places/index/edit.js +111 -0
  79. package/addon/controllers/management/places/index/new.js +88 -0
  80. package/addon/controllers/management/places/index.js +21 -182
  81. package/addon/controllers/management/vehicles/index/new.js +2 -6
  82. package/addon/controllers/management/vendors/index/details.js +55 -0
  83. package/addon/controllers/management/vendors/index/edit.js +111 -0
  84. package/addon/controllers/management/vendors/index/new.js +88 -0
  85. package/addon/controllers/management/vendors/index.js +43 -247
  86. package/addon/routes/management/contacts/index/details.js +14 -0
  87. package/addon/routes/management/contacts/index/edit.js +10 -0
  88. package/addon/routes/management/contacts/index/new.js +3 -0
  89. package/addon/routes/management/contacts/index.js +1 -1
  90. package/addon/routes/management/fleets/index/details.js +1 -1
  91. package/addon/routes/management/fleets/index/edit.js +1 -1
  92. package/addon/routes/management/fleets/index.js +1 -1
  93. package/addon/routes/management/fuel-reports/index/details.js +14 -0
  94. package/addon/routes/management/fuel-reports/index/edit.js +10 -0
  95. package/addon/routes/management/fuel-reports/index/new.js +3 -0
  96. package/addon/routes/management/fuel-reports/index.js +3 -1
  97. package/addon/routes/management/issues/index/details.js +14 -0
  98. package/addon/routes/management/issues/index/edit.js +10 -0
  99. package/addon/routes/management/issues/index/new.js +3 -0
  100. package/addon/routes/management/issues/index.js +1 -1
  101. package/addon/routes/management/places/index/details.js +14 -0
  102. package/addon/routes/management/places/index/edit.js +10 -0
  103. package/addon/routes/management/places/index/new.js +3 -0
  104. package/addon/routes/management/places/index.js +6 -1
  105. package/addon/routes/management/vendors/index/details.js +15 -0
  106. package/addon/routes/management/vendors/index/edit.js +11 -0
  107. package/addon/routes/management/vendors/index/new.js +3 -0
  108. package/addon/routes/management/vendors/index.js +1 -0
  109. package/addon/routes.js +27 -7
  110. package/addon/services/context-panel.js +60 -0
  111. package/addon/templates/management/contacts/index/details.hbs +1 -0
  112. package/addon/templates/management/contacts/index/edit.hbs +1 -0
  113. package/addon/templates/management/contacts/index/new.hbs +1 -0
  114. package/addon/templates/management/contacts/index.hbs +22 -3
  115. package/addon/templates/management/drivers/index.hbs +29 -5
  116. package/addon/templates/management/fleets/index/details.hbs +1 -1
  117. package/addon/templates/management/fleets/index/edit.hbs +1 -1
  118. package/addon/templates/management/fleets/index/new.hbs +1 -1
  119. package/addon/templates/management/fuel-reports/index/details.hbs +1 -0
  120. package/addon/templates/management/fuel-reports/index/edit.hbs +1 -0
  121. package/addon/templates/management/fuel-reports/index/new.hbs +1 -0
  122. package/addon/templates/management/fuel-reports/index.hbs +25 -4
  123. package/addon/templates/management/issues/index/details.hbs +1 -0
  124. package/addon/templates/management/issues/index/edit.hbs +1 -0
  125. package/addon/templates/management/issues/index/new.hbs +1 -0
  126. package/addon/templates/management/issues/index.hbs +5 -3
  127. package/addon/templates/management/places/index/details.hbs +1 -0
  128. package/addon/templates/management/places/index/edit.hbs +1 -0
  129. package/addon/templates/management/places/index/new.hbs +1 -0
  130. package/addon/templates/management/vendors/index/details.hbs +1 -0
  131. package/addon/templates/management/vendors/index/edit.hbs +1 -0
  132. package/addon/templates/management/vendors/index/new.hbs +1 -0
  133. package/addon/templates/operations/orders/index.hbs +3 -3
  134. package/app/components/contact-form-panel.js +1 -0
  135. package/app/components/contact-panel/details.js +1 -0
  136. package/app/components/contact-panel.js +1 -0
  137. package/app/components/fleet-listing-panel.js +1 -0
  138. package/app/components/fleet-panel/details.js +1 -0
  139. package/app/components/fleet-panel/driver-listing.js +1 -0
  140. package/app/components/fleet-panel/vehicle-listing.js +1 -0
  141. package/app/components/fuel-report-form-panel.js +1 -0
  142. package/app/components/fuel-report-panel.js +1 -0
  143. package/app/components/issue-form-panel.js +1 -0
  144. package/app/components/issue-panel.js +1 -0
  145. package/app/components/place-form-panel.js +1 -0
  146. package/app/components/place-panel.js +1 -0
  147. package/app/components/vendor-form-panel/create-form.js +1 -0
  148. package/app/components/vendor-form-panel/edit-form.js +1 -0
  149. package/app/components/vendor-form-panel.js +1 -0
  150. package/app/components/vendor-panel/details.js +1 -0
  151. package/app/components/vendor-panel.js +1 -0
  152. package/app/controllers/management/contacts/index/details.js +1 -0
  153. package/app/controllers/management/contacts/index/edit.js +1 -0
  154. package/app/controllers/management/contacts/index/new.js +1 -0
  155. package/app/controllers/management/fuel-reports/index/details.js +1 -0
  156. package/app/controllers/management/fuel-reports/index/edit.js +1 -0
  157. package/app/controllers/management/fuel-reports/index/new.js +1 -0
  158. package/app/controllers/management/issues/index/details.js +1 -0
  159. package/app/controllers/management/issues/index/edit.js +1 -0
  160. package/app/controllers/management/issues/index/new.js +1 -0
  161. package/app/controllers/management/places/index/details.js +1 -0
  162. package/app/controllers/management/places/index/edit.js +1 -0
  163. package/app/controllers/management/places/index/new.js +1 -0
  164. package/app/controllers/management/vendors/index/edit.js +1 -0
  165. package/app/controllers/management/vendors/index/new.js +1 -0
  166. package/app/routes/addon/routes/management/places/index/new.js +1 -0
  167. package/app/routes/management/contacts/index/details.js +1 -0
  168. package/app/routes/management/contacts/index/edit.js +1 -0
  169. package/app/routes/management/contacts/index/new.js +1 -0
  170. package/app/routes/management/fuel-reports/index/details.js +1 -0
  171. package/app/routes/management/fuel-reports/index/edit.js +1 -0
  172. package/app/routes/management/fuel-reports/index/new.js +1 -0
  173. package/app/routes/management/issues/index/details.js +1 -0
  174. package/app/routes/management/issues/index/edit.js +1 -0
  175. package/app/routes/management/issues/index/new.js +1 -0
  176. package/app/routes/management/places/index/details.js +1 -0
  177. package/app/routes/management/places/index/edit.js +1 -0
  178. package/app/routes/management/places/index/new.js +1 -0
  179. package/app/routes/management/vendors/index/details.js +1 -0
  180. package/app/routes/management/vendors/index/edit.js +1 -0
  181. package/app/routes/management/vendors/index/new.js +1 -0
  182. package/app/templates/addon/routes/management/places/index/new.js +1 -0
  183. package/app/templates/management/contacts/index/details.js +1 -0
  184. package/app/templates/management/contacts/index/edit.js +1 -0
  185. package/app/templates/management/contacts/index/new.js +1 -0
  186. package/app/templates/management/fuel-reports/index/details.js +1 -0
  187. package/app/templates/management/fuel-reports/index/edit.js +1 -0
  188. package/app/templates/management/fuel-reports/index/new.js +1 -0
  189. package/app/templates/management/issues/index/details.js +1 -0
  190. package/app/templates/management/issues/index/edit.js +1 -0
  191. package/app/templates/management/issues/index/new.js +1 -0
  192. package/app/templates/management/places/index/details.js +1 -0
  193. package/app/templates/management/places/index/edit.js +1 -0
  194. package/app/templates/management/places/index/new.js +1 -0
  195. package/app/templates/management/vendors/index/details.js +1 -0
  196. package/app/templates/management/vendors/index/edit.js +1 -0
  197. package/app/templates/management/vendors/index/new.js +1 -0
  198. package/composer.json +2 -2
  199. package/config/environment.js +2 -1
  200. package/extension.json +1 -1
  201. package/package.json +4 -3
  202. package/server/migrations/2023_11_03_072503_refactor_issues_table_columns.php +42 -0
  203. package/server/migrations/2023_11_06_040645_refactor_fuel_reports_table.php +38 -0
  204. package/server/src/Casts/Point.php +15 -1
  205. package/server/src/Http/Controllers/Internal/v1/DriverController.php +33 -15
  206. package/server/src/Http/Filter/FleetFilter.php +7 -0
  207. package/server/src/Http/Filter/FuelReportFilter.php +58 -0
  208. package/server/src/Http/Filter/IssueFilter.php +69 -0
  209. package/server/src/Http/Filter/VehicleFilter.php +10 -0
  210. package/server/src/Http/Middleware/TransformLocationMiddleware.php +48 -0
  211. package/server/src/Http/Resources/v1/Driver.php +1 -0
  212. package/server/src/Http/Resources/v1/Fleet.php +20 -21
  213. package/server/src/Http/Resources/v1/FuelReport.php +37 -35
  214. package/server/src/Http/Resources/v1/Issue.php +77 -0
  215. package/server/src/Http/Resources/v1/ParentFleet.php +60 -0
  216. package/server/src/Http/Resources/v1/SubFleet.php +60 -0
  217. package/server/src/Http/Resources/v1/Vehicle.php +4 -2
  218. package/server/src/Integrations/Lalamove/Lalamove.php +6 -6
  219. package/server/src/Models/Contact.php +7 -0
  220. package/server/src/Models/Driver.php +1 -1
  221. package/server/src/Models/Fleet.php +37 -4
  222. package/server/src/Models/FuelReport.php +53 -3
  223. package/server/src/Models/Issue.php +106 -7
  224. package/server/src/Models/Vehicle.php +1 -1
  225. package/server/src/Models/VehicleDevice.php +3 -1
  226. package/server/src/Models/VehicleDeviceEvent.php +7 -3
  227. package/server/src/Notifications/OrderAssigned.php +15 -0
  228. package/server/src/Notifications/OrderCanceled.php +15 -0
  229. package/server/src/Notifications/OrderDispatchFailed.php +15 -0
  230. package/server/src/Notifications/OrderDispatched.php +15 -0
  231. package/server/src/Notifications/OrderPing.php +15 -0
  232. package/server/src/Notifications/OrderSplit.php +26 -5
  233. package/server/src/Providers/FleetOpsServiceProvider.php +22 -0
  234. package/server/src/Providers/NotificationServiceProvider.php +43 -0
  235. package/server/src/routes.php +2 -2
@@ -16,11 +16,16 @@
16
16
  <div class="flex flex-row justify-between w-full">
17
17
  <div class="flex flex-col flex-1 w-3/4">
18
18
  <div class="flex flex-row">
19
- <div class="w-14 flex items-center justify-center">
20
- <Image src={{this.vehicle.photo_url}} @fallbackSrc={{config "defaultValues.vehicleImage"}} alt={{this.vehicle.name}} height="48" width="48" class="h-12 w-12" />
21
- <Attach::Tooltip @class="clean" @animation="scale" @placement={{"top"}}>
22
- <InputInfo @text={{this.vehicle.public_id}} />
23
- </Attach::Tooltip>
19
+ <div class="w-14">
20
+ <div class="upload-avatar-overlay w-12 h-12 flex items-center justify-start rounded-lg">
21
+ <img src={{this.vehicle.photo_url}} alt={{this.vehicle.name}} height="48" width="48" class="h-12 w-12 rounded-lg shadow-sm" />
22
+ <Attach::Tooltip @class="clean" @animation="scale" @placement="top">
23
+ <InputInfo @text="Upload new photo" />
24
+ </Attach::Tooltip>
25
+ <div class="upload-avatar-button-wrapper rounded-lg">
26
+ <UploadButton @name="photos" @accept="image/*" @onFileAdded={{this.onUploadNewPhoto}} @icon="upload" @hideButtonText={{true}} @labelClass="upload-avatar-label-overlay" class="w-12 btn-reset" />
27
+ </div>
28
+ </div>
24
29
  </div>
25
30
  <div class="flex flex-col">
26
31
  <h1 class="text-gray-900 dark:text-white text-2xl">
@@ -58,61 +63,47 @@
58
63
  <div class="flex-1 space-y-4">
59
64
  <ContentPanel @title="Details" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
60
65
  <div class="grid grid-cols-1 gap-4 lg:grid-cols-2 lg:gap-2">
61
- <div class="input-group mb-2">
62
- <label>
63
- Internal ID
64
- </label>
66
+ <InputGroup @name="Internal ID">
65
67
  <Input @value={{this.vehicle.internal_id}} @type="text" class="w-full form-input" placeholder="Internal ID" />
66
- </div>
68
+ </InputGroup>
67
69
 
68
- <div class="input-group mb-2">
69
- <label>
70
- Plate Number
71
- </label>
70
+ <InputGroup @name="Plate Number">
72
71
  <Input @value={{this.vehicle.plate_number}} @type="text" class="w-full form-input" placeholder="Plate Number" />
73
- </div>
72
+ </InputGroup>
74
73
 
75
- <div class="input-group mb-2">
76
- <label>
77
- VIN Number
78
- </label>
74
+ <InputGroup @name="VIN Number">
79
75
  <Input @value={{this.vehicle.vin}} @type="text" class="w-full form-input" placeholder="VIN Number" />
80
- </div>
76
+ </InputGroup>
81
77
 
82
- <div class="input-group mb-2">
83
- <label>
84
- Make
85
- </label>
78
+ <InputGroup @name="Make">
86
79
  <Input @value={{this.vehicle.make}} @type="text" class="w-full form-input" placeholder="Vehicle Make" />
87
- </div>
80
+ </InputGroup>
88
81
 
89
- <div class="input-group mb-2">
90
- <label>
91
- Model
92
- </label>
82
+ <InputGroup @name="Model">
93
83
  <Input @value={{this.vehicle.model}} @type="text" class="w-full form-input" placeholder="Vehicle Model" />
94
- </div>
84
+ </InputGroup>
95
85
 
96
- <div class="input-group mb-2">
97
- <label>
98
- Year
99
- </label>
86
+ <InputGroup @name="Year">
100
87
  <Input @value={{this.vehicle.year}} @type="text" class="w-full form-input" placeholder="Vehicle Year" />
101
- </div>
88
+ </InputGroup>
102
89
 
103
- <div class="input-group mb-2">
104
- <label>
105
- Driver Assigned
106
- </label>
107
- <ModelSelect @modelName="driver" @selectedModel={{this.vehicle.driver}} @placeholder="Select Driver" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut
108
- this.vehicle.driver)}} as |model|>
90
+ <InputGroup @name="Driver Assigned">
91
+ <ModelSelect @modelName="driver" @selectedModel={{this.vehicle.driver}} @placeholder="Select Driver" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut this.vehicle.driver)}} as |model|>
109
92
  {{model.name}}
110
93
  </ModelSelect>
111
- </div>
94
+ </InputGroup>
95
+
96
+ <InputGroup @name="Status">
97
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
98
+ <PowerSelect @options={{this.vehicleStatusOptions}} @selected={{this.vehicle.status}} @onChange={{fn (mut this.vehicle.status)}} @placeholder="Select vehicle status" @triggerClass="form-select form-input" as |status|>
99
+ {{smart-humanize status}}
100
+ </PowerSelect>
101
+ </div>
102
+ </InputGroup>
112
103
  </div>
113
104
  </ContentPanel>
114
105
 
115
- <ContentPanel @title="Avatar" @open={{false}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
106
+ <ContentPanel @title="Avatar" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
116
107
  <div class="grid grid-cols-1 gap-4 lg:grid-cols-2 lg:gap-2">
117
108
  <div class="input-group mb-2">
118
109
  <InputLabel @labelText="Select map avatar" @helpText="Select an avatar to be used for rendering on maps when using geolocation tracking features." />
@@ -121,7 +112,7 @@
121
112
  </FetchSelect>
122
113
  </div>
123
114
  <div>
124
- <img alt={{this.vehicle.public_id}} src={{this.vehicle.avatar_url}} class="w-24 h-24" />
115
+ <img alt={{this.vehicle.displayName}} src={{this.vehicle.avatar_url}} class="w-24 h-24" />
125
116
  </div>
126
117
  </div>
127
118
  </ContentPanel>
@@ -11,6 +11,16 @@ export default class VehicleFormPanelComponent extends Component {
11
11
  */
12
12
  @service store;
13
13
 
14
+ /**
15
+ * @service store
16
+ */
17
+ @service fetch;
18
+
19
+ /**
20
+ * @service currentUser
21
+ */
22
+ @service currentUser;
23
+
14
24
  /**
15
25
  * @service notifications
16
26
  */
@@ -43,6 +53,12 @@ export default class VehicleFormPanelComponent extends Component {
43
53
  */
44
54
  @tracked isLoading = false;
45
55
 
56
+ /**
57
+ * Status options for vehicles.
58
+ * @type {Array}
59
+ */
60
+ @tracked vehicleStatusOptions = ['active', 'pending'];
61
+
46
62
  /**
47
63
  * Constructs the component and applies initial state.
48
64
  */
@@ -97,6 +113,31 @@ export default class VehicleFormPanelComponent extends Component {
97
113
  }
98
114
  }
99
115
 
116
+ /**
117
+ * Uploads a new photo for the vehicle.
118
+ *
119
+ * @param {File} file
120
+ * @memberof DriverFormPanelComponent
121
+ */
122
+ @action onUploadNewPhoto(file) {
123
+ this.fetch.uploadFile.perform(
124
+ file,
125
+ {
126
+ path: `uploads/${this.currentUser.companyId}/vehicles/${this.vehicle.id}`,
127
+ subject_uuid: this.vehicle.id,
128
+ subject_type: 'vehicle',
129
+ type: 'vehicle_photo',
130
+ },
131
+ (uploadedFile) => {
132
+ this.vehicle.setProperties({
133
+ photo_uuid: uploadedFile.id,
134
+ photo_url: uploadedFile.url,
135
+ photo: uploadedFile,
136
+ });
137
+ }
138
+ );
139
+ }
140
+
100
141
  /**
101
142
  * View the details of the vehicle.
102
143
  *
@@ -1,6 +1,6 @@
1
- <div class="p-4">
1
+ <div class="p-4 space-y-4">
2
2
  <ContentPanel @title="Details" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-900">
3
- <div class="grid grid-cols-2 gap-2 text-xs md:mb-6 dark:text-gray-100">
3
+ <div class="grid grid-cols-2 gap-2 text-xs dark:text-gray-100">
4
4
  <div class="field-info-container">
5
5
  <div class="field-name">Name</div>
6
6
  <div class="field-value">{{n-a @vehicle.display_name}}</div>
@@ -31,4 +31,10 @@
31
31
  </div>
32
32
  </div>
33
33
  </ContentPanel>
34
+
35
+ <ContentPanel @title="Avatar" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
36
+ <div class="p-4">
37
+ <img alt={{@vehicle.displayName}} src={{@vehicle.avatar_url}} class="w-24 h-24" />
38
+ </div>
39
+ </ContentPanel>
34
40
  </div>
@@ -11,11 +11,13 @@
11
11
  <div class="flex flex-row justify-between w-full">
12
12
  <div class="flex flex-col flex-1 w-3/4">
13
13
  <div class="flex flex-row">
14
- <div class="w-14 flex items-center justify-center">
15
- <Image src={{this.vehicle.photo_url}} @fallbackSrc={{this.vehicle.avatar_url}} alt={{this.vehicle.name}} height="48" width="48" class="h-12 w-12" />
16
- <Attach::Tooltip @class="clean" @animation="scale" @placement={{"top"}}>
17
- <InputInfo @text={{this.vehicle.public_id}} />
18
- </Attach::Tooltip>
14
+ <div class="w-14">
15
+ <div class="w-12 h-12 flex items-center justify-start rounded-lg">
16
+ <Image src={{this.vehicle.photo_url}} @fallbackSrc={{config "defaultValues.vehicleImage"}} alt={{this.vehicle.name}} height="48" width="48" class="h-12 w-12 rounded-lg shadow-sm" />
17
+ <Attach::Tooltip @class="clean" @animation="scale" @placement="top">
18
+ <InputInfo @text={{this.vehicle.displayName}} />
19
+ </Attach::Tooltip>
20
+ </div>
19
21
  </div>
20
22
  <div class="flex flex-col">
21
23
  <h1 class="text-gray-900 dark:text-white text-2xl">{{this.vehicle.display_name}}</h1>
@@ -53,7 +55,7 @@
53
55
  </div>
54
56
  </div>
55
57
  <div class="tab-content tab-{{this.tab.slug}}">
56
- {{component this.tab.component vehicle=this.vehicle tabOptions=this.tab params=this.tab.componentParams}}
58
+ {{component this.tab.component vehicle=this.vehicle tabOptions=this.tab options=this.tab.componentParams}}
57
59
  </div>
58
60
  </Overlay::Body>
59
61
  </Overlay>
@@ -0,0 +1,114 @@
1
+ <div class="space-y-4">
2
+ <ContentPanel @title="Setup" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
3
+ <InputGroup @name="Select vendor type">
4
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
5
+ <PowerSelect @options={{this.vendorTypes}} @selected={{this.selectedVendorType}} @onChange={{this.onSelectVendorType}} @placeholder="Select vendor type" @triggerClass="form-select form-input" as |vendorType|>
6
+ {{vendorType.label}}
7
+ </PowerSelect>
8
+ </div>
9
+ </InputGroup>
10
+ {{#if (eq this.selectedVendorType.value "integrated-vendor")}}
11
+ <InputGroup @name="Choose integrated vendor provider">
12
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
13
+ <PowerSelect @options={{this.supportedIntegratedVendors}} @selected={{this.selectedIntegratedVendor}} @onChange={{this.onSelectIntegratedVendor}} @placeholder="Select integrated vendor provider" @triggerClass="form-select form-input" as |integratedVendor|>
14
+ <div class="flex flex-row items-center">
15
+ <Image src={{integratedVendor.logo}} alt={{integratedVendor.code}} class="w-4 h-4" width="16" height="16" />
16
+ <h3 class="text-sm ml-4 dark:text-white">{{integratedVendor.name}}</h3>
17
+ </div>
18
+ </PowerSelect>
19
+ </div>
20
+ </InputGroup>
21
+ {{/if}}
22
+ </ContentPanel>
23
+ {{#if this.selectedVendorType.value}}
24
+ {{#if (eq this.selectedVendorType.value "integrated-vendor")}}
25
+ {{#if this.selectedIntegratedVendor}}
26
+ <ContentPanel @title="Provider" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
27
+ <div class="flex flex-row items-center">
28
+ <img src={{this.selectedIntegratedVendor.logo}} alt={{this.selectedIntegratedVendor.code}} class="w-12 h-12" width="48" height="48" />
29
+ <h3 class="text-base text-black dark:text-white ml-4">{{this.selectedIntegratedVendor.name}}</h3>
30
+ </div>
31
+ </ContentPanel>
32
+ <ContentPanel @title="Credentials" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
33
+ {{#each this.selectedIntegratedVendor.credential_params as |param|}}
34
+ <InputGroup @name={{smart-humanize param.key}} @value={{mut (get this.integratedVendor.credentials param.key)}} @helpText={{concat "Optionally supply your own " (smart-humanize param.key) " to configure this vendor."}} />
35
+ {{/each}}
36
+ </ContentPanel>
37
+ <ContentPanel @title="Options" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
38
+ {{#each this.selectedIntegratedVendor.option_params as |param|}}
39
+ {{#if param.options}}
40
+ <InputGroup @name={{smart-humanize param.key}}>
41
+ <Select @value={{mut (get this.integratedVendor.options param.key)}} @options={{param.options}} @optionValue={{param.optionValue}} @optionLabel={{param.optionLabel}} @humanize={{true}} @placeholder={{concat "Select " (smart-humanize param.key)}} @onSelect={{fn (mut (get this.integratedVendor.options param.key))}} />
42
+ </InputGroup>
43
+ {{else}}
44
+ <InputGroup @name={{smart-humanize param.key}} @value={{mut (get this.integratedVendor.options param.key)}} @helpText={{concat "Optionally supply your own " (smart-humanize param.key) " to configure this vendor."}} />
45
+ {{/if}}
46
+ {{/each}}
47
+ <InputGroup>
48
+ <Checkbox @value={{this.integratedVendor.sandbox}} @label="Sandbox" @onToggle={{fn (mut this.integratedVendor.sandbox)}} @alignItems="center" @labelClass="mb-0i" />
49
+ </InputGroup>
50
+ </ContentPanel>
51
+ <ContentPanel @title="Advanced Options" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
52
+ <div>
53
+ <a href="javascript:;" class="text-blue-600 underline text-sm" {{on "click" this.toggleAdvancedOptions}}>{{if
54
+ this.showAdvancedOptions
55
+ "Hide Advanced Options"
56
+ "Show Advanced Options"
57
+ }}</a>
58
+ </div>
59
+ {{#if this.showAdvancedOptions}}
60
+ <div class="mt-4">
61
+ <InputGroup @name="Custom Host" @value={{this.integratedVendor.host}} @helpText="Optionally provide a custom host that should be used for this integration." />
62
+ <InputGroup @name="Custom Namespace" @value={{this.integratedVendor.namespace}} @helpText="Optionally provide a custom namespace or api version that should be used for the integration." />
63
+ <InputGroup @name="Webhook URL" @value={{this.integratedVendor.webhook_url}} @helpText="Integrated vendors will typically require this so that Fleetbase can receive activity updates on the order. Do not change unless you know what you are doing! Changing this may break your order updates!" />
64
+ </div>
65
+ {{/if}}
66
+ </ContentPanel>
67
+ {{else}}
68
+ <div class="flex items-center justify-center border-2 border-dashed h-32 w-full rounded-md dark:border-gray-700 border-gray-200">
69
+ <h3 class="text-gray-800 dark:text-gray-400 italic text-sm">Select an integrated vendor provider.</h3>
70
+ </div>
71
+ {{/if}}
72
+ {{else}}
73
+ <ContentPanel @title="Vendor Details" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
74
+ <InputGroup @name="Name" @value={{this.vendor.name}} @helpText="The vendor's name, typically the name of a business." />
75
+ <InputGroup @name="Email" @type="email" @value={{this.vendor.email}} @helpText="The vendor's email, this can be used to trigger emails to the vendor." />
76
+ <InputGroup @name="Phone" @type="tel" @value={{this.vendor.phone}} @helpText="The vendor's phone #, this can be used to trigger SMS or messages to the vendor." />
77
+ <InputGroup @name="Website" @value={{this.vendor.website}} @helpText="The vendor's website, optionally add the vendors website for reference." />
78
+ <InputGroup @name="Type">
79
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
80
+ <PowerSelect @options={{@vendorTypes}} @selected={{this.vendor.type}} @onChange={{fn (mut this.vendor.type)}} @placeholder="Select vendor type" @triggerClass="form-select form-input" as |type|>
81
+ {{smart-humanize type}}
82
+ </PowerSelect>
83
+ </div>
84
+ </InputGroup>
85
+ <InputGroup @name="Status">
86
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
87
+ <PowerSelect @options={{@vendorStatusOptions}} @selected={{this.vendor.status}} @onChange={{fn (mut this.vendor.status)}} @placeholder="Select vendor status" @triggerClass="form-select form-input" as |status|>
88
+ {{smart-humanize status}}
89
+ </PowerSelect>
90
+ </div>
91
+ </InputGroup>
92
+ <InputGroup @wrapperClass="col-span-2">
93
+ <div class="flex items-center justify-between">
94
+ <label>
95
+ Address
96
+ </label>
97
+ <div class="mb-1.5 flex flex-row">
98
+ <Button @type="default" @size="xs" @icon="edit" @text={{if this.vendor.has_place "Edit" "New Address"}} @onClick={{this.editAddress}} />
99
+ </div>
100
+ </div>
101
+ <ModelSelect @modelName="place" @selectedModel={{this.vendor.place}} @placeholder="Select Address" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{this.selectVendorAddress}} as |model|>
102
+ <div class="flex items-center flex-row justify-between">
103
+ <div class="truncate flex-1">{{n-a model.address}}</div>
104
+ <Badge @hideStatusDot={{true}} @status="info">{{model.public_id}}</Badge>
105
+ </div>
106
+ </ModelSelect>
107
+ </InputGroup>
108
+ <InputGroup @name="Country">
109
+ <CountrySelect class="w-full form-input form-select form-datalist" @value={{this.vendor.country}} @onChange={{fn (mut this.vendor.country)}} placeholder="Country" />
110
+ </InputGroup>
111
+ </ContentPanel>
112
+ {{/if}}
113
+ {{/if}}
114
+ </div>
@@ -0,0 +1,158 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { isArray } from '@ember/array';
6
+ import apiUrl from '@fleetbase/ember-core/utils/api-url';
7
+ import contextComponentCallback from '../../utils/context-component-callback';
8
+
9
+ export default class VendorFormPanelCreateFormComponent extends Component {
10
+ /**
11
+ * @service store
12
+ */
13
+ @service store;
14
+
15
+ /**
16
+ * @service fetch
17
+ */
18
+ @service fetch;
19
+
20
+ /**
21
+ * @service contextPanel
22
+ */
23
+ @service contextPanel;
24
+ /**
25
+ * State of whether editing credentials is enabled.
26
+ * @type {Boolean}
27
+ */
28
+ @tracked isEditingCredentials = false;
29
+
30
+ /**
31
+ * State of whether to show advanced options for integrated vendor.
32
+ * @type {Boolean}
33
+ */
34
+ @tracked showAdvancedOptions = false;
35
+
36
+ /**
37
+ * The selectable types of vendors.
38
+ * @type {Array}
39
+ */
40
+ @tracked vendorTypes = [
41
+ { label: 'Choose a integrated vendor', value: 'integrated-vendor' },
42
+ { label: 'Create a custom vendor', value: 'vendor' },
43
+ ];
44
+
45
+ /**
46
+ * The selected type of vendor being created or edited.
47
+ * @type {String}
48
+ */
49
+ @tracked selectedVendorType = this.vendorTypes[1];
50
+
51
+ /**
52
+ * The supported integrated vendors.
53
+ * @type {Array}
54
+ */
55
+ @tracked supportedIntegratedVendors = [];
56
+
57
+ /**
58
+ * The selected integrated vendor provider.
59
+ * @type {Object}
60
+ */
61
+ @tracked selectedIntegratedVendor;
62
+
63
+ constructor() {
64
+ super(...arguments);
65
+ this.vendor = this.args.vendor;
66
+ this.fetchSupportedIntegratedVendors();
67
+ }
68
+
69
+ @action toggleCredentialsReset() {
70
+ if (this.isEditingCredentials) {
71
+ this.isEditingCredentials = false;
72
+ } else {
73
+ this.isEditingCredentials = true;
74
+ }
75
+ }
76
+
77
+ @action toggleAdvancedOptions() {
78
+ if (this.showAdvancedOptions) {
79
+ this.showAdvancedOptions = false;
80
+ } else {
81
+ this.showAdvancedOptions = true;
82
+ }
83
+ }
84
+
85
+ @action onSelectVendorType(selectedVendorType) {
86
+ this.selectedVendorType = selectedVendorType;
87
+ }
88
+
89
+ @action onSelectIntegratedVendor(integratedVendor) {
90
+ this.selectedIntegratedVendor = integratedVendor;
91
+ const { credential_params, option_params } = integratedVendor;
92
+
93
+ // create credentials object
94
+ const credentials = {};
95
+ if (isArray(integratedVendor.credential_params)) {
96
+ for (let i = 0; i < integratedVendor.credential_params.length; i++) {
97
+ const param = integratedVendor.credential_params.objectAt(i);
98
+ credentials[param] = null;
99
+ }
100
+ }
101
+
102
+ // create options object
103
+ const options = {};
104
+ if (isArray(integratedVendor.option_params)) {
105
+ for (let i = 0; i < integratedVendor.option_params.length; i++) {
106
+ const param = integratedVendor.option_params.objectAt(i);
107
+ options[param.key] = null;
108
+ }
109
+ }
110
+
111
+ const vendor = this.store.createRecord('integrated-vendor', {
112
+ provider: integratedVendor.code,
113
+ webhook_url: apiUrl(`listeners/${integratedVendor.code}`),
114
+ credentials: {},
115
+ options: {},
116
+ credential_params,
117
+ option_params,
118
+ });
119
+
120
+ this.vendor = vendor;
121
+
122
+ // trigger callback
123
+ contextComponentCallback(this, 'onVendorChanged', vendor);
124
+ }
125
+
126
+ @action selectVendorAddress(place) {
127
+ this.vendor.place = place;
128
+ this.vendor.place_uuid = place.id;
129
+ }
130
+
131
+ @action async editAddress() {
132
+ let place;
133
+
134
+ if (this.vendor.has_place) {
135
+ place = await this.vendor.place;
136
+ } else {
137
+ place = this.store.createRecord('place');
138
+ }
139
+
140
+ return this.contextPanel.focus(place, 'editing', {
141
+ onAfterSave: (place) => {
142
+ this.vendor.place = place;
143
+ this.contextPanel.clear();
144
+ },
145
+ });
146
+ }
147
+
148
+ /**
149
+ * Fetches the supported integrated vendors.
150
+ *
151
+ * @returns {Promise}
152
+ */
153
+ fetchSupportedIntegratedVendors() {
154
+ return this.fetch.get('integrated-vendors/supported').then((supportedIntegratedVendors) => {
155
+ this.supportedIntegratedVendors = supportedIntegratedVendors;
156
+ });
157
+ }
158
+ }
@@ -0,0 +1,98 @@
1
+ <div class="space-y-4">
2
+ {{#if this.isIntegratedVendor}}
3
+ <ContentPanel @title="Provider" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
4
+ <div class="flex flex-row items-center">
5
+ <img src={{this.vendor.provider_settings.logo}} alt={{this.vendor.provider_settings.code}} class="w-12 h-12" width="48" height="48" />
6
+ <h3 class="text-base text-black dark:text-white ml-4">{{this.vendor.provider_settings.name}}</h3>
7
+ </div>
8
+ </ContentPanel>
9
+ <ContentPanel @title="Credentials" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
10
+ {{#if this.isEditingCredentials}}
11
+ {{#each this.vendor.provider_settings.credential_params as |param|}}
12
+ <InputGroup @name={{smart-humanize param.key}} @value={{mut (get this.vendor.credentials param.key)}} @helpText={{concat "Optionally supply your own " (smart-humanize param.key) " to configure this vendor."}} />
13
+ {{/each}}
14
+ <div class="mt-4">
15
+ <a href="javascript:;" class="text-red-600 underline text-sm" {{on "click" this.toggleCredentialsReset}}>Cancel credentials reset</a>
16
+ </div>
17
+ {{else}}
18
+ <div class="rounded-md border shadow-sm border-gray-200 text-black bg-white dark:border-gray-700 dark:bg-gray-900 dark:text-white text-xs px-3 py-2 mb-4 mt-2">
19
+ <p class="mb-2">Sensitive credentials can only be reset, to update credentials you must re-enter the credentials.</p>
20
+ <a href="javascript:;" class="text-red-600 underline text-sm" {{on "click" this.toggleCredentialsReset}}>Click here to reset credentials</a>
21
+ </div>
22
+ <div>
23
+ {{#each this.vendor.provider_settings.credential_params as |param|}}
24
+ <InputGroup @name={{smart-humanize param.key}} @value="*********" @disabled="true" @helpText={{concat "Optionally supply your own " (smart-humanize param.key) " to configure this vendor."}} />
25
+ {{/each}}
26
+ </div>
27
+ {{/if}}
28
+ </ContentPanel>
29
+ <ContentPanel @title="Options" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
30
+ {{#each this.vendor.provider_settings.option_params as |param|}}
31
+ {{#if param.options}}
32
+ <InputGroup @name={{smart-humanize param.key}}>
33
+ <Select @value={{mut (get this.vendor.options param.key)}} @options={{param.options}} @optionValue={{param.optionValue}} @optionLabel={{param.optionLabel}} @humanize={{true}} @placeholder={{concat "Select " (smart-humanize param.key)}} @onSelect={{fn (mut (get this.vendor.options param.key))}} />
34
+ </InputGroup>
35
+ {{else}}
36
+ <InputGroup @name={{smart-humanize param.key}} @value={{mut (get this.vendor.options param.key)}} @helpText={{concat "Optionally supply your own " (smart-humanize param.key) " to configure this vendor."}} />
37
+ {{/if}}
38
+ {{/each}}
39
+ <InputGroup>
40
+ <Checkbox @value={{this.vendor.sandbox}} @label="Sandbox" @onToggle={{fn (mut this.vendor.sandbox)}} @alignItems="center" @labelClass="mb-0i" />
41
+ </InputGroup>
42
+ </ContentPanel>
43
+ <ContentPanel @title="Advanced Options" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
44
+ <div>
45
+ <a href="javascript:;" class="text-blue-600 underline text-sm" {{on "click" this.toggleAdvancedOptions}}>{{if
46
+ this.showAdvancedOptions
47
+ "Hide Advanced Options"
48
+ "Show Advanced Options"
49
+ }}</a>
50
+ </div>
51
+ {{#if this.showAdvancedOptions}}
52
+ <div class="mt-4">
53
+ <InputGroup @name="Custom Host" @value={{this.vendor.host}} @helpText="Optionally provide a custom host that should be used for this integration." />
54
+ <InputGroup @name="Custom Namespace" @value={{this.vendor.namespace}} @helpText="Optionally provide a custom namespace or api version that should be used for the integration." />
55
+ <InputGroup @name="Webhook URL" @value={{this.vendor.webhook_url}} @helpText="Integrated vendors will typically require this so that Fleetbase can receive activity updates on the order. Do not change unless you know what you are doing! Changing this may break your order updates!" />
56
+ </div>
57
+ {{/if}}
58
+ </ContentPanel>
59
+ {{else}}
60
+ <InputGroup @name="Name" @value={{this.vendor.name}} @helpText="The vendor's name, typically the name of a business." />
61
+ <InputGroup @name="Email" @type="email" @value={{this.vendor.email}} @helpText="The vendor's email, this can be used to trigger emails to the vendor." />
62
+ <InputGroup @name="Phone" @type="tel" @value={{this.vendor.phone}} @helpText="The vendor's phone #, this can be used to trigger SMS or messages to the vendor." />
63
+ <InputGroup @name="Website" @value={{this.vendor.website}} @helpText="The vendor's website, optionally add the vendors website for reference." />
64
+ <InputGroup @name="Type">
65
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
66
+ <PowerSelect @options={{@vendorTypes}} @selected={{this.vendor.type}} @onChange={{fn (mut this.vendor.type)}} @placeholder="Select vendor type" @triggerClass="form-select form-input" as |type|>
67
+ {{smart-humanize type}}
68
+ </PowerSelect>
69
+ </div>
70
+ </InputGroup>
71
+ <InputGroup @name="Status">
72
+ <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
73
+ <PowerSelect @options={{@vendorStatusOptions}} @selected={{this.vendor.status}} @onChange={{fn (mut this.vendor.status)}} @placeholder="Select vendor status" @triggerClass="form-select form-input" as |status|>
74
+ {{smart-humanize status}}
75
+ </PowerSelect>
76
+ </div>
77
+ </InputGroup>
78
+ <InputGroup @wrapperClass="col-span-2">
79
+ <div class="flex items-center justify-between">
80
+ <label>
81
+ Address
82
+ </label>
83
+ <div class="mb-1.5 flex flex-row">
84
+ <Button @type="default" @size="xs" @icon="edit" @text={{if this.vendor.has_place "Edit" "New Address"}} @onClick={{this.editAddress}} />
85
+ </div>
86
+ </div>
87
+ <ModelSelect @modelName="place" @selectedModel={{this.vendor.place}} @placeholder="Select Address" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{this.selectVendorAddress}} as |model|>
88
+ <div class="flex items-center flex-row justify-between">
89
+ <div class="truncate flex-1">{{n-a model.address}}</div>
90
+ <Badge @hideStatusDot={{true}} @status="info">{{model.public_id}}</Badge>
91
+ </div>
92
+ </ModelSelect>
93
+ </InputGroup>
94
+ <InputGroup @name="Country">
95
+ <CountrySelect class="w-full form-input form-select form-datalist" @value={{this.vendor.country}} @onChange={{fn (mut this.vendor.country)}} placeholder="Country" />
96
+ </InputGroup>
97
+ {{/if}}
98
+ </div>