@fleetbase/fleetops-engine 0.6.19 → 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 (130) 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/kanban.hbs +12 -10
  20. package/addon/components/order/kanban.js +27 -3
  21. package/addon/components/order-config-manager/custom-fields.js +1 -1
  22. package/addon/components/positions-replay.hbs +333 -0
  23. package/addon/components/positions-replay.js +372 -0
  24. package/addon/components/sensor/details.hbs +64 -38
  25. package/addon/components/sensor/form.hbs +112 -63
  26. package/addon/components/sensor/form.js +36 -24
  27. package/addon/components/sensor/panel-header.hbs +32 -0
  28. package/addon/components/sensor/panel-header.js +3 -0
  29. package/addon/components/telematic/details.hbs +40 -16
  30. package/addon/components/telematic/form.hbs +63 -64
  31. package/addon/components/telematic/form.js +73 -4
  32. package/addon/components/vehicle/card.hbs +1 -1
  33. package/addon/controllers/analytics/reports/index/edit.js +1 -1
  34. package/addon/controllers/connectivity/devices/index/details.js +22 -1
  35. package/addon/controllers/connectivity/devices/index/edit.js +66 -1
  36. package/addon/controllers/connectivity/devices/index.js +51 -9
  37. package/addon/controllers/connectivity/events/index.js +65 -16
  38. package/addon/controllers/connectivity/sensors/index/details.js +22 -1
  39. package/addon/controllers/connectivity/sensors/index/edit.js +66 -1
  40. package/addon/controllers/connectivity/sensors/index.js +66 -6
  41. package/addon/controllers/connectivity/telematics/index/details.js +22 -1
  42. package/addon/controllers/connectivity/telematics/index/edit.js +66 -1
  43. package/addon/controllers/connectivity/telematics/index.js +20 -11
  44. package/addon/controllers/management/fleets/index/details.js +26 -21
  45. package/addon/controllers/management/fleets/index/edit.js +9 -6
  46. package/addon/controllers/management/vehicles/index/details.js +21 -13
  47. package/addon/controllers/operations/orders/index/new.js +4 -2
  48. package/addon/controllers/operations/orders/index.js +50 -45
  49. package/addon/controllers/settings/custom-fields.js +6 -0
  50. package/addon/helpers/get-fleet-ops-option-label.js +11 -0
  51. package/addon/routes/connectivity/devices/index/details.js +27 -1
  52. package/addon/routes/connectivity/devices/index/edit.js +27 -1
  53. package/addon/routes/connectivity/sensors/index/details.js +27 -1
  54. package/addon/routes/connectivity/sensors/index/edit.js +27 -1
  55. package/addon/routes/connectivity/telematics/index/details.js +27 -1
  56. package/addon/routes/connectivity/telematics/index/edit.js +27 -1
  57. package/addon/routes/management/vehicles/index/details/positions.js +3 -0
  58. package/addon/routes/operations/orders/index.js +0 -3
  59. package/addon/routes.js +1 -0
  60. package/addon/services/movement-tracker.js +81 -30
  61. package/addon/services/order-creation.js +4 -8
  62. package/addon/services/order-validation.js +3 -3
  63. package/addon/styles/fleetops-engine.css +192 -0
  64. package/addon/templates/connectivity/devices/index/details/index.hbs +2 -2
  65. package/addon/templates/connectivity/devices/index/details.hbs +15 -2
  66. package/addon/templates/connectivity/devices/index/edit.hbs +1 -1
  67. package/addon/templates/connectivity/events/index.hbs +1 -1
  68. package/addon/templates/connectivity/sensors/index/details/index.hbs +2 -2
  69. package/addon/templates/connectivity/sensors/index/details.hbs +15 -2
  70. package/addon/templates/connectivity/sensors/index/edit.hbs +1 -1
  71. package/addon/templates/connectivity/telematics/index/details/index.hbs +2 -2
  72. package/addon/templates/connectivity/telematics/index/details.hbs +14 -2
  73. package/addon/templates/connectivity/telematics/index/edit.hbs +1 -1
  74. package/addon/templates/management/vehicles/index/details/positions.hbs +1 -0
  75. package/addon/templates/operations/orders/index.hbs +26 -2
  76. package/addon/utils/fleet-ops-options.js +95 -0
  77. package/addon/utils/setup-customer-portal.js +7 -0
  78. package/app/components/device/panel-header.js +1 -0
  79. package/app/components/map/drawer/device-event-listing.js +1 -0
  80. package/app/components/map/drawer/position-listing.js +1 -0
  81. package/app/components/positions-replay.js +1 -0
  82. package/app/components/sensor/panel-header.js +1 -0
  83. package/app/helpers/get-fleet-ops-option-label.js +1 -0
  84. package/app/routes/management/vehicles/index/details/positions.js +1 -0
  85. package/app/templates/management/vehicles/index/details/positions.js +1 -0
  86. package/composer.json +1 -1
  87. package/extension.json +1 -1
  88. package/package.json +4 -4
  89. package/server/config/telematics.php +111 -0
  90. package/server/migrations/2025_10_27_000001_add_telematics_integration_fields.php +70 -0
  91. package/server/migrations/2025_10_27_171322_fix_device_column_names.php +107 -0
  92. package/server/migrations/2025_10_27_203023_add_company_uuid_to_device_events_table.php +28 -0
  93. package/server/src/Console/Commands/ReplayVehicleLocations.php +225 -0
  94. package/server/src/Contracts/TelematicProviderDescriptor.php +72 -0
  95. package/server/src/Contracts/TelematicProviderInterface.php +119 -0
  96. package/server/src/Exceptions/TelematicProviderException.php +14 -0
  97. package/server/src/Exceptions/TelematicRateLimitExceededException.php +12 -0
  98. package/server/src/Http/Controllers/Api/v1/DriverController.php +24 -14
  99. package/server/src/Http/Controllers/Api/v1/VehicleController.php +27 -7
  100. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +22 -0
  101. package/server/src/Http/Controllers/Internal/v1/OrderController.php +50 -68
  102. package/server/src/Http/Controllers/Internal/v1/PositionController.php +240 -0
  103. package/server/src/Http/Controllers/Internal/v1/SensorController.php +11 -0
  104. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +141 -0
  105. package/server/src/Http/Controllers/Internal/v1/TelematicWebhookController.php +170 -0
  106. package/server/src/Http/Filter/DeviceEventFilter.php +68 -0
  107. package/server/src/Http/Filter/PositionFilter.php +35 -0
  108. package/server/src/Http/Resources/v1/Position.php +44 -0
  109. package/server/src/Jobs/ReplayPositions.php +64 -0
  110. package/server/src/Jobs/SendPositionReplay.php +65 -0
  111. package/server/src/Jobs/SyncTelematicDevicesJob.php +106 -0
  112. package/server/src/Jobs/TestTelematicConnectionJob.php +102 -0
  113. package/server/src/Models/Device.php +72 -10
  114. package/server/src/Models/DeviceEvent.php +7 -0
  115. package/server/src/Models/Driver.php +28 -1
  116. package/server/src/Models/Payload.php +11 -3
  117. package/server/src/Models/Place.php +9 -2
  118. package/server/src/Models/Position.php +17 -17
  119. package/server/src/Models/Sensor.php +78 -13
  120. package/server/src/Models/Telematic.php +116 -6
  121. package/server/src/Models/Vehicle.php +104 -1
  122. package/server/src/Providers/FleetOpsServiceProvider.php +2 -0
  123. package/server/src/Support/Telematics/Providers/AbstractProvider.php +151 -0
  124. package/server/src/Support/Telematics/Providers/FlespiProvider.php +182 -0
  125. package/server/src/Support/Telematics/Providers/GeotabProvider.php +181 -0
  126. package/server/src/Support/Telematics/Providers/SamsaraProvider.php +177 -0
  127. package/server/src/Support/Telematics/TelematicProviderRegistry.php +147 -0
  128. package/server/src/Support/Telematics/TelematicService.php +223 -0
  129. package/server/src/Support/Utils.php +1 -1
  130. package/server/src/routes.php +12 -1
