@trackunit/iris-app 1.12.9 → 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 (41) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +1 -1
  3. package/src/executors/submit/executor.js.map +1 -0
  4. package/src/executors/unpublish/executor.js.map +1 -0
  5. package/src/executors/utils/authentication.js.map +1 -0
  6. package/src/executors/utils/irisAppServerSettings.js.map +1 -0
  7. package/src/executors/utils/src/index.js.map +1 -0
  8. package/src/generators/ai-agent-sync/README.md +5 -2
  9. package/src/generators/ai-agent-sync/generator.d.ts +1 -1
  10. package/src/generators/ai-agent-sync/generator.js +29 -4
  11. package/src/generators/ai-agent-sync/generator.js.map +1 -0
  12. package/src/generators/create/generator.js.map +1 -0
  13. package/src/generators/extend/dependencies.js.map +1 -0
  14. package/src/generators/extend/generator.js.map +1 -0
  15. package/src/generators/preset/files/.agents/skills/browser-testing/SKILL.md +193 -0
  16. package/src/generators/preset/files/.agents/skills/create-app/SKILL.md +191 -0
  17. package/src/generators/preset/files/.agents/skills/customfields/SKILL.md +239 -0
  18. package/src/generators/preset/files/.agents/skills/graphql/SKILL.md +147 -0
  19. package/src/generators/preset/files/.agents/skills/graphql-timeseries/SKILL.md +193 -0
  20. package/src/generators/preset/files/.agents/skills/irisx-app-sdk/SKILL.md +116 -0
  21. package/src/generators/preset/files/.agents/skills/react-core-hooks/SKILL.md +215 -0
  22. package/src/generators/preset/files/.agents/skills/tables-and-sorting/SKILL.md +122 -0
  23. package/src/generators/preset/files/.agents/skills/widget-extensions/SKILL.md +245 -0
  24. package/src/generators/preset/files/.cursor/mcp.json +4 -0
  25. package/src/generators/preset/generator.js.map +1 -0
  26. package/src/generators/preset/root-files/AGENTS.md +43 -0
  27. package/src/generators/preset/root-files/CLAUDE.md +17 -0
  28. package/src/index.js.map +1 -0
  29. package/src/utils/ast/astUtils.js.map +1 -0
  30. package/src/utils/fileUpdater.js.map +1 -0
  31. package/src/generators/preset/files/.cursor/commands/create-app.md +0 -226
  32. package/src/generators/preset/files/.cursor/rules/browser-irisx-development.mdc +0 -246
  33. package/src/generators/preset/files/.cursor/rules/graphql-timeseries.md +0 -260
  34. package/src/generators/preset/files/.cursor/rules/irisx-app-sdk-customfields.md +0 -305
  35. package/src/generators/preset/files/.cursor/rules/irisx-app-sdk-graphql.md +0 -30
  36. package/src/generators/preset/files/.cursor/rules/irisx-app-sdk.mdc +0 -82
  37. package/src/generators/preset/files/.cursor/rules/react-core-hooks.md +0 -155
  38. package/src/generators/preset/files/.cursor/rules/rules-index.mdc +0 -10
  39. package/src/generators/preset/files/.cursor/rules/structured-development.mdc +0 -86
  40. package/src/generators/preset/files/.cursor/rules/tables-and-sorting.mdc +0 -126
  41. package/src/generators/preset/files/.cursor/rules/widget-extensions.md +0 -323
@@ -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.