@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,155 +0,0 @@
1
- ## React Core Hooks Library
2
-
3
- Available hooks from `@trackunit/react-core-hooks` for IrisX App development.
4
-
5
- ### Runtime Hooks
6
-
7
- **`useAssetRuntime()`** - Access asset information in asset-scoped extensions
8
- ```typescript
9
- const { assetInfo, loading, error } = useAssetRuntime();
10
- // assetInfo.assetId, assetInfo.name, etc.
11
- ```
12
-
13
- **`useCustomerRuntime()`** - Access customer information
14
- ```typescript
15
- const { customerInfo, loading, error } = useCustomerRuntime();
16
- // customerInfo.customerId, customerInfo.name, etc.
17
- ```
18
-
19
- **`useEventRuntime()`** - Access event information in event-scoped extensions
20
- ```typescript
21
- const { eventInfo, loading, error } = useEventRuntime();
22
- // eventInfo.eventId, eventInfo.type, etc.
23
- ```
24
-
25
- **`useSiteRuntime()`** - Access site information in site-scoped extensions
26
- ```typescript
27
- const { siteInfo, loading, error } = useSiteRuntime();
28
- // siteInfo.siteId, siteInfo.name, etc.
29
- ```
30
-
31
- **`useIrisAppName()`** - Get current app name
32
- ```typescript
33
- const { appName, loading, error } = useIrisAppName();
34
- ```
35
-
36
- **`useIrisAppId()`** - Get current app ID
37
- ```typescript
38
- const { irisAppId, loading, error } = useIrisAppId();
39
- ```
40
-
41
- ### Navigation & User Context
42
-
43
- **`useNavigateInHost()`** - Navigate within Trackunit Manager
44
- ```typescript
45
- const { navigateToAsset, navigateToSite } = useNavigateInHost();
46
- navigateToAsset({ assetId: "123" });
47
- ```
48
-
49
- **`useHasAccessTo()`** - Check user permissions
50
- ```typescript
51
- const hasAccess = useHasAccessTo({ permission: "assets.read" });
52
- ```
53
-
54
- **`useCurrentUser()`** - Access current user information
55
- ```typescript
56
- const { user } = useCurrentUser();
57
- // user.id, user.email, etc.
58
- ```
59
-
60
- **`useCurrentUserLanguage()`** - Get/set user language preference
61
- ```typescript
62
- const { language, setLanguage } = useCurrentUserLanguage();
63
- ```
64
-
65
- **`useCurrentUserTimeZonePreference()`** - Get user timezone
66
- ```typescript
67
- const { timeZone } = useCurrentUserTimeZonePreference();
68
- ```
69
-
70
- **`useToken()`** - Access authentication token
71
- ```typescript
72
- const { token } = useToken();
73
- ```
74
-
75
- ### UI & Interaction
76
-
77
- **`useToast()`** - Show toast notifications
78
- ```typescript
79
- const { showToast } = useToast();
80
- showToast({ message: "Success!", type: "success" });
81
- ```
82
-
83
- **`useConfirmationDialog()`** - Show confirmation dialogs
84
- ```typescript
85
- const { showConfirmationDialog } = useConfirmationDialog();
86
- const confirmed = await showConfirmationDialog({ message: "Are you sure?" });
87
- ```
88
-
89
- **`useModalDialogContext()`** - Manage modal dialogs
90
- ```typescript
91
- const { openModal, closeModal } = useModalDialogContext();
92
- ```
93
-
94
- **`useErrorHandler()`** - Handle errors consistently
95
- ```typescript
96
- const { handleError } = useErrorHandler();
97
- handleError(new Error("Something went wrong"));
98
- ```
99
-
100
- ### Data & State Management
101
-
102
- **`useLocalStorage()`** - Persist state in localStorage
103
- ```typescript
104
- const [value, setValue, reset] = useLocalStorage({
105
- key: "myKey",
106
- defaultState: { count: 0 }
107
- });
108
- ```
109
-
110
- **`useLocalStorageReducer()`** - localStorage with reducer pattern
111
- ```typescript
112
- const [state, dispatch] = useLocalStorageReducer({
113
- key: "counterState",
114
- defaultState: { count: 0 },
115
- reducer: (state, action) => { /* reducer logic */ }
116
- });
117
- ```
118
-
119
- **`useAssetSorting()`** - Asset sorting functionality
120
- ```typescript
121
- const { sortField, sortDirection, setSorting } = useAssetSorting();
122
- ```
123
-
124
- **`useFilterBarContext()`** - Filter bar state management
125
- ```typescript
126
- const { filters, setFilters, clearFilters } = useFilterBarContext();
127
- ```
128
-
129
- **`useTimeRange()`** - Time range selection
130
- ```typescript
131
- const { timeRange, setTimeRange } = useTimeRange();
132
- ```
133
-
134
-
135
-
136
- ### Widget Configuration
137
-
138
- **`useWidgetConfig()`** - Access widget configuration (synchronous)
139
- ```typescript
140
- const config = useWidgetConfig();
141
- ```
142
-
143
- **`useWidgetConfigAsync()`** - Access widget configuration (asynchronous)
144
- ```typescript
145
- const { getData, setData } = useWidgetConfigAsync();
146
- const config = await getConfig();
147
- ```
148
-
149
-
150
-
151
-
152
-
153
- All hooks require their respective providers to be set up in your app's component tree.
154
-
155
- ```
@@ -1,10 +0,0 @@
1
- ---
2
- alwaysApply: true
3
- ---
4
- This file contains a list of helpful information and context that the agent can reference when working in this codebase. Each entry provides specific guidance or rules for different aspects of the project. You can read these files using the readFile tool if the users prompt seems related.
5
-
6
- - [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.](./irisx-app-sdk-customfields.md)
7
- - [This rule covers GraphQL API integration in Trackunit IrisX App SDK workspace. All GraphQL development MUST follow the Trackunit GraphQL API patterns and commands.](./irisx-app-sdk-graphql.md)
8
- - [Time series API, get time series data from GraphQL. Machine insights data over time.](./graphql-timeseries.md)
9
- - [Use these rules when building Widget Extensions for an Iris App.](./widget-extensions.md)
10
- - [Use these rules whne building App SDK specific React Hook, Runtime Hooks](./react-core-hooks.md)
@@ -1,86 +0,0 @@
1
- ---
2
- alwaysApply: true
3
- ---
4
-
5
- # Structured Feature Development Documentation
6
-
7
- ## Overview
8
- When developing new features, maintain concise documentation to track progress, decisions, and implementation details.
9
-
10
- ## Process
11
- 1. **Check for existing documentation**: Look in `/docs` folder for a markdown file named after the feature (e.g., `user-authentication.md`, `shopping-cart.md`)
12
- 2. **Create or update**:
13
- - If documentation exists: Update it with new requirements and progress
14
- - If it doesn't exist: Create a new file with the feature name as filename
15
- 3. **Use visual aids**: Include mermaid diagrams for complex flows, architecture, or data relationships
16
- 4. **Keep it current**: Update the documentation as development progresses
17
-
18
- ## Important Guidelines
19
- - **Be concise**: Keep descriptions brief and to the point
20
- - **Only document what was requested**: Do not make up future steps or tasks that weren't part of the user's suggestions, unless explitly asked.
21
- - **Focus on implementation**: Document what was actually built, not theoretical features
22
-
23
- ## Task Analysis Process
24
- 1. **Analyze the user's request**: Understand exactly what the user asked for
25
- 2. **Break down into tasks**: Split the request into specific, actionable tasks
26
- 3. **Document only requested work**: Only include tasks that directly relate to the user's request
27
- 4. **Optional sections**: Todo and In Progress sections are OPTIONAL - only include them if there are actual remaining tasks from the user's request
28
-
29
- ## Required File Structure
30
-
31
- ### File Naming
32
- Use kebab-case naming convention: `feature-name.md`
33
-
34
- ### Template Structure
35
-
36
- ```markdown
37
- # Feature Name
38
-
39
- ## Description
40
- Brief overview of what the feature does and why it's needed.
41
-
42
- ## Architecture
43
- Technical approach and key design decisions.
44
-
45
- ## Progress Tracking
46
-
47
- ### ✅ Completed Steps
48
- - [x] Task 1: Description
49
- - [x] Task 2: Description
50
-
51
- ### 🔄 In Progress
52
- *OPTIONAL: Only include if there are actual tasks from the user's request that are currently being worked on*
53
- - [ ] Task 3: Description
54
- - [ ] Task 4: Description
55
-
56
- ### 📝 Todo
57
- *OPTIONAL: Only include if there are remaining tasks from the user's request that haven't been started*
58
- - [ ] Task 5: Description
59
- - [ ] Task 6: Description
60
-
61
- ## Technologies Used
62
- - **Technology Name**: Brief description of usage
63
- - **Library Name**: Version and purpose
64
-
65
- ## Implementation Details
66
- Key technical specifics:
67
- - API endpoints used
68
- - Configuration requirements
69
- - Performance considerations
70
-
71
- ## Good To Know
72
- Important findings, decisions, and gotchas:
73
- - Quirks or workarounds implemented
74
- - Alternative approaches considered
75
- - Performance implications
76
- - Security considerations
77
- - Testing strategies
78
- ```
79
-
80
- ## Best Practices
81
- - Keep descriptions brief and focused
82
- - Only document requested features and tasks
83
- - Include mermaid diagrams for complex flows
84
- - Document actual implementation details
85
- - Update progress as development happens
86
- - **CRITICAL**: Never add tasks or features that weren't explicitly mentioned in the user's request
@@ -1,126 +0,0 @@
1
- ---
2
- alwaysApply: false
3
- ---
4
- # 📊 Trackunit Table with Filtering & Sorting
5
-
6
- Create interactive data tables with server-side filtering, sorting, and pagination using Trackunit components and GraphQL.
7
-
8
- ## 🎯 When to Apply
9
- - Building asset management interfaces
10
- - Creating user administration tables
11
- - Developing dashboard data grids
12
- - Implementing reporting interfaces with large datasets
13
- - Any UI requiring interactive table features (filter/sort/paginate)
14
-
15
- ## 🔧 Required Imports
16
- ```typescript
17
- import { Table, useTable, TextCell, DateCell } from '@trackunit/react-table';
18
- import { FilterBar, useFilterBar } from '@trackunit/filters-filter-bar';
19
- import { usePaginationQuery } from '@trackunit/react-graphql-hooks';
20
- import { createColumnHelper, SortingState } from '@tanstack/react-table';
21
- import { useBrandFilter, useModelFilter } from '@trackunit/filters-asset-filters';
22
- ```
23
-
24
- ## ✅ Valid Implementation
25
-
26
- ```typescript
27
- const AssetTable = () => {
28
- // Setup filters with proper naming
29
- const filterBar = useFilterBar({
30
- name: "assetFilters",
31
- filterBarDefinition: {
32
- brand: useBrandFilter(),
33
- model: useModelFilter()
34
- }
35
- });
36
-
37
- // Server-side sorting state
38
- const [sorting, setSorting] = useState<SortingState>([]);
39
-
40
- // GraphQL query with filters
41
- const { data, loading, error, pagination } = usePaginationQuery(GetAssetsDocument, {
42
- variables: { first: 50, ...filterBar.selectedFilters },
43
- pageSize: 50,
44
- });
45
-
46
- // Transform data with useMemo
47
- const assets = useMemo(() =>
48
- data?.assets.edges.map(edge => ({ ...edge.node, id: edge.node.id })) ?? [],
49
- [data]
50
- );
51
-
52
- // Define columns with proper cell components
53
- const columns = useMemo(() => [
54
- columnHelper.accessor('name', {
55
- cell: ({ row: { original } }) => <TextCell text={original.name} />,
56
- header: "Asset Name",
57
- enableSorting: true,
58
- }),
59
- columnHelper.accessor('createdAt', {
60
- cell: ({ row: { original } }) => <DateCell date={original.createdAt} />,
61
- header: "Created",
62
- enableSorting: true,
63
- }),
64
- ], []);
65
-
66
- // Setup table with manual sorting
67
- const { table } = useTable({
68
- data: assets,
69
- columns,
70
- enableSorting: true,
71
- manualSorting: true,
72
- state: { sorting },
73
- onSortingChange: setSorting,
74
- });
75
-
76
- return (
77
- <>
78
- <FilterBar filterBar={filterBar} />
79
- <Table
80
- table={table}
81
- loading={loading}
82
- error={error}
83
- pagination={pagination}
84
- onRowClick={(row) => navigateToAsset(row.original.id)}
85
- />
86
- </>
87
- );
88
- };
89
- ```
90
-
91
- ## ❌ Invalid Implementation
92
-
93
- ```typescript
94
- // DON'T: Missing useMemo optimization
95
- const columns = [
96
- columnHelper.accessor('name', {
97
- cell: ({ getValue }) => getValue(), // Wrong: Use TextCell component
98
- header: "Name"
99
- })
100
- ];
101
-
102
- // DON'T: Client-side sorting on large datasets
103
- const { table } = useTable({
104
- data: assets,
105
- columns,
106
- enableSorting: true,
107
- manualSorting: false, // Wrong: Should be true for server-side
108
- });
109
-
110
- // DON'T: Missing filter integration
111
- const { data } = usePaginationQuery(GetAssetsDocument, {
112
- variables: { first: 50 }, // Wrong: Missing filter variables
113
- });
114
-
115
- // DON'T: No row click handler
116
- <Table table={table} loading={loading} />
117
- ```
118
-
119
- ## 🎯 Key Requirements
120
-
121
- - **Always use `useMemo`** for data transformation and column definitions
122
- - **Enable `manualSorting: true`** for datasets > 1000 items
123
- - **Integrate filter state** with GraphQL variables using spread operator
124
- - **Use Trackunit cell components** (`TextCell`, `DateCell`) for consistency
125
- - **Implement `onRowClick`** for navigation or detail views
126
- - **Sync state properly** between filters, sorting, and GraphQL queries
@@ -1,323 +0,0 @@
1
- # Widget Extensions
2
-
3
- Widget extensions are specialized components that integrate into Trackunit Manager's dashboard systems, providing customizable UI elements for data visualization and user interaction.
4
-
5
- ## Key Concepts
6
-
7
- 1. **Widget Extensions** are React applications that render within widget containers on various pages
8
- 2. **Supported Locations** define where widgets can be placed in Trackunit Manager
9
- 3. **Widget Types** categorize widgets by their primary purpose and visual style
10
- 4. **Filter Support** enables widgets to respond to user-applied filters
11
- 5. **Configuration** allows widgets to store and manage their own settings
12
-
13
- ## Creating Widget Extensions
14
-
15
- ### Generate a new widget extension:
16
- ```bash
17
- npx nx g @trackunit/iris-app:extend --name=[my-widget-name] --app=[app-name] --directory=[feature] --type=WIDGET_EXTENSION
18
- ```
19
-
20
- This creates:
21
- - `extension-manifest.ts` - Widget configuration and metadata
22
- - `src/app.tsx` - Main widget component
23
- - `src/editDialog.tsx` - Configuration dialog (if `hasEditDialog: true`)
24
-
25
- ## Widget Extension Manifest
26
-
27
- The manifest defines widget metadata, appearance, and behavior:
28
-
29
- ```typescript
30
- import { WidgetExtensionManifest } from '@trackunit/iris-app-api';
31
-
32
- const widgetExtensionManifest: WidgetExtensionManifest = {
33
- id: "my-widget-id",
34
- type: "WIDGET_EXTENSION",
35
- sourceRoot: "libs/[feature]/[widget-name]/src",
36
-
37
- widgetType: "CHART", // Required: Widget classification
38
-
39
- size: {
40
- default: {
41
- width: 2, // 1-6 grid units
42
- height: 2, // 1-6 grid units
43
- },
44
- allowFullWidth: false, // Optional: Allow full-width expansion
45
- },
46
-
47
- header: {
48
- name: "My Widget", // Display name
49
- image: { name: "ChartBar" }, // Icon (IconByName or IconByPath)
50
- hasEditDialog: true, // Optional: Enable edit button
51
- },
52
-
53
- footer: { // Optional: Footer with link
54
- linkDescription: "View details",
55
- link: "/my-app/details",
56
- poweredByImage: { path: "/assets/logo.svg" },
57
- },
58
-
59
- preview: { // Optional: Description for widget drawer
60
- description: "Displays chart data for analysis",
61
- },
62
-
63
- supportedLocations: ["MY_HOME", "PLAYGROUND"],
64
-
65
- supportedFilters: { // Optional: Enable filter support
66
- TIME_RANGE: { include: ["ALL"] },
67
- ASSETS: { include: ["assetType", "brands", "models"] },
68
- CUSTOMERS: { include: ["customerType", "criticality"] },
69
- SITES: { include: ["siteType", "location"] },
70
- },
71
- };
72
-
73
- export default widgetExtensionManifest;
74
- ```
75
-
76
- ## Widget Types
77
-
78
- Available widget types that determine visual presentation:
79
-
80
- - **`"KPI"`** - Single metric displays (typically 1x1 size)
81
- - **`"CHART"`** - Data visualization widgets (charts, graphs)
82
- - **`"LIST"`** - Tabular or list-based data presentation
83
- - **`"MAP"`** - Geographic or spatial data visualization
84
- - **`"OTHER"`** - Custom or specialized widgets
85
-
86
- ## Supported Locations
87
-
88
- Widgets can be placed in these locations:
89
-
90
- - **`"MY_HOME"`** - User's personal dashboard
91
- - **`"SITE_HOME"`** - Site-specific dashboards
92
-
93
- ## Widget Development
94
-
95
- ### Basic Widget Component
96
-
97
- ```typescript
98
- import { useWidgetConfig } from '@trackunit/react-core-hooks';
99
-
100
- export const App = () => {
101
- const {
102
- data,
103
- setData,
104
- dataVersion,
105
- title,
106
- setTitle,
107
- filters,
108
- timeRange,
109
- isEditMode,
110
- openEditMode,
111
- closeEditMode
112
- pollInterval,
113
- setLoadingState
114
- } = useWidgetConfig();
115
-
116
- if (isEditMode) {
117
- return <EditDialog />;
118
- }
119
-
120
- return (
121
- <WidgetBody>
122
- <h2>{title}</h2>
123
- {/* Widget content */}
124
- </WidgetBody>
125
- );
126
- };
127
- ```
128
-
129
- ### Widget Configuration Hook
130
-
131
- The `useWidgetConfig()` hook provides:
132
-
133
- **Data Management:**
134
- - `data: Record<string, unknown>` - Widget configuration data
135
- - `setData: (data: Record<string, unknown>, version: number) => Promise<void>` - Update widget data
136
- - `dataVersion: number` - Current data version for migrations
137
-
138
- **Title Management:**
139
- - `title: string` - Widget title
140
- - `setTitle: (title: string) => Promise<void>` - Update widget title
141
-
142
- **Context Information:**
143
- - `filters: { assetsFilterBarValues, customersFilterBarValues, sitesFilterBarValues }` - Applied filters
144
- - `timeRange: { startMsInEpoch, endMsInEpoch }` - Selected time range
145
- - `isEditMode: boolean` - Whether widget is in edit mode
146
-
147
- **Edit Mode Control:**
148
- - `openEditMode: () => Promise<void>` - Enter edit mode
149
- - `closeEditMode: () => Promise<void>` - Exit edit mode
150
-
151
- ### Widget with Edit Dialog
152
-
153
- ```typescript
154
- import { useWidgetConfig } from '@trackunit/react-core-hooks';
155
- import { WidgetEditBody } from '@trackunit/react-widgets';
156
-
157
- export const App = () => {
158
- const { isEditMode, data, closeEditMode } = useWidgetConfig();
159
-
160
- if (isEditMode) {
161
- return (
162
- <WidgetEditBody
163
- onSave={async () => {
164
- await closeEditMode({ newData: { data: { demo: "youDataHere"}, dataVersion: 1 });
165
- }}
166
- onCancel={closeEditMode}
167
- initialData={data}
168
- />
169
- );
170
- }
171
-
172
- return <MainWidgetContent />;
173
- };
174
- ```
175
-
176
- ## Filter Support
177
-
178
- ### Supported Filter Types
179
-
180
- Configure which filters your widget responds to:
181
-
182
- ```typescript
183
- supportedFilters: {
184
- // Time range filtering
185
- TIME_RANGE: { include: ["ALL"] },
186
-
187
- // Asset filtering
188
- ASSETS: {
189
- include: [
190
- "assetType", "brands", "models", "types",
191
- "activity", "criticality", "lastSeen", "groups",
192
- "siteIds", "customerIds", "ownerAccountIds",
193
- // Add custom fields support
194
- ...allAssetFilterKeysWithCustomFields
195
- ]
196
- },
197
-
198
- // Customer filtering
199
- CUSTOMERS: {
200
- include: [
201
- "customerType", "criticality", "servicePlan",
202
- ...allCustomerFilterKeysWithCustomFields
203
- ]
204
- },
205
-
206
- // Site filtering
207
- SITES: {
208
- include: [
209
- "siteType", "location", "area",
210
- ...allSiteFilterKeysWithCustomFields
211
- ]
212
- },
213
- }
214
- ```
215
-
216
- ### Using Filters in Widgets
217
-
218
- ```typescript
219
- const { filters, timeRange } = useWidgetConfig();
220
-
221
- // Access filter values
222
- const selectedAssets = filters.assetsFilterBarValues?.assetType;
223
- const selectedCustomers = filters.customersFilterBarValues?.customerType;
224
- const selectedSites = filters.sitesFilterBarValues?.siteType;
225
-
226
- // Use time range
227
- const startTime = timeRange?.startMsInEpoch;
228
- const endTime = timeRange?.endMsInEpoch;
229
- ```
230
-
231
- ## Widget Lifecycle
232
-
233
- ### 1. Widget Creation
234
- - Generated via `@trackunit/iris-app:extend` command
235
- - Manifest defines widget metadata and capabilities
236
- - React component handles rendering and user interaction
237
-
238
- ### 2. Widget Registration
239
- - Widget appears in the widget drawer based on `supportedLocations`
240
- - Users can add widgets to their dashboards
241
- - Widget configuration is persisted automatically
242
-
243
- ### 3. Widget Runtime
244
- - Widget receives context (filters, time range, etc.)
245
- - Widget can store and retrieve configuration data
246
- - Widget responds to user interactions and filter changes
247
-
248
- ## Best Practices
249
-
250
- ### Widget Design
251
- 1. **Responsive Layout** - Design for different grid sizes
252
- 2. **Loading States** - Show loading indicators for async operations
253
- 3. **Error Handling** - Gracefully handle data loading errors
254
- 4. **Empty States** - Provide meaningful empty state messages
255
-
256
- ### Data Management
257
- 1. **Use Real Data** - Always fetch from Trackunit GraphQL API
258
- 2. **Respect Filters** - Apply user-selected filters to your data queries
259
- 3. **Efficient Updates** - Only update widget data when necessary
260
- 4. **Version Control** - Use `dataVersion` for configuration migrations
261
-
262
- ### Configuration
263
- 1. **Meaningful Defaults** - Provide sensible default configurations
264
- 2. **Validation** - Validate user input in edit dialogs
265
- 3. **Persistence** - Use `setData()` to save configuration changes
266
- 4. **User Experience** - Keep configuration UI simple and intuitive
267
-
268
- ## Example: KPI Widget
269
-
270
- ```typescript
271
- import { useWidgetConfig } from '@trackunit/react-core-hooks';
272
- import { useQuery } from '@trackunit/react-graphql-hooks';
273
-
274
- export const App = () => {
275
- const { filters, timeRange, data, pollInterval, setLoadingState} = useWidgetConfig();
276
-
277
- const { data: kpiData, loading } = useQuery(MY_KPI_QUERY, {
278
- variables: {
279
- filters: {
280
- assetIds: filters.assetsFilterBarValues?.assetIds,
281
- timeRange: {
282
- start: timeRange?.startMsInEpoch,
283
- end: timeRange?.endMsInEpoch,
284
- },
285
- },
286
- },
287
- pollInterval
288
- });
289
-
290
- useEffect(() => {
291
- void setLoadingState({ hasData: !!kpiData, isLoading: loading });
292
- }, [data, loading, setLoadingState]);
293
-
294
- return (
295
- <div className="kpi-widget">
296
- <div className="kpi-value">{kpiData?.totalCount}</div>
297
- <div className="kpi-label">Total Assets</div>
298
- </div>
299
- );
300
- };
301
- ```
302
-
303
- ## Common Patterns
304
-
305
- ### Chart Widget
306
- - Use `widgetType: "CHART"`
307
- - Implement responsive chart sizing
308
- - Support time range filtering
309
- - Show data trends and comparisons
310
-
311
- ### List Widget
312
- - Use `widgetType: "LIST"`
313
- - Implement pagination for large datasets
314
- - Support asset/customer filtering
315
- - Provide links to detailed views
316
-
317
- ### Map Widget
318
- - Use `widgetType: "MAP"`
319
- - Set `allowFullWidth: true` for better visibility
320
- - Support location-based filtering
321
- - Show asset positions and movement
322
-
323
- DO NOT use generic React widget libraries - always use the Trackunit IrisX App SDK widget patterns and components.