@@ -22,7 +22,7 @@ export default class AnalyticsReportsIndexEditController extends Controller {
22
22
  yield report.validate();
23
23
 
24
24
  try {
25
- const result = yield report.executeQuery();
25
+ const result = yield report.execute();
26
26
  report.fillResult(result);
27
27
 
28
28
  yield report.save();
@@ -1,3 +1,24 @@
1
1
  import Controller from '@ember/controller';
2
+ import { inject as service } from '@ember/service';
2
3
 
3
- export default class ConnectivityDevicesIndexDetailsController extends Controller {}
4
+ export default class ConnectivityDevicesIndexDetailsController extends Controller {
5
+ @service hostRouter;
6
+
7
+ get tabs() {
8
+ return [
9
+ {
10
+ route: 'connectivity.devices.index.details.index',
11
+ label: 'Overview',
12
+ },
13
+ ];
14
+ }
15
+
16
+ get actionButtons() {
17
+ return [
18
+ {
19
+ icon: 'pencil',
20
+ fn: () => this.hostRouter.transitionTo('console.fleet-ops.connectivity.devices.index.edit', this.model),
21
+ },
22
+ ];
23
+ }
24
+ }
@@ -1,3 +1,68 @@
1
1
  import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { task } from 'ember-concurrency';
2
6
 
3
- export default class ConnectivityDevicesIndexEditController extends Controller {}
7
+ export default class ConnectivityDevicesIndexEditController extends Controller {
8
+ @service hostRouter;
9
+ @service intl;
10
+ @service notifications;
11
+ @service modalsManager;
12
+ @tracked overlay;
13
+
14
+ get actionButtons() {
15
+ return [
16
+ {
17
+ icon: 'eye',
18
+ fn: this.view,
19
+ },
20
+ ];
21
+ }
22
+
23
+ @task *save(device) {
24
+ try {
25
+ yield device.save();
26
+ this.overlay?.close();
27
+
28
+ yield this.hostRouter.transitionTo('console.fleet-ops.connectivity.devices.index.details', device);
29
+ this.notifications.success(
30
+ this.intl.t('common.resource-updated-success', {
31
+ resource: this.intl.t('resource.device'),
32
+ resourceName: device.name ?? device.serial_number,
33
+ })
34
+ );
35
+ } catch (err) {
36
+ this.notifications.serverError(err);
37
+ }
38
+ }
39
+
40
+ @action cancel() {
41
+ if (this.model.hasDirtyAttributes) {
42
+ return this.#confirmContinueWithUnsavedChanges(this.model);
43
+ }
44
+
45
+ return this.hostRouter.transitionTo('console.fleet-ops.connectivity.devices.index');
46
+ }
47
+
48
+ @action view() {
49
+ if (this.model.hasDirtyAttributes) {
50
+ return this.#confirmContinueWithUnsavedChanges(this.model);
51
+ }
52
+
53
+ return this.hostRouter.transitionTo('console.fleet-ops.connectivity.devices.index.details', this.model);
54
+ }
55
+
56
+ #confirmContinueWithUnsavedChanges(device, options = {}) {
57
+ return this.modalsManager.confirm({
58
+ title: this.intl.t('common.continue-without-saving'),
59
+ body: this.intl.t('common.continue-without-saving-prompt', { resource: this.intl.t('resource.device') }),
60
+ acceptButtonText: this.intl.t('common.continue'),
61
+ confirm: async () => {
62
+ device.rollbackAttributes();
63
+ await this.hostRouter.transitionTo('console.fleet-ops.connectivity.devices.index.details', device);
64
+ },
65
+ ...options,
66
+ });
67
+ }
68
+ }
@@ -1,9 +1,11 @@
1
1
  import Controller from '@ember/controller';
2
2
  import { inject as service } from '@ember/service';
3
3
  import { tracked } from '@glimmer/tracking';
4
+ import fleetOpsOptions from '../../../utils/fleet-ops-options';
4
5
 
5
6
  export default class ConnectivityDevicesIndexController extends Controller {
6
7
  @service deviceActions;
8
+ @service telematicActions;
7
9
  @service intl;
8
10
 
9
11
  /** query params */
@@ -55,24 +57,64 @@ export default class ConnectivityDevicesIndexController extends Controller {
55
57
  @tracked columns = [
56
58
  {
57
59
  label: this.intl.t('column.name'),
58
- valuePath: 'name',
59
- width: '180px',
60
+ valuePath: 'displayName',
60
61
  cellComponent: 'table/cell/anchor',
61
- cellClassNames: 'uppercase',
62
62
  action: this.deviceActions.transition.view,
63
63
  permission: 'fleet-ops view device',
64
- hidden: true,
65
64
  resizable: true,
66
65
  sortable: true,
67
66
  filterable: true,
68
67
  filterParam: 'name',
69
68
  filterComponent: 'filter/string',
70
69
  },
70
+ {
71
+ label: 'Telematic',
72
+ valuePath: 'telematic.provider',
73
+ cellComponent: 'table/cell/anchor',
74
+ action: this.telematicActions.transition.view,
75
+ permission: 'fleet-ops view telematic',
76
+ resizable: true,
77
+ sortable: true,
78
+ filterable: true,
79
+ filterComponent: 'filter/model',
80
+ filterComponentPlaceholder: 'Select telematic',
81
+ filterParam: 'telematic',
82
+ model: 'telematic',
83
+ },
84
+ {
85
+ label: 'Type',
86
+ valuePath: 'type',
87
+ resizable: true,
88
+ sortable: true,
89
+ filterable: true,
90
+ filterParam: 'type',
91
+ filterComponent: 'filter/multi-option',
92
+ filterOptions: fleetOpsOptions('deviceTypes'),
93
+ },
94
+ {
95
+ label: 'Serial Number',
96
+ valuePath: 'serial_number',
97
+ resizable: true,
98
+ sortable: true,
99
+ filterable: true,
100
+ filterParam: 'serial_number',
101
+ filterComponent: 'filter/string',
102
+ },
103
+ {
104
+ label: this.intl.t('column.status'),
105
+ valuePath: 'status',
106
+ cellComponent: 'table/cell/status',
107
+ width: '10%',
108
+ resizable: true,
109
+ sortable: true,
110
+ filterable: true,
111
+ filterComponent: 'filter/multi-option',
112
+ filterOptions: fleetOpsOptions('deviceStatuses'),
113
+ },
71
114
  {
72
115
  label: this.intl.t('column.created-at'),
73
116
  valuePath: 'createdAt',
74
117
  sortParam: 'created_at',
75
- width: '10%',
76
118
  resizable: true,
77
119
  sortable: true,
78
120
  filterable: true,
@@ -96,18 +138,18 @@ export default class ConnectivityDevicesIndexController extends Controller {
96
138
  ddButtonText: false,
97
139
  ddButtonIcon: 'ellipsis-h',
98
140
  ddButtonIconPrefix: 'fas',
99
- ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.Device') }),
141
+ ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.device') }),
100
142
  cellClassNames: 'overflow-visible',
101
143
  wrapperClass: 'flex items-center justify-end mx-2',
102
144
  width: '10%',
103
145
  actions: [
104
146
  {
105
- label: this.intl.t('column.view-details'),
147
+ label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.device') }),
106
148
  fn: this.deviceActions.transition.view,
107
149
  permission: 'fleet-ops view device',
108
150
  },
109
151
  {
110
- label: this.intl.t('column.edit-place'),
152
+ label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.device') }),
111
153
  fn: this.deviceActions.transition.edit,
112
154
  permission: 'fleet-ops update device',
113
155
  },
@@ -115,7 +157,7 @@ export default class ConnectivityDevicesIndexController extends Controller {
115
157
  separator: true,
116
158
  },
117
159
  {
118
- label: this.intl.t('column.delete'),
160
+ label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.device') }),
119
161
  fn: this.deviceActions.delete,
120
162
  permission: 'fleet-ops delete device',
121
163
  },
@@ -4,6 +4,7 @@ import { tracked } from '@glimmer/tracking';
4
4
 
5
5
  export default class ConnectivityEventsIndexController extends Controller {
6
6
  @service deviceEventActions;
7
+ @service deviceActions;
7
8
  @service intl;
8
9
 
9
10
  /** query params */
@@ -29,14 +30,12 @@ export default class ConnectivityEventsIndexController extends Controller {
29
30
  /** columns */
30
31
  @tracked columns = [
31
32
  {
32
- label: this.intl.t('column.name'),
33
- valuePath: 'name',
34
- width: '180px',
33
+ label: 'Event',
34
+ valuePath: 'event_type',
35
35
  cellComponent: 'table/cell/anchor',
36
36
  cellClassNames: 'uppercase',
37
37
  action: this.deviceEventActions.transition.view,
38
38
  permission: 'fleet-ops view device-event',
39
- hidden: true,
40
39
  resizable: true,
41
40
  sortable: true,
42
41
  filterable: true,
@@ -44,40 +43,90 @@ export default class ConnectivityEventsIndexController extends Controller {
44
43
  filterComponent: 'filter/string',
45
44
  },
46
45
  {
47
- label: this.intl.t('column.created-at'),
48
- valuePath: 'createdAt',
49
- sortParam: 'created_at',
50
- width: '10%',
46
+ label: 'Device',
47
+ valuePath: 'device.displayName',
48
+ cellComponent: 'table/cell/anchor',
49
+ action: this.deviceActions.transition.view,
50
+ permission: 'fleet-ops view device',
51
51
  resizable: true,
52
52
  sortable: true,
53
53
  filterable: true,
54
- filterComponent: 'filter/date',
54
+ filterComponent: 'filter/model',
55
+ filterComponentPlaceholder: 'Select device',
56
+ filterParam: 'device',
57
+ model: 'device',
55
58
  },
56
59
  {
57
- label: this.intl.t('column.updated-at'),
58
- valuePath: 'updatedAt',
59
- sortParam: 'updated_at',
60
- width: '10%',
60
+ label: 'Provider',
61
+ valuePath: 'provider',
61
62
  resizable: true,
62
63
  sortable: true,
64
+ filterable: true,
65
+ filterParam: 'provider',
66
+ filterComponent: 'filter/string',
67
+ },
68
+ {
69
+ label: 'Severity',
70
+ valuePath: 'severity',
71
+ resizable: true,
72
+ sortable: true,
73
+ filterable: true,
74
+ filterParam: 'severity',
75
+ filterComponent: 'filter/string',
76
+ },
77
+ {
78
+ label: 'IDENT',
79
+ valuePath: 'ident',
80
+ hidden: true,
81
+ resizable: true,
82
+ sortable: true,
83
+ },
84
+ {
85
+ label: 'Protocol',
86
+ valuePath: 'protocol',
63
87
  hidden: true,
88
+ resizable: true,
89
+ sortable: true,
90
+ },
91
+ {
92
+ label: 'State',
93
+ valuePath: 'state',
94
+ hidden: true,
95
+ resizable: true,
96
+ sortable: true,
97
+ },
98
+ {
99
+ label: 'Code',
100
+ valuePath: 'code',
101
+ resizable: true,
102
+ sortable: true,
103
+ filterable: true,
104
+ filterParam: 'code',
105
+ filterComponent: 'filter/string',
106
+ },
107
+ {
108
+ label: this.intl.t('column.created-at'),
109
+ valuePath: 'createdAt',
110
+ sortParam: 'created_at',
111
+ width: '10%',
112
+ resizable: true,
113
+ sortable: true,
64
114
  filterable: true,
65
115
  filterComponent: 'filter/date',
66
116
  },
67
-
68
117
  {
69
118
  label: '',
70
119
  cellComponent: 'table/cell/dropdown',
71
120
  ddButtonText: false,
72
121
  ddButtonIcon: 'ellipsis-h',
73
122
  ddButtonIconPrefix: 'fas',
74
- ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.Device Event') }),
123
+ ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.device-event') }),
75
124
  cellClassNames: 'overflow-visible',
76
125
  wrapperClass: 'flex items-center justify-end mx-2',
77
126
  width: '10%',
78
127
  actions: [
79
128
  {
80
- label: this.intl.t('column.view-details'),
129
+ label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.device-event') }),
81
130
  fn: this.deviceEventActions.transition.view,
82
131
  permission: 'fleet-ops view device-event',
83
132
  },
@@ -1,3 +1,24 @@
1
1
  import Controller from '@ember/controller';
2
+ import { inject as service } from '@ember/service';
2
3
 
3
- export default class ConnectivitySensorsIndexDetailsController extends Controller {}
4
+ export default class ConnectivitySensorsIndexDetailsController extends Controller {
5
+ @service hostRouter;
6
+
7
+ get tabs() {
8
+ return [
9
+ {
10
+ route: 'connectivity.sensors.index.details.index',
11
+ label: 'Overview',
12
+ },
13
+ ];
14
+ }
15
+
16
+ get actionButtons() {
17
+ return [
18
+ {
19
+ icon: 'pencil',
20
+ fn: () => this.hostRouter.transitionTo('console.fleet-ops.connectivity.sensors.index.edit', this.model),
21
+ },
22
+ ];
23
+ }
24
+ }
@@ -1,3 +1,68 @@
1
1
  import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { task } from 'ember-concurrency';
2
6
 
3
- export default class ConnectivitySensorsIndexEditController extends Controller {}
7
+ export default class ConnectivitySensorsIndexEditController extends Controller {
8
+ @service hostRouter;
9
+ @service intl;
10
+ @service notifications;
11
+ @service modalsManager;
12
+ @tracked overlay;
13
+
14
+ get actionButtons() {
15
+ return [
16
+ {
17
+ icon: 'eye',
18
+ fn: this.view,
19
+ },
20
+ ];
21
+ }
22
+
23
+ @task *save(sensor) {
24
+ try {
25
+ yield sensor.save();
26
+ this.overlay?.close();
27
+
28
+ yield this.hostRouter.transitionTo('console.fleet-ops.connectivity.sensors.index.details', sensor);
29
+ this.notifications.success(
30
+ this.intl.t('common.resource-updated-success', {
31
+ resource: this.intl.t('resource.sensor'),
32
+ resourceName: sensor.name ?? sensor.serial_number,
33
+ })
34
+ );
35
+ } catch (err) {
36
+ this.notifications.serverError(err);
37
+ }
38
+ }
39
+
40
+ @action cancel() {
41
+ if (this.model.hasDirtyAttributes) {
42
+ return this.#confirmContinueWithUnsavedChanges(this.model);
43
+ }
44
+
45
+ return this.hostRouter.transitionTo('console.fleet-ops.connectivity.sensors.index');
46
+ }
47
+
48
+ @action view() {
49
+ if (this.model.hasDirtyAttributes) {
50
+ return this.#confirmContinueWithUnsavedChanges(this.model);
51
+ }
52
+
53
+ return this.hostRouter.transitionTo('console.fleet-ops.connectivity.sensors.index.details', this.model);
54
+ }
55
+
56
+ #confirmContinueWithUnsavedChanges(sensor, options = {}) {
57
+ return this.modalsManager.confirm({
58
+ title: this.intl.t('common.continue-without-saving'),
59
+ body: this.intl.t('common.continue-without-saving-prompt', { resource: this.intl.t('resource.sensor') }),
60
+ acceptButtonText: this.intl.t('common.continue'),
61
+ confirm: async () => {
62
+ sensor.rollbackAttributes();
63
+ await this.hostRouter.transitionTo('console.fleet-ops.connectivity.sensors.index.details', sensor);
64
+ },
65
+ ...options,
66
+ });
67
+ }
68
+ }
@@ -1,9 +1,12 @@
1
1
  import Controller from '@ember/controller';
2
2
  import { inject as service } from '@ember/service';
3
3
  import { tracked } from '@glimmer/tracking';
4
+ import fleetOpsOptions from '../../../utils/fleet-ops-options';
4
5
 
5
6
  export default class ConnectivitySensorsIndexController extends Controller {
6
7
  @service sensorActions;
8
+ @service deviceActions;
9
+ @service telematicActions;
7
10
  @service intl;
8
11
 
9
12
  /** query params */
@@ -55,19 +58,76 @@ export default class ConnectivitySensorsIndexController extends Controller {
55
58
  @tracked columns = [
56
59
  {
57
60
  label: this.intl.t('column.name'),
58
- valuePath: 'name',
61
+ valuePath: 'displayName',
59
62
  width: '180px',
60
63
  cellComponent: 'table/cell/anchor',
61
64
  cellClassNames: 'uppercase',
62
65
  action: this.sensorActions.transition.view,
63
66
  permission: 'fleet-ops view sensor',
64
- hidden: true,
65
67
  resizable: true,
66
68
  sortable: true,
67
69
  filterable: true,
68
70
  filterParam: 'name',
69
71
  filterComponent: 'filter/string',
70
72
  },
73
+ {
74
+ label: 'Telematic',
75
+ valuePath: 'telematic.provider',
76
+ cellComponent: 'table/cell/anchor',
77
+ action: this.telematicActions.transition.view,
78
+ permission: 'fleet-ops view telematic',
79
+ resizable: true,
80
+ sortable: true,
81
+ filterable: true,
82
+ filterComponent: 'filter/model',
83
+ filterComponentPlaceholder: 'Select telematic',
84
+ filterParam: 'telematic',
85
+ model: 'telematic',
86
+ },
87
+ {
88
+ label: 'Device',
89
+ valuePath: 'device.displayName',
90
+ cellComponent: 'table/cell/anchor',
91
+ action: this.deviceActions.transition.view,
92
+ permission: 'fleet-ops view device',
93
+ resizable: true,
94
+ sortable: true,
95
+ filterable: true,
96
+ filterComponent: 'filter/model',
97
+ filterComponentPlaceholder: 'Select device',
98
+ filterParam: 'device',
99
+ model: 'device',
100
+ },
101
+ {
102
+ label: 'Type',
103
+ valuePath: 'type',
104
+ resizable: true,
105
+ sortable: true,
106
+ filterable: true,
107
+ filterParam: 'type',
108
+ filterComponent: 'filter/multi-option',
109
+ filterOptions: fleetOpsOptions('sensorTypes'),
110
+ },
111
+ {
112
+ label: 'Serial Number',
113
+ valuePath: 'serial_number',
114
+ resizable: true,
115
+ sortable: true,
116
+ filterable: true,
117
+ filterParam: 'serial_number',
118
+ filterComponent: 'filter/string',
119
+ },
120
+ {
121
+ label: this.intl.t('column.status'),
122
+ valuePath: 'status',
123
+ cellComponent: 'table/cell/status',
124
+ width: '10%',
125
+ resizable: true,
126
+ sortable: true,
127
+ filterable: true,
128
+ filterComponent: 'filter/multi-option',
129
+ filterOptions: fleetOpsOptions('sensorStatuses'),
130
+ },
71
131
  {
72
132
  label: this.intl.t('column.created-at'),
73
133
  valuePath: 'createdAt',
@@ -96,18 +156,18 @@ export default class ConnectivitySensorsIndexController extends Controller {
96
156
  ddButtonText: false,
97
157
  ddButtonIcon: 'ellipsis-h',
98
158
  ddButtonIconPrefix: 'fas',
99
- ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.Sensor') }),
159
+ ddMenuLabel: this.intl.t('common.resource-actions', { resource: this.intl.t('resource.sensor') }),
100
160
  cellClassNames: 'overflow-visible',
101
161
  wrapperClass: 'flex items-center justify-end mx-2',
102
162
  width: '10%',
103
163
  actions: [
104
164
  {
105
- label: this.intl.t('column.view-details'),
165
+ label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.sensor') }),
106
166
  fn: this.sensorActions.transition.view,
107
167
  permission: 'fleet-ops view sensor',
108
168
  },
109
169
  {
110
- label: this.intl.t('column.edit-place'),
170
+ label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.sensor') }),
111
171
  fn: this.sensorActions.transition.edit,
112
172
  permission: 'fleet-ops update sensor',
113
173
  },
@@ -115,7 +175,7 @@ export default class ConnectivitySensorsIndexController extends Controller {
115
175
  separator: true,
116
176
  },
117
177
  {
118
- label: this.intl.t('column.delete'),
178
+ label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.sensor') }),
119
179
  fn: this.sensorActions.delete,
120
180
  permission: 'fleet-ops delete sensor',
121
181
  },
@@ -1,3 +1,24 @@
1
1
  import Controller from '@ember/controller';
2
+ import { inject as service } from '@ember/service';
2
3
 
3
- export default class ConnectivityTelematicsIndexDetailsController extends Controller {}
4
+ export default class ConnectivityTelematicsIndexDetailsController extends Controller {
5
+ @service hostRouter;
6
+
7
+ get tabs() {
8
+ return [
9
+ {
10
+ route: 'connectivity.telematics.index.details.index',
11
+ label: 'Overview',
12
+ },
13
+ ];
14
+ }
15
+
16
+ get actionButtons() {
17
+ return [
18
+ {
19
+ icon: 'pencil',
20
+ fn: () => this.hostRouter.transitionTo('console.fleet-ops.connectivity.telematics.index.edit', this.model),
21
+ },
22
+ ];
23
+ }
24
+ }
@@ -1,3 +1,68 @@
1
1
  import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { task } from 'ember-concurrency';
2
6
 
3
- export default class ConnectivityTelematicsIndexEditController extends Controller {}
7
+ export default class ConnectivityTelematicsIndexEditController extends Controller {
8
+ @service hostRouter;
9
+ @service intl;
10
+ @service notifications;
11
+ @service modalsManager;
12
+ @tracked overlay;
13
+
14
+ get actionButtons() {
15
+ return [
16
+ {
17
+ icon: 'eye',
18
+ fn: this.view,
19
+ },
20
+ ];
21
+ }
22
+
23
+ @task *save(telematic) {
24
+ try {
25
+ yield telematic.save();
26
+ this.overlay?.close();
27
+
28
+ yield this.hostRouter.transitionTo('console.fleet-ops.connectivity.telematics.index.details', telematic);
29
+ this.notifications.success(
30
+ this.intl.t('common.resource-updated-success', {
31
+ resource: this.intl.t('resource.telematic'),
32
+ resourceName: telematic.name ?? telematic.provider,
33
+ })
34
+ );
35
+ } catch (err) {
36
+ this.notifications.serverError(err);
37
+ }
38
+ }
39
+
40
+ @action cancel() {
41
+ if (this.model.hasDirtyAttributes) {
42
+ return this.#confirmContinueWithUnsavedChanges(this.model);
43
+ }
44
+
45
+ return this.hostRouter.transitionTo('console.fleet-ops.connectivity.telematics.index');
46
+ }
47
+
48
+ @action view() {
49
+ if (this.model.hasDirtyAttributes) {
50
+ return this.#confirmContinueWithUnsavedChanges(this.model);
51
+ }
52
+
53
+ return this.hostRouter.transitionTo('console.fleet-ops.connectivity.telematics.index.details', this.model);
54
+ }
55
+
56
+ #confirmContinueWithUnsavedChanges(telematic, options = {}) {
57
+ return this.modalsManager.confirm({
58
+ title: this.intl.t('common.continue-without-saving'),
59
+ body: this.intl.t('common.continue-without-saving-prompt', { resource: this.intl.t('resource.telematic') }),
60
+ acceptButtonText: this.intl.t('common.continue'),
61
+ confirm: async () => {
62
+ telematic.rollbackAttributes();
63
+ await this.hostRouter.transitionTo('console.fleet-ops.connectivity.telematics.index.details', telematic);
64
+ },
65
+ ...options,
66
+ });
67
+ }
68
+ }