@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.
Files changed (29) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/package.json +3 -3
  3. package/src/generators/ai-agent-sync/README.md +5 -2
  4. package/src/generators/ai-agent-sync/generator.d.ts +1 -1
  5. package/src/generators/ai-agent-sync/generator.js +29 -4
  6. package/src/generators/ai-agent-sync/generator.js.map +1 -1
  7. package/src/generators/preset/files/.agents/skills/browser-testing/SKILL.md +193 -0
  8. package/src/generators/preset/files/.agents/skills/create-app/SKILL.md +191 -0
  9. package/src/generators/preset/files/.agents/skills/customfields/SKILL.md +239 -0
  10. package/src/generators/preset/files/.agents/skills/graphql/SKILL.md +147 -0
  11. package/src/generators/preset/files/.agents/skills/graphql-timeseries/SKILL.md +193 -0
  12. package/src/generators/preset/files/.agents/skills/irisx-app-sdk/SKILL.md +116 -0
  13. package/src/generators/preset/files/.agents/skills/react-core-hooks/SKILL.md +215 -0
  14. package/src/generators/preset/files/.agents/skills/tables-and-sorting/SKILL.md +122 -0
  15. package/src/generators/preset/files/.agents/skills/widget-extensions/SKILL.md +245 -0
  16. package/src/generators/preset/files/.cursor/mcp.json +4 -0
  17. package/src/generators/preset/root-files/AGENTS.md +43 -0
  18. package/src/generators/preset/root-files/CLAUDE.md +17 -0
  19. package/src/generators/preset/files/.cursor/commands/create-app.md +0 -226
  20. package/src/generators/preset/files/.cursor/rules/browser-irisx-development.mdc +0 -246
  21. package/src/generators/preset/files/.cursor/rules/graphql-timeseries.md +0 -260
  22. package/src/generators/preset/files/.cursor/rules/irisx-app-sdk-customfields.md +0 -305
  23. package/src/generators/preset/files/.cursor/rules/irisx-app-sdk-graphql.md +0 -30
  24. package/src/generators/preset/files/.cursor/rules/irisx-app-sdk.mdc +0 -82
  25. package/src/generators/preset/files/.cursor/rules/react-core-hooks.md +0 -155
  26. package/src/generators/preset/files/.cursor/rules/rules-index.mdc +0 -10
  27. package/src/generators/preset/files/.cursor/rules/structured-development.mdc +0 -86
  28. package/src/generators/preset/files/.cursor/rules/tables-and-sorting.mdc +0 -126
  29. 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
-