@trackunit/iris-app 1.4.33 → 1.4.34
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
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: *.graphql
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GraphQL Time Series API Usage
|
|
7
|
+
|
|
8
|
+
This rule covers how to query time series data through GraphQL in IrisX App SDK using PromQL (Prometheus Query Language).
|
|
9
|
+
|
|
10
|
+
## Query Structure
|
|
11
|
+
|
|
12
|
+
### Range Query (time series data)
|
|
13
|
+
```graphql
|
|
14
|
+
query GetTimeSeriesData($assetId: ID!, $start: DateTime!, $end: DateTime!, $step: Duration!) {
|
|
15
|
+
asset(id: $assetId) {
|
|
16
|
+
timeSeries {
|
|
17
|
+
rangeQuery(query: "metric_name", start: $start, end: $end, step: $step) {
|
|
18
|
+
data {
|
|
19
|
+
... on TimeSeriesMatrixData {
|
|
20
|
+
result {
|
|
21
|
+
values { timestamp value }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Instant Query (single point in time)
|
|
32
|
+
```graphql
|
|
33
|
+
query GetInstantData($assetId: ID!, $time: DateTime!) {
|
|
34
|
+
asset(id: $assetId) {
|
|
35
|
+
timeSeries {
|
|
36
|
+
instantQuery(query: "metric_name", time: $time) {
|
|
37
|
+
data {
|
|
38
|
+
... on TimeSeriesVectorData {
|
|
39
|
+
result { value { timestamp value } }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Common Metrics
|
|
49
|
+
|
|
50
|
+
### Machine Insights
|
|
51
|
+
- `machine_insight_cumulative_operating_hours` - Operating hours
|
|
52
|
+
- `machine_insight_cumulative_operating_hours_raw` - Raw operating hours
|
|
53
|
+
- `machine_insight_engine_total_fuel_used` - Fuel consumed
|
|
54
|
+
- `machine_insight_engine_total_idle_hours` - Idle hours
|
|
55
|
+
- `machine_insight_cumulative_distance_travelled` - Distance
|
|
56
|
+
- `machine_insight_cumulative_payload_total` - Payload
|
|
57
|
+
- `machine_insight_cumulative_moving_hours` - Moving hours
|
|
58
|
+
- `machine_insight_total_vehicle_distance` - Vehicle distance
|
|
59
|
+
- `machine_insight_total_vehicle_distance_raw` - Raw vehicle distance
|
|
60
|
+
- `machine_insight_speed` - Current speed
|
|
61
|
+
- `machine_insight_altitude` - Current altitude
|
|
62
|
+
- `machine_insight_engine_status` - Engine status
|
|
63
|
+
- `machine_insight_battery_potential` - Battery voltage
|
|
64
|
+
- `machine_insight_impact` - Impact detection
|
|
65
|
+
- `machine_insight_accelerometer_x_axis` - X-axis acceleration
|
|
66
|
+
- `machine_insight_accelerometer_y_axis` - Y-axis acceleration
|
|
67
|
+
- `machine_insight_accelerometer_z_axis` - Z-axis acceleration
|
|
68
|
+
|
|
69
|
+
### Advanced Sensors
|
|
70
|
+
- `advanced_sensor_run_1` - Run sensor 1
|
|
71
|
+
- `advanced_sensor_run_1_raw` - Raw run sensor 1
|
|
72
|
+
- `advanced_sensor_run_2` - Run sensor 2
|
|
73
|
+
- `advanced_sensor_run_2_raw` - Raw run sensor 2
|
|
74
|
+
- `advanced_sensor_run_4` - Run sensor 4
|
|
75
|
+
- `advanced_sensor_input_1` - Digital input 1
|
|
76
|
+
- `advanced_sensor_input_2` - Digital input 2
|
|
77
|
+
- `advanced_sensor_input_3` - Digital input 3
|
|
78
|
+
- `advanced_sensor_input_4` - Digital input 4
|
|
79
|
+
- `advanced_sensor_input_7` - Digital input 7
|
|
80
|
+
- `advanced_sensor_input_8` - Digital input 8
|
|
81
|
+
- `advanced_sensor_input_change_counter_1` - Input change counter 1
|
|
82
|
+
- `advanced_sensor_input_change_counter_2` - Input change counter 2
|
|
83
|
+
- `advanced_sensor_input_change_counter_3` - Input change counter 3
|
|
84
|
+
- `advanced_sensor_input_change_counter_4` - Input change counter 4
|
|
85
|
+
|
|
86
|
+
## PromQL Examples
|
|
87
|
+
|
|
88
|
+
### Calculate daily increases
|
|
89
|
+
```
|
|
90
|
+
query: "increase(machine_insight_cumulative_operating_hours[1d])"
|
|
91
|
+
step: "1d"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Filter with conditions
|
|
95
|
+
```
|
|
96
|
+
query: "increase(machine_insight_engine_total_fuel_used[1d]) > 13"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Combine metrics
|
|
100
|
+
```
|
|
101
|
+
query: "(increase(machine_insight_engine_total_fuel_used[1d]) > 13) and (increase(machine_insight_engine_total_idle_hours[1d]) > 4)"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Key Points
|
|
105
|
+
|
|
106
|
+
- **Always use fragments** for both `TimeSeriesMatrixData` and `TimeSeriesVectorData`
|
|
107
|
+
- **Use PromQL functions** like `increase()`, `rate()`, `avg_over_time()`
|
|
108
|
+
- **Filter at query level** with operators: `>`, `<`, `>=`, `<=`, `==`, `!=`
|
|
109
|
+
- **Time windows** use brackets: `[1d]`, `[1h]`, `[15m]`
|
|
110
|
+
- **Step intervals**: Choose based on data granularity needed
|
|
111
|
+
- **Timestamps** are Unix timestamps in seconds
|
|
112
|
+
- **Values** are returned as strings, convert to numbers as needed
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create filterable, sortable data tables using Trackunit's Table and FilterBar components with GraphQL pagination for asset lists, user management, dashboards, and reporting interfaces requiring interactive data presentation
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 📊 Trackunit Table with Filtering & Sorting
|
|
8
|
+
|
|
9
|
+
Create interactive data tables with server-side filtering, sorting, and pagination using Trackunit components and GraphQL.
|
|
10
|
+
|
|
11
|
+
## 🎯 When to Apply
|
|
12
|
+
- Building asset management interfaces
|
|
13
|
+
- Creating user administration tables
|
|
14
|
+
- Developing dashboard data grids
|
|
15
|
+
- Implementing reporting interfaces with large datasets
|
|
16
|
+
- Any UI requiring interactive table features (filter/sort/paginate)
|
|
17
|
+
|
|
18
|
+
## 🔧 Required Imports
|
|
19
|
+
```typescript
|
|
20
|
+
import { Table, useTable, TextCell, DateCell } from '@trackunit/react-table';
|
|
21
|
+
import { FilterBar, useFilterBar } from '@trackunit/filters-filter-bar';
|
|
22
|
+
import { usePaginationQuery } from '@trackunit/react-graphql-hooks';
|
|
23
|
+
import { createColumnHelper, SortingState } from '@tanstack/react-table';
|
|
24
|
+
import { useBrandFilter, useModelFilter } from '@trackunit/filters-asset-filters';
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## ✅ Valid Implementation
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
const AssetTable = () => {
|
|
31
|
+
// Setup filters with proper naming
|
|
32
|
+
const filterBar = useFilterBar({
|
|
33
|
+
name: "assetFilters",
|
|
34
|
+
filterBarDefinition: {
|
|
35
|
+
brand: useBrandFilter(),
|
|
36
|
+
model: useModelFilter()
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Server-side sorting state
|
|
41
|
+
const [sorting, setSorting] = useState<SortingState>([]);
|
|
42
|
+
|
|
43
|
+
// GraphQL query with filters
|
|
44
|
+
const { data, loading, error, pagination } = usePaginationQuery(GetAssetsDocument, {
|
|
45
|
+
variables: { first: 50, ...filterBar.selectedFilters },
|
|
46
|
+
pageSize: 50,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Transform data with useMemo
|
|
50
|
+
const assets = useMemo(() =>
|
|
51
|
+
data?.assets.edges.map(edge => ({ ...edge.node, id: edge.node.id })) ?? [],
|
|
52
|
+
[data]
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Define columns with proper cell components
|
|
56
|
+
const columns = useMemo(() => [
|
|
57
|
+
columnHelper.accessor('name', {
|
|
58
|
+
cell: ({ row: { original } }) => <TextCell text={original.name} />,
|
|
59
|
+
header: "Asset Name",
|
|
60
|
+
enableSorting: true,
|
|
61
|
+
}),
|
|
62
|
+
columnHelper.accessor('createdAt', {
|
|
63
|
+
cell: ({ row: { original } }) => <DateCell date={original.createdAt} />,
|
|
64
|
+
header: "Created",
|
|
65
|
+
enableSorting: true,
|
|
66
|
+
}),
|
|
67
|
+
], []);
|
|
68
|
+
|
|
69
|
+
// Setup table with manual sorting
|
|
70
|
+
const { table } = useTable({
|
|
71
|
+
data: assets,
|
|
72
|
+
columns,
|
|
73
|
+
enableSorting: true,
|
|
74
|
+
manualSorting: true,
|
|
75
|
+
state: { sorting },
|
|
76
|
+
onSortingChange: setSorting,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<>
|
|
81
|
+
<FilterBar filterBar={filterBar} />
|
|
82
|
+
<Table
|
|
83
|
+
table={table}
|
|
84
|
+
loading={loading}
|
|
85
|
+
error={error}
|
|
86
|
+
pagination={pagination}
|
|
87
|
+
onRowClick={(row) => navigateToAsset(row.original.id)}
|
|
88
|
+
/>
|
|
89
|
+
</>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## ❌ Invalid Implementation
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// DON'T: Missing useMemo optimization
|
|
98
|
+
const columns = [
|
|
99
|
+
columnHelper.accessor('name', {
|
|
100
|
+
cell: ({ getValue }) => getValue(), // Wrong: Use TextCell component
|
|
101
|
+
header: "Name"
|
|
102
|
+
})
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
// DON'T: Client-side sorting on large datasets
|
|
106
|
+
const { table } = useTable({
|
|
107
|
+
data: assets,
|
|
108
|
+
columns,
|
|
109
|
+
enableSorting: true,
|
|
110
|
+
manualSorting: false, // Wrong: Should be true for server-side
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// DON'T: Missing filter integration
|
|
114
|
+
const { data } = usePaginationQuery(GetAssetsDocument, {
|
|
115
|
+
variables: { first: 50 }, // Wrong: Missing filter variables
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// DON'T: No row click handler
|
|
119
|
+
<Table table={table} loading={loading} />
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 🎯 Key Requirements
|
|
123
|
+
|
|
124
|
+
- **Always use `useMemo`** for data transformation and column definitions
|
|
125
|
+
- **Enable `manualSorting: true`** for datasets > 1000 items
|
|
126
|
+
- **Integrate filter state** with GraphQL variables using spread operator
|
|
127
|
+
- **Use Trackunit cell components** (`TextCell`, `DateCell`) for consistency
|
|
128
|
+
- **Implement `onRowClick`** for navigation or detail views
|
|
129
|
+
- **Sync state properly** between filters, sorting, and GraphQL queries
|