@powerhousedao/academy 3.2.0-staging.0 → 3.2.0-staging.2
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
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## 3.2.0-staging.2 (2025-07-01)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- **reactor-api,reactor-local:** allow providing processors to be instantiated and enable drive analytics ([1a3800fc2](https://github.com/powerhouse-inc/powerhouse/commit/1a3800fc2))
|
|
6
|
+
|
|
7
|
+
### ❤️ Thank You
|
|
8
|
+
|
|
9
|
+
- acaldas @acaldas
|
|
10
|
+
|
|
11
|
+
## 3.2.0-staging.1 (2025-07-01)
|
|
12
|
+
|
|
13
|
+
### 🚀 Features
|
|
14
|
+
|
|
15
|
+
- **academy:** add Drive Analytics documentation and examples ([430ca8fab](https://github.com/powerhouse-inc/powerhouse/commit/430ca8fab))
|
|
16
|
+
- **connect:** use atom store and provider from state library ([d617a1fe2](https://github.com/powerhouse-inc/powerhouse/commit/d617a1fe2))
|
|
17
|
+
|
|
18
|
+
### ❤️ Thank You
|
|
19
|
+
|
|
20
|
+
- Guillermo Puente
|
|
21
|
+
- ryanwolhuter
|
|
22
|
+
|
|
1
23
|
## 3.2.0-staging.0 (2025-06-26)
|
|
2
24
|
|
|
3
25
|
This was a version bump only for @powerhousedao/academy to align it with other projects, there were no code changes.
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
# Drive Analytics
|
|
2
|
+
|
|
3
|
+
Drive Analytics provides automated monitoring and insights into document drive operations within Powerhouse applications. This system tracks user interactions, document modifications, and drive activity to help developers understand usage patterns and system performance.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Drive Analytics system consists of two specialized processors that automatically collect metrics from document drives:
|
|
8
|
+
|
|
9
|
+
1. **Drive Analytics Processor**: Tracks file and folder operations (creation, deletion, moves, etc.)
|
|
10
|
+
2. **Document Analytics Processor**: Tracks document content changes and state modifications
|
|
11
|
+
|
|
12
|
+
These processors run in the background, converting operations into structured time-series data that can be queried and visualized in real-time.
|
|
13
|
+
|
|
14
|
+
## Available Metrics in Connect
|
|
15
|
+
|
|
16
|
+
Connect applications have Drive Analytics enabled by default through the `ReactorAnalyticsProvider`. When enabled, the system automatically tracks:
|
|
17
|
+
|
|
18
|
+
### Drive Operations Metrics
|
|
19
|
+
- **File Creation**: New documents added to drives
|
|
20
|
+
- **Folder Creation**: New directories created
|
|
21
|
+
- **File Updates**: Document content modifications
|
|
22
|
+
- **Node Updates**: Metadata changes
|
|
23
|
+
- **File Moves**: Documents relocated between folders
|
|
24
|
+
- **File Copies**: Document duplication
|
|
25
|
+
- **File Deletions**: Documents removed from drives
|
|
26
|
+
|
|
27
|
+
### Document Operations Metrics
|
|
28
|
+
- **State Changes**: Document model state modifications
|
|
29
|
+
|
|
30
|
+
## Data Sources and Structure
|
|
31
|
+
|
|
32
|
+
Drive Analytics organizes data using hierarchical source paths that allow precise querying of different analytics contexts:
|
|
33
|
+
|
|
34
|
+
### Drive Analytics Sources
|
|
35
|
+
Pattern: `ph/drive/{driveId}/{branch}/{scope}`
|
|
36
|
+
- **driveId**: Unique identifier for the document drive
|
|
37
|
+
- **branch**: Branch name (e.g., "main", "dev")
|
|
38
|
+
- **scope**: Operation scope ("global" for shared operations, "local" for device-specific)
|
|
39
|
+
|
|
40
|
+
Example: `ph/drive/abc123/main/global`
|
|
41
|
+
|
|
42
|
+
### Document Analytics Sources
|
|
43
|
+
Pattern: `ph/doc/{driveId}/{documentId}/{branch}/{scope}`
|
|
44
|
+
- **driveId**: Drive containing the document
|
|
45
|
+
- **documentId**: Specific document identifier
|
|
46
|
+
- **branch**: Branch name
|
|
47
|
+
- **scope**: Operation scope
|
|
48
|
+
|
|
49
|
+
Example: `ph/doc/abc123/doc456/main/global`
|
|
50
|
+
|
|
51
|
+
## Available Metrics
|
|
52
|
+
|
|
53
|
+
### DriveOperations
|
|
54
|
+
Tracks file system operations within drives:
|
|
55
|
+
- **Value**: Always 1 (counter metric)
|
|
56
|
+
- **Purpose**: Count drive-level operations like file creation, deletion, moves
|
|
57
|
+
- **Source Pattern**: `ph/drive/*`
|
|
58
|
+
|
|
59
|
+
### DocumentOperations
|
|
60
|
+
Tracks document content and state changes:
|
|
61
|
+
- **Value**: Always 1 (counter metric)
|
|
62
|
+
- **Purpose**: Count document-specific operations like state changes
|
|
63
|
+
- **Source Pattern**: `ph/doc/*`
|
|
64
|
+
|
|
65
|
+
## Complete Dimensions Reference
|
|
66
|
+
|
|
67
|
+
### Drive Analytics Dimensions
|
|
68
|
+
|
|
69
|
+
#### 1. Drive Dimension
|
|
70
|
+
**Pattern**: `ph/drive/{driveId}/{branch}/{scope}/{revision}`
|
|
71
|
+
**Purpose**: Identifies the drive context with revision information
|
|
72
|
+
```tsx
|
|
73
|
+
// Examples
|
|
74
|
+
"ph/drive/abc123/main/global/42"
|
|
75
|
+
"ph/drive/my-drive/feature-branch/local/15"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### 2. Operation Dimension
|
|
79
|
+
**Pattern**: `ph/drive/operation/{operationType}/{operationIndex}`
|
|
80
|
+
**Purpose**: Identifies specific operation types and their sequence
|
|
81
|
+
|
|
82
|
+
**Available Operation Types**:
|
|
83
|
+
- **ADD_FILE**: Create new file
|
|
84
|
+
- **ADD_FOLDER**: Create new folder
|
|
85
|
+
- **UPDATE_FILE**: Modify file content
|
|
86
|
+
- **UPDATE_NODE**: Modify node metadata
|
|
87
|
+
- **MOVE_NODE**: Move file/folder to different location
|
|
88
|
+
- **COPY_NODE**: Duplicate existing file/folder
|
|
89
|
+
- **DELETE_NODE**: Remove file/folder
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
// Examples
|
|
93
|
+
"ph/drive/operation/ADD_FILE/5"
|
|
94
|
+
"ph/drive/operation/DELETE_NODE/23"
|
|
95
|
+
"ph/drive/operation/MOVE_NODE/12"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### 3. Target Dimension
|
|
99
|
+
**Pattern**: `ph/drive/target/{targetType}/{targetId}`
|
|
100
|
+
**Purpose**: Identifies what was targeted by the operation
|
|
101
|
+
|
|
102
|
+
**Target Types**:
|
|
103
|
+
- **DRIVE**: Operation affects the drive itself
|
|
104
|
+
- **NODE**: Operation affects a specific file/folder
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// Examples
|
|
108
|
+
"ph/drive/target/DRIVE/abc123"
|
|
109
|
+
"ph/drive/target/NODE/file456"
|
|
110
|
+
"ph/drive/target/NODE/folder789"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### 4. Action Type Dimension
|
|
114
|
+
**Pattern**: `ph/drive/actionType/{actionType}/{targetId}`
|
|
115
|
+
**Purpose**: Categorizes operations by their effect
|
|
116
|
+
|
|
117
|
+
**Action Types**:
|
|
118
|
+
- **CREATED**: New items added (ADD_FILE, ADD_FOLDER)
|
|
119
|
+
- **DUPLICATED**: Items copied (COPY_NODE)
|
|
120
|
+
- **UPDATED**: Existing items modified (UPDATE_FILE, UPDATE_NODE)
|
|
121
|
+
- **MOVED**: Items relocated (MOVE_NODE)
|
|
122
|
+
- **REMOVED**: Items deleted (DELETE_NODE)
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
// Examples
|
|
126
|
+
"ph/drive/actionType/CREATED/file123"
|
|
127
|
+
"ph/drive/actionType/MOVED/folder456"
|
|
128
|
+
"ph/drive/actionType/REMOVED/doc789"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Document Analytics Dimensions
|
|
132
|
+
|
|
133
|
+
#### 1. Drive Dimension
|
|
134
|
+
**Pattern**: `ph/doc/drive/{driveId}/{branch}/{scope}/{revision}`
|
|
135
|
+
**Purpose**: Drive context for document operations
|
|
136
|
+
```tsx
|
|
137
|
+
// Examples
|
|
138
|
+
"ph/doc/drive/abc123/main/global/42"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### 2. Operation Dimension
|
|
142
|
+
**Pattern**: `ph/doc/operation/{operationType}/{operationIndex}`
|
|
143
|
+
**Purpose**: Document-specific operation identification
|
|
144
|
+
```tsx
|
|
145
|
+
// Examples (document model operations vary by document type)
|
|
146
|
+
"ph/doc/operation/SET_STATE/15"
|
|
147
|
+
"ph/doc/operation/ADD_ITEM/8"
|
|
148
|
+
"ph/doc/operation/UPDATE_PROPERTY/22"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### 3. Target Dimension
|
|
152
|
+
**Pattern**: `ph/doc/target/{driveId}/{targetType}/{documentId}`
|
|
153
|
+
**Purpose**: Document target identification
|
|
154
|
+
|
|
155
|
+
**Target Types**:
|
|
156
|
+
- **DRIVE**: Document is the drive document itself (driveId === documentId)
|
|
157
|
+
- **NODE**: Document is a regular document within the drive
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
// Examples
|
|
161
|
+
"ph/doc/target/abc123/DRIVE/abc123" // Drive document
|
|
162
|
+
"ph/doc/target/abc123/NODE/doc456" // Regular document
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Query Parameters
|
|
166
|
+
|
|
167
|
+
### Time Range
|
|
168
|
+
- **start**: DateTime object for query start time
|
|
169
|
+
- **end**: DateTime object for query end time
|
|
170
|
+
- **granularity**: Time bucketing (Total, Hourly, Daily, Weekly, Monthly)
|
|
171
|
+
|
|
172
|
+
### Filtering with Select
|
|
173
|
+
|
|
174
|
+
Use the `select` parameter to filter by specific dimension values:
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
select: {
|
|
178
|
+
// Filter by specific drives
|
|
179
|
+
drive: [
|
|
180
|
+
AnalyticsPath.fromString("ph/drive/abc123"),
|
|
181
|
+
AnalyticsPath.fromString("ph/drive/xyz789")
|
|
182
|
+
],
|
|
183
|
+
|
|
184
|
+
// Filter by operation types
|
|
185
|
+
operation: [
|
|
186
|
+
AnalyticsPath.fromString("ph/drive/operation/ADD_FILE"),
|
|
187
|
+
AnalyticsPath.fromString("ph/drive/operation/UPDATE_FILE")
|
|
188
|
+
],
|
|
189
|
+
|
|
190
|
+
// Filter by action types
|
|
191
|
+
actionType: [
|
|
192
|
+
AnalyticsPath.fromString("ph/drive/actionType/CREATED"),
|
|
193
|
+
AnalyticsPath.fromString("ph/drive/actionType/UPDATED")
|
|
194
|
+
],
|
|
195
|
+
|
|
196
|
+
// Filter by targets
|
|
197
|
+
target: [
|
|
198
|
+
AnalyticsPath.fromString("ph/drive/target/NODE")
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Level of Detail (LOD)
|
|
204
|
+
|
|
205
|
+
Control how deeply dimensions are grouped:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
lod: {
|
|
209
|
+
drive: 1, // Group by drive only (ignore branch/scope/revision)
|
|
210
|
+
operation: 1, // Group by operation type only (ignore index)
|
|
211
|
+
actionType: 1, // Group by action type only (ignore target ID)
|
|
212
|
+
target: 1 // Group by target type only (ignore target ID)
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Querying Analytics Data
|
|
217
|
+
|
|
218
|
+
### Using the useAnalyticsQuery Hook
|
|
219
|
+
|
|
220
|
+
The primary way to access drive analytics is through the `useAnalyticsQuery` hook:
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
import { useAnalyticsQuery, AnalyticsGranularity, AnalyticsPath, DateTime } from '@powerhousedao/reactor-browser/analytics';
|
|
224
|
+
|
|
225
|
+
function DriveUsageChart({ driveId }: { driveId: string }) {
|
|
226
|
+
const { data, isLoading } = useAnalyticsQuery({
|
|
227
|
+
start: DateTime.now().minus({ days: 7 }),
|
|
228
|
+
end: DateTime.now(),
|
|
229
|
+
granularity: AnalyticsGranularity.Daily,
|
|
230
|
+
metrics: ["DriveOperations"],
|
|
231
|
+
select: {
|
|
232
|
+
drive: [AnalyticsPath.fromString(`ph/drive/${driveId}`)],
|
|
233
|
+
actionType: [
|
|
234
|
+
AnalyticsPath.fromString("ph/drive/actionType/CREATED"),
|
|
235
|
+
AnalyticsPath.fromString("ph/drive/actionType/UPDATED"),
|
|
236
|
+
AnalyticsPath.fromString("ph/drive/actionType/REMOVED")
|
|
237
|
+
]
|
|
238
|
+
},
|
|
239
|
+
lod: {
|
|
240
|
+
drive: 1,
|
|
241
|
+
actionType: 1
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
if (isLoading) return <div>Loading analytics...</div>;
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<div>
|
|
249
|
+
{/* Render your chart using the analytics data */}
|
|
250
|
+
{data?.rows.map(row => (
|
|
251
|
+
<div key={row.metric}>
|
|
252
|
+
{row.metric}: {row.value}
|
|
253
|
+
</div>
|
|
254
|
+
))}
|
|
255
|
+
</div>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Using the useDriveAnalytics Hook
|
|
261
|
+
|
|
262
|
+
For common drive analytics queries, use the specialized `useDriveAnalytics` hook:
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
import { useDriveAnalytics } from '@powerhousedao/common/drive-analytics';
|
|
266
|
+
import { AnalyticsGranularity } from '@powerhousedao/reactor-browser/analytics';
|
|
267
|
+
|
|
268
|
+
function DriveInsights({ driveIds }: { driveIds: string[] }) {
|
|
269
|
+
const analytics = useDriveAnalytics({
|
|
270
|
+
filters: {
|
|
271
|
+
driveId: driveIds,
|
|
272
|
+
operation: ["ADD_FILE", "UPDATE_FILE", "DELETE_NODE"],
|
|
273
|
+
actionType: ["CREATED", "UPDATED", "REMOVED"]
|
|
274
|
+
},
|
|
275
|
+
from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(), // 7 days ago
|
|
276
|
+
to: new Date().toISOString(),
|
|
277
|
+
granularity: AnalyticsGranularity.Daily,
|
|
278
|
+
levelOfDetail: { drive: 1, operation: 1 }
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
if (analytics.isLoading) return <div>Loading...</div>;
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
<div>
|
|
285
|
+
<h3>Drive Activity Summary</h3>
|
|
286
|
+
{analytics.data?.rows.map((row, index) => (
|
|
287
|
+
<div key={index}>
|
|
288
|
+
<strong>{row.dimensions.find(d => d.name === 'actionType')?.path}</strong>: {row.value}
|
|
289
|
+
</div>
|
|
290
|
+
))}
|
|
291
|
+
</div>
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Using the useDocumentAnalytics Hook
|
|
297
|
+
|
|
298
|
+
For document-specific analytics queries, use the `useDocumentAnalytics` hook:
|
|
299
|
+
|
|
300
|
+
```tsx
|
|
301
|
+
import { useDocumentAnalytics } from '@powerhousedao/common/drive-analytics';
|
|
302
|
+
import { AnalyticsGranularity } from '@powerhousedao/reactor-browser/analytics';
|
|
303
|
+
|
|
304
|
+
function DocumentInsights({ driveId, documentIds }: { driveId: string, documentIds: string[] }) {
|
|
305
|
+
const analytics = useDocumentAnalytics({
|
|
306
|
+
filters: {
|
|
307
|
+
driveId: [driveId],
|
|
308
|
+
documentId: documentIds,
|
|
309
|
+
target: ["NODE"], // Focus on document nodes vs drive documents
|
|
310
|
+
branch: ["main"],
|
|
311
|
+
scope: ["global"]
|
|
312
|
+
},
|
|
313
|
+
from: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), // 24 hours ago
|
|
314
|
+
to: new Date().toISOString(),
|
|
315
|
+
granularity: AnalyticsGranularity.Hourly,
|
|
316
|
+
levelOfDetail: {
|
|
317
|
+
drive: 1,
|
|
318
|
+
operation: 1,
|
|
319
|
+
target: 1
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
if (analytics.isLoading) return <div>Loading...</div>;
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<div>
|
|
327
|
+
<h3>Document Activity Summary</h3>
|
|
328
|
+
{analytics.data?.rows.map((row, index) => (
|
|
329
|
+
<div key={index}>
|
|
330
|
+
Document Operations: {row.value}
|
|
331
|
+
</div>
|
|
332
|
+
))}
|
|
333
|
+
</div>
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Advanced Query Examples
|
|
339
|
+
|
|
340
|
+
### Filter by Multiple Criteria
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
// Get file creations and updates for specific drives in the last 24 hours
|
|
344
|
+
const { data } = useAnalyticsQuery({
|
|
345
|
+
start: DateTime.now().minus({ hours: 24 }),
|
|
346
|
+
end: DateTime.now(),
|
|
347
|
+
granularity: AnalyticsGranularity.Hourly,
|
|
348
|
+
metrics: ["DriveOperations"],
|
|
349
|
+
select: {
|
|
350
|
+
drive: [
|
|
351
|
+
AnalyticsPath.fromString("ph/drive/project-a"),
|
|
352
|
+
AnalyticsPath.fromString("ph/drive/project-b")
|
|
353
|
+
],
|
|
354
|
+
operation: [
|
|
355
|
+
AnalyticsPath.fromString("ph/drive/operation/ADD_FILE"),
|
|
356
|
+
AnalyticsPath.fromString("ph/drive/operation/UPDATE_FILE")
|
|
357
|
+
],
|
|
358
|
+
target: [
|
|
359
|
+
AnalyticsPath.fromString("ph/drive/target/NODE")
|
|
360
|
+
]
|
|
361
|
+
},
|
|
362
|
+
lod: {
|
|
363
|
+
drive: 1,
|
|
364
|
+
operation: 1
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Compare Document vs Drive Operations
|
|
370
|
+
|
|
371
|
+
```tsx
|
|
372
|
+
// Using the specialized hooks for easier comparison
|
|
373
|
+
const driveOps = useDriveAnalytics({
|
|
374
|
+
filters: { driveId: [driveId] },
|
|
375
|
+
from: DateTime.now().minus({ days: 1 }).toISO(),
|
|
376
|
+
to: DateTime.now().toISO(),
|
|
377
|
+
granularity: AnalyticsGranularity.Total
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
const docOps = useDocumentAnalytics({
|
|
381
|
+
filters: { driveId: [driveId] },
|
|
382
|
+
from: DateTime.now().minus({ days: 1 }).toISO(),
|
|
383
|
+
to: DateTime.now().toISO(),
|
|
384
|
+
granularity: AnalyticsGranularity.Total
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Or using useAnalyticsQuery directly
|
|
388
|
+
const driveOpsQuery = useAnalyticsQuery({
|
|
389
|
+
start: DateTime.now().minus({ days: 1 }),
|
|
390
|
+
end: DateTime.now(),
|
|
391
|
+
granularity: AnalyticsGranularity.Total,
|
|
392
|
+
metrics: ["DriveOperations"],
|
|
393
|
+
select: {
|
|
394
|
+
drive: [AnalyticsPath.fromString(`ph/drive/${driveId}`)]
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
const docOpsQuery = useAnalyticsQuery({
|
|
399
|
+
start: DateTime.now().minus({ days: 1 }),
|
|
400
|
+
end: DateTime.now(),
|
|
401
|
+
granularity: AnalyticsGranularity.Total,
|
|
402
|
+
metrics: ["DocumentOperations"],
|
|
403
|
+
select: {
|
|
404
|
+
drive: [AnalyticsPath.fromString(`ph/doc/drive/${driveId}`)]
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Real-time Activity Monitoring
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
// Monitor specific drive for real-time updates
|
|
413
|
+
const { data } = useAnalyticsQuery(
|
|
414
|
+
{
|
|
415
|
+
start: DateTime.now().minus({ minutes: 10 }),
|
|
416
|
+
end: DateTime.now(),
|
|
417
|
+
granularity: AnalyticsGranularity.Total,
|
|
418
|
+
metrics: ["DriveOperations"],
|
|
419
|
+
select: {
|
|
420
|
+
drive: [AnalyticsPath.fromString(`ph/drive/${driveId}`)]
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
sources: [AnalyticsPath.fromString(`ph/drive/${driveId}`)],
|
|
425
|
+
refetchInterval: 5000 // Poll every 5 seconds
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Real-time Updates
|
|
431
|
+
|
|
432
|
+
Analytics queries can automatically update when new data is available by specifying sources:
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
const { data } = useAnalyticsQuery(
|
|
436
|
+
{
|
|
437
|
+
start: DateTime.now().minus({ hours: 1 }),
|
|
438
|
+
end: DateTime.now(),
|
|
439
|
+
granularity: AnalyticsGranularity.Total,
|
|
440
|
+
metrics: ["DriveOperations"]
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
sources: [AnalyticsPath.fromString(`ph/drive/${driveId}`)]
|
|
444
|
+
}
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
// This query will automatically refetch when new operations occur in the specified drive
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
## Configuration in Connect
|
|
452
|
+
|
|
453
|
+
Drive Analytics is automatically enabled in Connect applications through feature flags:
|
|
454
|
+
|
|
455
|
+
```tsx
|
|
456
|
+
// In apps/connect/src/context/reactor-analytics.tsx
|
|
457
|
+
export function ReactorAnalyticsProvider({ children }: PropsWithChildren) {
|
|
458
|
+
return (
|
|
459
|
+
<AnalyticsProvider options={{ databaseName: "connect:analytics" }}>
|
|
460
|
+
{connectConfig.analytics.driveAnalyticsEnabled && (
|
|
461
|
+
<DriveAnalyticsProcessor />
|
|
462
|
+
)}
|
|
463
|
+
{children}
|
|
464
|
+
</AnalyticsProvider>
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
```
|