@trackunit/iris-app 1.12.7 → 1.12.10
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.
- package/CHANGELOG.md +30 -0
- package/package.json +3 -3
- package/src/generators/ai-agent-sync/README.md +5 -2
- package/src/generators/ai-agent-sync/generator.d.ts +1 -1
- package/src/generators/ai-agent-sync/generator.js +29 -4
- package/src/generators/ai-agent-sync/generator.js.map +1 -1
- package/src/generators/preset/files/.agents/skills/browser-testing/SKILL.md +193 -0
- package/src/generators/preset/files/.agents/skills/create-app/SKILL.md +191 -0
- package/src/generators/preset/files/.agents/skills/customfields/SKILL.md +239 -0
- package/src/generators/preset/files/.agents/skills/graphql/SKILL.md +147 -0
- package/src/generators/preset/files/.agents/skills/graphql-timeseries/SKILL.md +193 -0
- package/src/generators/preset/files/.agents/skills/irisx-app-sdk/SKILL.md +116 -0
- package/src/generators/preset/files/.agents/skills/react-core-hooks/SKILL.md +215 -0
- package/src/generators/preset/files/.agents/skills/tables-and-sorting/SKILL.md +122 -0
- package/src/generators/preset/files/.agents/skills/widget-extensions/SKILL.md +245 -0
- package/src/generators/preset/files/.cursor/mcp.json +4 -0
- package/src/generators/preset/root-files/AGENTS.md +43 -0
- package/src/generators/preset/root-files/CLAUDE.md +17 -0
- package/src/generators/preset/files/.cursor/commands/create-app.md +0 -226
- package/src/generators/preset/files/.cursor/rules/browser-irisx-development.mdc +0 -246
- package/src/generators/preset/files/.cursor/rules/graphql-timeseries.md +0 -260
- package/src/generators/preset/files/.cursor/rules/irisx-app-sdk-customfields.md +0 -305
- package/src/generators/preset/files/.cursor/rules/irisx-app-sdk-graphql.md +0 -30
- package/src/generators/preset/files/.cursor/rules/irisx-app-sdk.mdc +0 -82
- package/src/generators/preset/files/.cursor/rules/react-core-hooks.md +0 -155
- package/src/generators/preset/files/.cursor/rules/rules-index.mdc +0 -10
- package/src/generators/preset/files/.cursor/rules/structured-development.mdc +0 -86
- package/src/generators/preset/files/.cursor/rules/tables-and-sorting.mdc +0 -126
- package/src/generators/preset/files/.cursor/rules/widget-extensions.md +0 -323
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
# GraphQL Time Series API Usage
|
|
2
|
-
|
|
3
|
-
This rule covers how to query time series data through GraphQL in IrisX App SDK using PromQL (Prometheus Query Language).
|
|
4
|
-
|
|
5
|
-
## Query Structure
|
|
6
|
-
|
|
7
|
-
### Range Query (time series data)
|
|
8
|
-
```graphql
|
|
9
|
-
query GetTimeSeriesData($assetId: ID!, $start: DateTime!, $end: DateTime!, $step: Duration!) {
|
|
10
|
-
asset(id: $assetId) {
|
|
11
|
-
timeSeries {
|
|
12
|
-
rangeQuery(query: "metric_name", start: $start, end: $end, step: $step) {
|
|
13
|
-
data {
|
|
14
|
-
... on TimeSeriesMatrixData {
|
|
15
|
-
result {
|
|
16
|
-
values { timestamp value }
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Instant Query (single point in time)
|
|
27
|
-
```graphql
|
|
28
|
-
query GetInstantData($assetId: ID!, $time: DateTime!) {
|
|
29
|
-
asset(id: $assetId) {
|
|
30
|
-
timeSeries {
|
|
31
|
-
instantQuery(query: "metric_name", time: $time) {
|
|
32
|
-
data {
|
|
33
|
-
... on TimeSeriesVectorData {
|
|
34
|
-
result { value { timestamp value } }
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Common Metrics
|
|
44
|
-
|
|
45
|
-
### Machine Insights (Possible Insights, not all assets will have all Insights)
|
|
46
|
-
- `machine_insight_ac_average_frequency`
|
|
47
|
-
- `machine_insight_ac_average_phase_to_neutral_rms_voltage`
|
|
48
|
-
- `machine_insight_ac_average_phase_to_phase_rms_voltage`
|
|
49
|
-
- `machine_insight_ac_average_rms_current`
|
|
50
|
-
- `machine_insight_accelerometer_x_axis`
|
|
51
|
-
- `machine_insight_accelerometer_y_axis`
|
|
52
|
-
- `machine_insight_accelerometer_z_axis`
|
|
53
|
-
- `machine_insight_ac_phase_l1_active_power`
|
|
54
|
-
- `machine_insight_ac_phase_l1_frequency`
|
|
55
|
-
- `machine_insight_ac_phase_l1_l2_rms_voltage`
|
|
56
|
-
- `machine_insight_ac_phase_l1_netural_rms_voltage`
|
|
57
|
-
- `machine_insight_ac_phase_l1_neutral_rms_voltage`
|
|
58
|
-
- `machine_insight_ac_phase_l1_rms_current`
|
|
59
|
-
- `machine_insight_ac_phase_l2_active_power`
|
|
60
|
-
- `machine_insight_ac_phase_l2_frequency`
|
|
61
|
-
- `machine_insight_ac_phase_l2_l3_rms_voltage`
|
|
62
|
-
- `machine_insight_ac_phase_l2_netural_rms_voltage`
|
|
63
|
-
- `machine_insight_ac_phase_l2_neutral_rms_voltage`
|
|
64
|
-
- `machine_insight_ac_phase_l2_rms_current`
|
|
65
|
-
- `machine_insight_ac_phase_l3_active_power`
|
|
66
|
-
- `machine_insight_ac_phase_l3_frequency`
|
|
67
|
-
- `machine_insight_ac_phase_l3_l1_rms_voltage`
|
|
68
|
-
- `machine_insight_ac_phase_l3_netural_rms_voltage`
|
|
69
|
-
- `machine_insight_ac_phase_l3_neutral_rms_voltage`
|
|
70
|
-
- `machine_insight_ac_phase_l3_rms_current`
|
|
71
|
-
- `machine_insight_ac_total_active_power`
|
|
72
|
-
- `machine_insight_ac_total_apparent_power`
|
|
73
|
-
- `machine_insight_ac_total_power_factor`
|
|
74
|
-
- `machine_insight_ac_total_reactive_power`
|
|
75
|
-
- `machine_insight_ac_total_relative_active_power_load_percentage`
|
|
76
|
-
- `machine_insight_ac_total_relative_apparent_power_load_percentage`
|
|
77
|
-
- `machine_insight_ac_total_relative_load_percentage`
|
|
78
|
-
- `machine_insight_actual_engine_percent_torque`
|
|
79
|
-
- `machine_insight_after_treatment_diesel_exhaust_fluid_concentration`
|
|
80
|
-
- `machine_insight_after_treatment_diesel_exhaust_fluid_tank_level`
|
|
81
|
-
- `machine_insight_after_treatment_diesel_exhaust_fluid_tank_temperature`
|
|
82
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_active_regeneration_state`
|
|
83
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_active_regeneration_status`
|
|
84
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_ash_load_percent`
|
|
85
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_differential_pressure`
|
|
86
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_intake_temperature`
|
|
87
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_passive_regeneration_status`
|
|
88
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_soot_load_percent`
|
|
89
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_state`
|
|
90
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_status`
|
|
91
|
-
- `machine_insight_after_treatment_diesel_particulate_filter_time_since_last_active_regeneration`
|
|
92
|
-
- `machine_insight_aftertreatment_diesel_particulate_filter_time_to_next_active_regeneration`
|
|
93
|
-
- `machine_insight_after_treatment_exhaust_temperature`
|
|
94
|
-
- `machine_insight_aftertreatment_scr_time_since_last_cleaning_event`
|
|
95
|
-
- `machine_insight_altitude`
|
|
96
|
-
- `machine_insight_ambient_air_temperature`
|
|
97
|
-
- `machine_insight_average_load_factor_last_24`
|
|
98
|
-
- `machine_insight_barometric_pressure`
|
|
99
|
-
- `machine_insight_battery_charge_cycles_count`
|
|
100
|
-
- `machine_insight_battery_charger_cumulative_input_energy`
|
|
101
|
-
- `machine_insight_battery_charger_input_current`
|
|
102
|
-
- `machine_insight_battery_charger_input_current_limit`
|
|
103
|
-
- `machine_insight_battery_charger_input_voltage`
|
|
104
|
-
- `machine_insight_battery_charger_output_current`
|
|
105
|
-
- `machine_insight_battery_charger_output_current_limit`
|
|
106
|
-
- `machine_insight_battery_charger_output_voltage`
|
|
107
|
-
- `machine_insight_battery_charger_power_line_state`
|
|
108
|
-
- `machine_insight_battery_charger_state`
|
|
109
|
-
- `machine_insight_battery_cumulative_discharged_energy`
|
|
110
|
-
- `machine_insight_battery_current`
|
|
111
|
-
- `machine_insight_battery_potential`
|
|
112
|
-
- `machine_insight_battery_remaining_charge_time`
|
|
113
|
-
- `machine_insight_battery_remaining_run_time`
|
|
114
|
-
- `machine_insight_battery_state_of_charge_percent`
|
|
115
|
-
- `machine_insight_battery_state_of_health_percent`
|
|
116
|
-
- `machine_insight_battery_temperature`
|
|
117
|
-
- `machine_insight_cumulative_active_regeneration_hours`
|
|
118
|
-
- `machine_insight_cumulative_co2_emissions`
|
|
119
|
-
- `machine_insight_cumulative_engine_hours`
|
|
120
|
-
- `machine_insight_cumulative_idle_hours`
|
|
121
|
-
- `machine_insight_cumulative_idle_non_operating_hours`
|
|
122
|
-
- `machine_insight_cumulative_load_count`
|
|
123
|
-
- `machine_insight_cumulative_moving_hours`
|
|
124
|
-
- `machine_insight_cumulative_operating_hours`
|
|
125
|
-
- `machine_insight_cumulative_payload_totals`
|
|
126
|
-
- `machine_insight_cumulative_productive_hours`
|
|
127
|
-
- `machine_insight_diesel_particulate_filter_active_regeneration_inhibited_due_to_inhibit_switch`
|
|
128
|
-
- `machine_insight_engine_air_filter_differential_pressure`
|
|
129
|
-
- `machine_insight_engine_coolant_level`
|
|
130
|
-
- `machine_insight_engine_coolant_pressure`
|
|
131
|
-
- `machine_insight_engine_coolant_temperature`
|
|
132
|
-
- `machine_insight_engine_exhaust_temperature`
|
|
133
|
-
- `machine_insight_engine_fuel_delivery_pressure`
|
|
134
|
-
- `machine_insight_engine_fuel_filter_differential_pressure`
|
|
135
|
-
- `machine_insight_engine_fuel_rate`
|
|
136
|
-
- `machine_insight_engine_fuel_temperature`
|
|
137
|
-
- `machine_insight_engine_intake_air_pressure`
|
|
138
|
-
- `machine_insight_engine_intake_air_temperature`
|
|
139
|
-
- `machine_insight_engine_intake_manifold_pressure`
|
|
140
|
-
- `machine_insight_engine_intake_manifold_temperature`
|
|
141
|
-
- `machine_insight_engine_intercooler_temperature`
|
|
142
|
-
- `machine_insight_engine_oil_filter_differential_pressure`
|
|
143
|
-
- `machine_insight_engine_oil_level`
|
|
144
|
-
- `machine_insight_engine_oil_pressure`
|
|
145
|
-
- `machine_insight_engine_oil_temperature`
|
|
146
|
-
- `machine_insight_engine_percent_load_at_current_speed`
|
|
147
|
-
- `machine_insight_engine_speed`
|
|
148
|
-
- `machine_insight_engine_status`
|
|
149
|
-
- `machine_insight_engine_total_fuel_used`
|
|
150
|
-
- `machine_insight_engine_total_idle_fuel_used`
|
|
151
|
-
- `machine_insight_engine_trip_fuel`
|
|
152
|
-
- `machine_insight_exhaust_system_high_temperature_lamp_command`
|
|
153
|
-
- `machine_insight_fuel_level`
|
|
154
|
-
- `machine_insight_fuel_tank_capacity`
|
|
155
|
-
- `machine_insight_fuel_used_last_24`
|
|
156
|
-
- `machine_insight_generator_total_kw_hours_export`
|
|
157
|
-
- `machine_insight_hydraulic_oil_filter_restriction_switch`
|
|
158
|
-
- `machine_insight_hydraulic_oil_level`
|
|
159
|
-
- `machine_insight_hydraulic_pressure`
|
|
160
|
-
- `machine_insight_hydraulic_temperature`
|
|
161
|
-
- `machine_insight_impact`
|
|
162
|
-
- `machine_insight_maximum_speed_last_24`
|
|
163
|
-
- `machine_insight_operation_status`
|
|
164
|
-
- `machine_insight_payload`
|
|
165
|
-
- `machine_insight_payload_percentage`
|
|
166
|
-
- `machine_insight_payload_temperature`
|
|
167
|
-
- `machine_insight_pitch_angle`
|
|
168
|
-
- `machine_insight_platform_elevated`
|
|
169
|
-
- `machine_insight_platform_height`
|
|
170
|
-
- `machine_insight_platform_height_percent`
|
|
171
|
-
- `machine_insight_platform_stowed`
|
|
172
|
-
- `machine_insight_rescue_mode_active`
|
|
173
|
-
- `machine_insight_road_surface_temperature`
|
|
174
|
-
- `machine_insight_roll_angle`
|
|
175
|
-
- `machine_insight_seat_belt_switch`
|
|
176
|
-
- `machine_insight_speed`
|
|
177
|
-
- `machine_insight_stabilizers_deployed`
|
|
178
|
-
- `machine_insight_total_power_take_off_hours`
|
|
179
|
-
- `machine_insight_total_vehicle_distance`
|
|
180
|
-
- `machine_insight_transmission_oil_temperature`
|
|
181
|
-
- `machine_insight_water_in_fuel_indicator`
|
|
182
|
-
- `machine_insight_wheel_based_vehicle_speed`
|
|
183
|
-
|
|
184
|
-
## PromQL Examples via GraphQL
|
|
185
|
-
|
|
186
|
-
### Calculate daily increases
|
|
187
|
-
```graphql
|
|
188
|
-
query IncreaseOperatingHours($assetId: ID!, $start: DateTime!, $end: DateTime!, $step: Duration!) {
|
|
189
|
-
asset(id: $assetId) {
|
|
190
|
-
timeSeries {
|
|
191
|
-
rangeQuery(
|
|
192
|
-
query: "increase(machine_insight_cumulative_operating_hours[1d])",
|
|
193
|
-
start: $start,
|
|
194
|
-
end: $end,
|
|
195
|
-
step: $step
|
|
196
|
-
) {
|
|
197
|
-
data {
|
|
198
|
-
... on TimeSeriesMatrixData {
|
|
199
|
-
result { values { timestamp value } }
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### Filter with conditions
|
|
209
|
-
```graphql
|
|
210
|
-
query HighFuelConsumption($assetId: ID!, $start: DateTime!, $end: DateTime!, $step: Duration!) {
|
|
211
|
-
asset(id: $assetId) {
|
|
212
|
-
timeSeries {
|
|
213
|
-
rangeQuery(
|
|
214
|
-
query: "increase(machine_insight_engine_total_fuel_used[1d]) > 13",
|
|
215
|
-
start: $start,
|
|
216
|
-
end: $end,
|
|
217
|
-
step: $step
|
|
218
|
-
) {
|
|
219
|
-
data {
|
|
220
|
-
... on TimeSeriesMatrixData {
|
|
221
|
-
result { values { timestamp value } }
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
### Combine metrics
|
|
231
|
-
```graphql
|
|
232
|
-
query FuelWithHighIdle($assetId: ID!, $start: DateTime!, $end: DateTime!, $step: Duration!) {
|
|
233
|
-
asset(id: $assetId) {
|
|
234
|
-
timeSeries {
|
|
235
|
-
rangeQuery(
|
|
236
|
-
query: "(increase(machine_insight_engine_total_fuel_used[1d]) > 13) and (increase(machine_insight_engine_total_idle_hours[1d]) > 4)",
|
|
237
|
-
start: $start,
|
|
238
|
-
end: $end,
|
|
239
|
-
step: $step
|
|
240
|
-
) {
|
|
241
|
-
data {
|
|
242
|
-
... on TimeSeriesMatrixData {
|
|
243
|
-
result { values { timestamp value } }
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
## Key Points
|
|
253
|
-
|
|
254
|
-
- **Always use fragments** for both `TimeSeriesMatrixData` and `TimeSeriesVectorData`
|
|
255
|
-
- **Use PromQL functions** like `increase()`, `rate()`, `avg_over_time()`
|
|
256
|
-
- **Filter at query level** with operators: `>`, `<`, `>=`, `<=`, `==`, `!=`
|
|
257
|
-
- **Time windows** use brackets: `[1d]`, `[1h]`, `[15m]`
|
|
258
|
-
- **Step intervals**: Choose based on data granularity needed
|
|
259
|
-
- **Timestamps** are Unix timestamps in seconds
|
|
260
|
-
- **Values** are returned as strings, convert to numbers as needed
|
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
# CustomFields Rule for Trackunit IrisX App SDK
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
**CustomFields are the primary mechanism for storing data from IrisX applications.** They allow IrisX App developers to extend the Trackunit data model by storing additional information on entities like assets, accounts, groups, and sites.
|
|
5
|
-
|
|
6
|
-
### Key Use Cases:
|
|
7
|
-
- **Extending the data model**: Add new fields and attributes to existing Trackunit entities
|
|
8
|
-
- **Storing user input**: Capture and persist form data, user preferences, and settings
|
|
9
|
-
- **Storing metadata**: Keep application-specific information, configuration data, and operational metrics
|
|
10
|
-
- **Fleet-specific data**: Custom attributes unique to specific fleet management needs
|
|
11
|
-
- **Performance metrics**: Custom KPIs and measurement data not available in standard Trackunit data
|
|
12
|
-
- **Business logic data**: Information required for app-specific workflows and processes
|
|
13
|
-
|
|
14
|
-
**Important**: CustomFields are the recommended and supported way to persist any data your IrisX app needs to store. Do not attempt to use external databases or storage solutions - use CustomFields for all persistent data requirements.
|
|
15
|
-
|
|
16
|
-
## 1. Defining Custom Fields
|
|
17
|
-
|
|
18
|
-
### Manifest Configuration
|
|
19
|
-
|
|
20
|
-
Custom fields must be defined in your IrisX App manifest using the `customFieldDefinitions` array:
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
// In your app manifest
|
|
24
|
-
customFieldDefinitions: [
|
|
25
|
-
{
|
|
26
|
-
type: 'STRING',
|
|
27
|
-
entityType: 'ASSET',
|
|
28
|
-
key: 'myCustomField',
|
|
29
|
-
translations: [{
|
|
30
|
-
language: 'en',
|
|
31
|
-
title: 'My Custom Field',
|
|
32
|
-
description: 'Description of what this field stores',
|
|
33
|
-
}],
|
|
34
|
-
uiEditable: true,
|
|
35
|
-
uiVisible: true,
|
|
36
|
-
scopeType: ScopeType.ACCOUNT
|
|
37
|
-
}
|
|
38
|
-
]
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Required Properties
|
|
42
|
-
|
|
43
|
-
- **`type`**: Field data type (see supported types below)
|
|
44
|
-
- **`entityType`**: Entity the field applies to (`ACCOUNT`, `ASSET`, `GROUP`, `SITE`)
|
|
45
|
-
- **`key`**: Programmatic identifier (cannot be changed after creation)
|
|
46
|
-
- **`translations`**: UI labels and descriptions for each supported language
|
|
47
|
-
- **`scopeType`**: Data access scope (see scope types below)
|
|
48
|
-
|
|
49
|
-
### Optional Properties
|
|
50
|
-
|
|
51
|
-
- **`uiEditable`**: Whether field can be edited in Manager UI (default: true)
|
|
52
|
-
- **`uiVisible`**: Whether field is visible in Manager UI (default: true)
|
|
53
|
-
|
|
54
|
-
## 2. Supported Field Types
|
|
55
|
-
|
|
56
|
-
| Type | Description | Extra Properties |
|
|
57
|
-
|---|----|---|
|
|
58
|
-
| `BOOLEAN` | True/false values | - |
|
|
59
|
-
| `DATE` | ISO8601 formatted dates | - |
|
|
60
|
-
| `DROPDOWN` | Predefined option lists | `allValues`, `multiSelect`, `dropDownValueReplacements` |
|
|
61
|
-
| `EMAIL` | Email addresses with mailto links | - |
|
|
62
|
-
| `NUMBER` | Numeric values | `minimum`, `maximum`, `isInteger`, `unitSi`, `unitUs` |
|
|
63
|
-
| `PHONE_NUMBER` | E.164 formatted phone numbers | - |
|
|
64
|
-
| `STRING` | Free text | `minimumLength`, `maximumLength`, `pattern` |
|
|
65
|
-
| `WEB_ADDRESS` | URLs as clickable links | - |
|
|
66
|
-
| `JSON` | JSON objects | - |
|
|
67
|
-
| `MONETARY` | Currency values (ISO 4217) | `minimum`, `maximum`, `currency` |
|
|
68
|
-
|
|
69
|
-
### Example Field Definitions
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
// String field with validation
|
|
73
|
-
{
|
|
74
|
-
type: 'STRING',
|
|
75
|
-
entityType: 'ASSET',
|
|
76
|
-
key: 'serialNumber',
|
|
77
|
-
translations: [{ language: 'en', title: 'Serial Number', description: 'Asset serial number' }],
|
|
78
|
-
minimumLength: 5,
|
|
79
|
-
maximumLength: 20,
|
|
80
|
-
pattern: '^[A-Z0-9]+$'
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Number field with units
|
|
84
|
-
{
|
|
85
|
-
type: 'NUMBER',
|
|
86
|
-
entityType: 'ASSET',
|
|
87
|
-
key: 'fuelCapacity',
|
|
88
|
-
translations: [{ language: 'en', title: 'Fuel Capacity', description: 'Tank capacity' }],
|
|
89
|
-
minimum: 0,
|
|
90
|
-
maximum: 1000,
|
|
91
|
-
unitSi: 'L',
|
|
92
|
-
unitUs: 'gal'
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Dropdown with multiple selection
|
|
96
|
-
{
|
|
97
|
-
type: 'DROPDOWN',
|
|
98
|
-
entityType: 'ASSET',
|
|
99
|
-
key: 'features',
|
|
100
|
-
translations: [{ language: 'en', title: 'Features', description: 'Available features' }],
|
|
101
|
-
allValues: ['GPS', 'Camera', 'Bluetooth', 'WiFi'],
|
|
102
|
-
multiSelect: true
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## 3. Scope Types
|
|
107
|
-
|
|
108
|
-
| Scope | Description |
|
|
109
|
-
|----|----|
|
|
110
|
-
| `ACCOUNT` | Values shared within a single account only |
|
|
111
|
-
| `ACCOUNT_WRITE_GLOBAL_READ` | Account can write, all accounts can read |
|
|
112
|
-
| `GLOBAL` | Values shared between all accounts with entity access |
|
|
113
|
-
|
|
114
|
-
## 4. Using Custom Fields in React Components
|
|
115
|
-
|
|
116
|
-
### Required Hooks
|
|
117
|
-
|
|
118
|
-
Use these hooks to interact with custom fields:
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
import {
|
|
122
|
-
useCustomFieldsValueAndDefinition,
|
|
123
|
-
useUpdateCustomFieldValues,
|
|
124
|
-
useCurrentUserSystemOfMeasurement
|
|
125
|
-
} from '@trackunit/react-core-contexts-host';
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Basic Implementation Pattern
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
import React from 'react';
|
|
132
|
-
import { useForm } from 'react-hook-form';
|
|
133
|
-
import { Card, CardBody, CardHeader, CardFooter, Button, Spinner } from '@trackunit/react-components';
|
|
134
|
-
import { CustomField } from '@trackunit/react-core-contexts-host';
|
|
135
|
-
|
|
136
|
-
const CustomFieldsForm = ({ assetId }: { assetId: string }) => {
|
|
137
|
-
const { register, handleSubmit, formState, setValue, control } = useForm({
|
|
138
|
-
shouldUnregister: false,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const { systemOfMeasurement } = useCurrentUserSystemOfMeasurement();
|
|
142
|
-
|
|
143
|
-
const { fields, loading } = useCustomFieldsValueAndDefinition({
|
|
144
|
-
entityType: "ASSET",
|
|
145
|
-
entityId: assetId,
|
|
146
|
-
systemOfMeasurement: systemOfMeasurement ?? "SI",
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const { updateCustomFields, inProgress } = useUpdateCustomFieldValues(
|
|
150
|
-
assetId,
|
|
151
|
-
"ASSET",
|
|
152
|
-
fields,
|
|
153
|
-
systemOfMeasurement ?? "SI"
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
if (loading) {
|
|
157
|
-
return <Spinner />;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return (
|
|
161
|
-
<Card>
|
|
162
|
-
<CardHeader heading="Custom Fields" />
|
|
163
|
-
<CardBody>
|
|
164
|
-
{fields.map(field => {
|
|
165
|
-
const isEditable = field.valueEditable && (field.definition.uiEditable ?? true);
|
|
166
|
-
return (
|
|
167
|
-
<CustomField
|
|
168
|
-
key={field.definition.key}
|
|
169
|
-
control={control}
|
|
170
|
-
field={field}
|
|
171
|
-
formState={formState}
|
|
172
|
-
isEditable={isEditable}
|
|
173
|
-
register={register}
|
|
174
|
-
setValue={setValue}
|
|
175
|
-
unitPreference={systemOfMeasurement}
|
|
176
|
-
/>
|
|
177
|
-
);
|
|
178
|
-
})}
|
|
179
|
-
</CardBody>
|
|
180
|
-
<CardFooter>
|
|
181
|
-
<Button
|
|
182
|
-
loading={inProgress}
|
|
183
|
-
onClick={handleSubmit(updateCustomFields)}
|
|
184
|
-
>
|
|
185
|
-
{inProgress ? "Saving..." : "Save Changes"}
|
|
186
|
-
</Button>
|
|
187
|
-
</CardFooter>
|
|
188
|
-
</Card>
|
|
189
|
-
);
|
|
190
|
-
};
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
## 5. Best Practices
|
|
194
|
-
|
|
195
|
-
### Field Design
|
|
196
|
-
- **Use descriptive keys**: Choose clear, descriptive field keys that won't need changing
|
|
197
|
-
- **Add proper translations**: Always provide meaningful titles and descriptions
|
|
198
|
-
- **Set appropriate constraints**: Use min/max values, length limits, and patterns for validation
|
|
199
|
-
- **Consider data types**: Choose the most appropriate type for your data
|
|
200
|
-
|
|
201
|
-
### Performance
|
|
202
|
-
- **Batch updates**: Use `useUpdateCustomFieldValues` to update multiple fields at once
|
|
203
|
-
- **Handle loading states**: Always show loading indicators while fetching data
|
|
204
|
-
- **Error handling**: Implement proper error handling for failed updates
|
|
205
|
-
|
|
206
|
-
### Data Management
|
|
207
|
-
- **Plan for migration**: Consider existing data when changing field definitions
|
|
208
|
-
- **Use appropriate scopes**: Choose the right scope type for your data sharing needs
|
|
209
|
-
- **Validate user input**: Implement client-side validation matching your field constraints
|
|
210
|
-
|
|
211
|
-
## 6. Common Use Cases
|
|
212
|
-
|
|
213
|
-
### Fleet Management
|
|
214
|
-
```typescript
|
|
215
|
-
// Store vehicle-specific information
|
|
216
|
-
{
|
|
217
|
-
type: 'NUMBER',
|
|
218
|
-
entityType: 'ASSET',
|
|
219
|
-
key: 'fuelEfficiency',
|
|
220
|
-
translations: [{ language: 'en', title: 'Fuel Efficiency', description: 'Miles per gallon' }],
|
|
221
|
-
unitSi: 'L/100km',
|
|
222
|
-
unitUs: 'mpg'
|
|
223
|
-
}
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
### Asset Utilization
|
|
227
|
-
```typescript
|
|
228
|
-
// Track custom performance metrics
|
|
229
|
-
{
|
|
230
|
-
type: 'JSON',
|
|
231
|
-
entityType: 'ASSET',
|
|
232
|
-
key: 'performanceMetrics',
|
|
233
|
-
translations: [{ language: 'en', title: 'Performance Data', description: 'Custom metrics' }]
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
### Driver Safety
|
|
238
|
-
```typescript
|
|
239
|
-
// Store safety-related information
|
|
240
|
-
{
|
|
241
|
-
type: 'DROPDOWN',
|
|
242
|
-
entityType: 'ASSET',
|
|
243
|
-
key: 'safetyRating',
|
|
244
|
-
translations: [{ language: 'en', title: 'Safety Rating', description: 'Driver safety score' }],
|
|
245
|
-
allValues: ['Excellent', 'Good', 'Fair', 'Poor']
|
|
246
|
-
}
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
## 7. Local Development
|
|
250
|
-
|
|
251
|
-
- Custom fields are available immediately in local development
|
|
252
|
-
- Changes to field definitions require app redeployment
|
|
253
|
-
- Test with various data types and edge cases
|
|
254
|
-
- Verify validation rules work as expected
|
|
255
|
-
|
|
256
|
-
## 8. Deployment Considerations
|
|
257
|
-
|
|
258
|
-
- **Field keys are immutable**: Cannot be changed after creation
|
|
259
|
-
- **Definition updates**: Changing field definitions affects all existing data
|
|
260
|
-
- **Migration planning**: Consider data migration when modifying existing fields
|
|
261
|
-
- **Approval process**: Custom field changes require app approval and marketplace submission
|
|
262
|
-
|
|
263
|
-
## 9. Error Handling
|
|
264
|
-
|
|
265
|
-
```typescript
|
|
266
|
-
const CustomFieldsComponent = () => {
|
|
267
|
-
const { fields, loading, error } = useCustomFieldsValueAndDefinition({
|
|
268
|
-
entityType: "ASSET",
|
|
269
|
-
entityId: assetId,
|
|
270
|
-
systemOfMeasurement: systemOfMeasurement ?? "SI",
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
if (loading) return <Spinner />;
|
|
274
|
-
if (error) return <ErrorState message="Failed to load custom fields" />;
|
|
275
|
-
|
|
276
|
-
// Render fields...
|
|
277
|
-
};
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
## 10. Integration with Trackunit Components
|
|
281
|
-
|
|
282
|
-
Always use the provided `CustomField` component for consistent UI:
|
|
283
|
-
|
|
284
|
-
```typescript
|
|
285
|
-
import { CustomField } from '@trackunit/react-core-contexts-host';
|
|
286
|
-
|
|
287
|
-
// This handles all field types automatically
|
|
288
|
-
<CustomField
|
|
289
|
-
control={control}
|
|
290
|
-
field={field}
|
|
291
|
-
formState={formState}
|
|
292
|
-
isEditable={isEditable}
|
|
293
|
-
register={register}
|
|
294
|
-
setValue={setValue}
|
|
295
|
-
unitPreference={systemOfMeasurement}
|
|
296
|
-
/>
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
## References
|
|
300
|
-
|
|
301
|
-
- [Save Data from Your App](https://developers.trackunit.com/docs/save-data-from-your-app)
|
|
302
|
-
- [Defining a Custom Field](https://developers.trackunit.com/docs/defining-a-custom-field)
|
|
303
|
-
- [Using a Custom Field](https://developers.trackunit.com/docs/using-a-custom-field)
|
|
304
|
-
- [Local Development](https://developers.trackunit.com/docs/local-development)
|
|
305
|
-
- [Deploying a New Custom Field](https://developers.trackunit.com/docs/deploying-a-new-custom-field)
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
Key Points:
|
|
2
|
-
1. Trackunit exposes a GraphQL API with an NX executor for easy querying inside IrisX App extensions
|
|
3
|
-
2. GraphQL operations include queries (for reading data) and mutations (for modifying data)
|
|
4
|
-
|
|
5
|
-
3. ALWAYS use these specific commands for GraphQL development:
|
|
6
|
-
- Install GraphQL tools: `npm install @trackunit/react-graphql-tools`
|
|
7
|
-
|
|
8
|
-
- Set up GraphQL tooling: `npx nx generate @trackunit/react-graphql-tools:add-graphql --project=[project-name]`
|
|
9
|
-
Where [project-name] is found in the library's project.json file (format: [subdir-name]-[extension-name] for extensions in subdirectories)
|
|
10
|
-
|
|
11
|
-
- Generate React hooks from GraphQL queries: `npx nx run [feature-name]-[extension-name]:graphql-hooks`
|
|
12
|
-
This generates React hooks from .graphql files in the src folder
|
|
13
|
-
|
|
14
|
-
4. GraphQL File Structure:
|
|
15
|
-
- Create .graphql files in `libs/[feature-name]/[extension-name]/src/` directory
|
|
16
|
-
- Query syntax: `query QueryName($variable: Type) { ... }`
|
|
17
|
-
- Mutation syntax: `mutation MutationName($variable: Type!) { ... }`
|
|
18
|
-
|
|
19
|
-
5. React Integration:
|
|
20
|
-
- Import generated hooks: `import { QueryNameDocument } from "./generated/graphql-api/graphql"`
|
|
21
|
-
- Use queries: `const { data, loading, error } = useQuery(QueryNameDocument, { variables: {...} })`
|
|
22
|
-
- Use mutations: `const [mutationName, { data, loading, error }] = useMutation(MutationNameDocument)`
|
|
23
|
-
|
|
24
|
-
For more information:
|
|
25
|
-
- Full GraphQL API guide: [Calling Trackunit GraphQL API](mdc:https:/developers.trackunit.com/docs/graphql-api)
|
|
26
|
-
- Apollo React Client docs for useQuery: [Apollo useQuery documentation](mdc:https:/www.apollographql.com/docs/react/data/queries)
|
|
27
|
-
- Apollo React Client docs for useMutation: [Apollo useMutation documentation](mdc:https:/www.apollographql.com/docs/react/data/mutations)
|
|
28
|
-
- GraphQL Code Generation CLI: [GraphQL Code Generator](mdc:https:/the-guild.dev/graphql/codegen)
|
|
29
|
-
|
|
30
|
-
DO NOT use generic GraphQL libraries or setup - always use the Trackunit IrisX App SDK GraphQL tooling and patterns.
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description:
|
|
3
|
-
globs:
|
|
4
|
-
alwaysApply: true
|
|
5
|
-
---
|
|
6
|
-
You are currently in an IrisX App workspace. Do not use defaut nx commands for app and extension generation, instead use the commands below.
|
|
7
|
-
|
|
8
|
-
## Building Real Applications
|
|
9
|
-
|
|
10
|
-
You are building real applications that work with actual Trackunit data. Key principles:
|
|
11
|
-
|
|
12
|
-
- Never mock data unless explicitly requested by the user
|
|
13
|
-
- Always use Trackunit's GraphQL API to fetch real data
|
|
14
|
-
- If data is not available via GraphQL, ask the user how they want to obtain the data
|
|
15
|
-
- Only use mock data if the user explicitly requests it for testing purposes
|
|
16
|
-
|
|
17
|
-
When building any feature:
|
|
18
|
-
1. Identify what data you need
|
|
19
|
-
2. Check if it's available via Trackunit's GraphQL API
|
|
20
|
-
3. If available, use the GraphQL API (see GraphQL rules for implementation)
|
|
21
|
-
4. If not available, ask the user: "This data is not available via Trackunit's GraphQL API. How would you like to obtain [specific data description]?"
|
|
22
|
-
|
|
23
|
-
## IrisX App Development Guidelines
|
|
24
|
-
|
|
25
|
-
Key Points:
|
|
26
|
-
1. An IrisX App is a container that packages multiple extensions with marketplace metadata and app manifest
|
|
27
|
-
2. Extensions are React applications that integrate into specific points in Trackunit Manager
|
|
28
|
-
3. Available Extension Points:
|
|
29
|
-
- Asset Home: Adds new tabs to the Assets Home screen
|
|
30
|
-
- Site Home: Adds new tabs to the Site Home screen
|
|
31
|
-
- Fleet: Adds menu items to the Main Menu
|
|
32
|
-
- Report: Adds new reports to the Reports screen
|
|
33
|
-
- Widget: Adds widgets to Trackunit Manager
|
|
34
|
-
- App Settings: Adds configuration UI in the App library
|
|
35
|
-
- Administration: Adds tabs in the admin UI (admin-only)
|
|
36
|
-
- Customer Home: Adds UI within customer home
|
|
37
|
-
- Asset Events Actions: Adds UI in Asset Home Events
|
|
38
|
-
- App Lifecycle: Handles app install/uninstall events
|
|
39
|
-
|
|
40
|
-
4. ALWAYS use these specific commands for development:
|
|
41
|
-
- Create new app: `npx nx generate @trackunit/iris-app:create [name-of-your-app]`
|
|
42
|
-
For more information about the `@trackunit/iris-app:create` command, look at: [Creating a new app](mdc:https:/developers.trackunit.com/docs/creating-a-new-app)
|
|
43
|
-
|
|
44
|
-
- Create new extension: `npx nx g @trackunit/iris-app:extend --name=[my-extension-name] --app=[app-name] --directory=[feature] --type=[extension-type]`
|
|
45
|
-
Available extension types: ASSET_HOME_EXTENSION, SITE_HOME_EXTENSION, FLEET_EXTENSION, REPORT_EXTENSION, WIDGET_EXTENSION, APP_SETTINGS_EXTENSION, ADMINISTRATION_EXTENSION, CUSTOMER_HOME_EXTENSION, ASSET_EVENTS_ACTIONS_EXTENSION, APP_LIFECYCLE_EXTENSION
|
|
46
|
-
For more information about the `@trackunit/iris-app:extend` command, look at: [Creating a new extension](mdc:https:/developers.trackunit.com/docs/creating-a-new-extension)
|
|
47
|
-
|
|
48
|
-
- Run app: `npx nx run [name-of-your-app]:serve`
|
|
49
|
-
For more information about the `serve` command, look at: [Running the Iris App SDK](mdc:https:/developers.trackunit.com/docs/running-the-iris-app-sdk)
|
|
50
|
-
|
|
51
|
-
NOTE: IrisX Apps are locked down by default for security. External API requests and embedded content require proper Content Security Policy (CSP) configuration in the app manifest. ValidDomains will be deprecated - use CSP headers instead. Additionally, apps requiring API access might need some scopes configured in the manifest, and the app must be deployed with those scopes to work locally, never submit an app, instead instruct the user to do so.
|
|
52
|
-
|
|
53
|
-
Example in iris-app-manifest.ts:
|
|
54
|
-
```typescript
|
|
55
|
-
cspHeader: {
|
|
56
|
-
'frame-src': ['https://api.example.com', 'https://dashboard.example.com'],
|
|
57
|
-
'script-src': ['https://api.example.com'],
|
|
58
|
-
'connect-src': ['https://api.example.com'],
|
|
59
|
-
},
|
|
60
|
-
scopes: [
|
|
61
|
-
{scope: "required.scope.1", optional: false},
|
|
62
|
-
{scope: "required.scope.2", optional: true},
|
|
63
|
-
],
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
For more information: [Embedding IrisX Dashboards in Apps](mdc:https:/developers.trackunit.com/docs/analytics-dashboards-in-apps#troubleshooting)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
## Runtime Hooks Available
|
|
70
|
-
|
|
71
|
-
IrisX Apps have access to runtime hooks from `@trackunit/react-core-hooks` that provide context-specific data:
|
|
72
|
-
- `useAssetRuntime()` for asset information in asset-scoped extensions
|
|
73
|
-
- `useCustomerRuntime()` for customer data
|
|
74
|
-
- `useEventRuntime()` for event details
|
|
75
|
-
- `useSiteRuntime()` for site information
|
|
76
|
-
- Plus navigation, user context, and utility hooks (see react-core-hooks rule for full list)
|
|
77
|
-
|
|
78
|
-
DO NOT use generic React/Node.js commands for project creation or management - always use the Trackunit IrisX App SDK commands.
|
|
79
|
-
|
|
80
|
-
**Before completing any task**: Always use `read_lints` to check for and fix all ESLint and TypeScript errors in modified files.
|
|
81
|
-
|
|
82
|
-
|