een-api-toolkit 0.3.14 → 0.3.16
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 +10 -40
- package/README.md +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +825 -0
- package/dist/index.js +489 -254
- package/dist/index.js.map +1 -1
- package/docs/AI-CONTEXT.md +314 -2
- package/examples/vue-alerts-metrics/README.md +136 -0
- package/examples/vue-alerts-metrics/e2e/app.spec.ts +74 -0
- package/examples/vue-alerts-metrics/e2e/auth.spec.ts +561 -0
- package/examples/vue-alerts-metrics/index.html +13 -0
- package/examples/vue-alerts-metrics/package-lock.json +1756 -0
- package/examples/vue-alerts-metrics/package.json +31 -0
- package/examples/vue-alerts-metrics/playwright.config.ts +46 -0
- package/examples/vue-alerts-metrics/src/App.vue +108 -0
- package/examples/vue-alerts-metrics/src/components/AlertsList.vue +881 -0
- package/examples/vue-alerts-metrics/src/components/CameraSelector.vue +106 -0
- package/examples/vue-alerts-metrics/src/components/MetricsChart.vue +336 -0
- package/examples/vue-alerts-metrics/src/components/NotificationsList.vue +825 -0
- package/examples/vue-alerts-metrics/src/components/TimeRangeSelector.vue +259 -0
- package/examples/vue-alerts-metrics/src/composables/useHlsPlayer.ts +285 -0
- package/examples/vue-alerts-metrics/src/main.ts +23 -0
- package/examples/vue-alerts-metrics/src/router/index.ts +61 -0
- package/examples/vue-alerts-metrics/src/views/Callback.vue +76 -0
- package/examples/vue-alerts-metrics/src/views/Dashboard.vue +174 -0
- package/examples/vue-alerts-metrics/src/views/Home.vue +216 -0
- package/examples/vue-alerts-metrics/src/views/Login.vue +33 -0
- package/examples/vue-alerts-metrics/src/views/Logout.vue +66 -0
- package/examples/vue-alerts-metrics/src/vite-env.d.ts +12 -0
- package/examples/vue-alerts-metrics/tsconfig.json +21 -0
- package/examples/vue-alerts-metrics/tsconfig.node.json +10 -0
- package/examples/vue-alerts-metrics/vite.config.ts +12 -0
- package/package.json +1 -1
package/docs/AI-CONTEXT.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# EEN API Toolkit - AI Reference
|
|
2
2
|
|
|
3
|
-
> **Version:** 0.3.
|
|
3
|
+
> **Version:** 0.3.16
|
|
4
4
|
>
|
|
5
5
|
> This file is optimized for AI assistants. It contains all API signatures,
|
|
6
6
|
> types, and usage patterns in a single, parseable document.
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
> **Working Examples:** The installed package includes complete Vue 3 example applications
|
|
12
12
|
> at `./node_modules/een-api-toolkit/examples/`. These demonstrate OAuth authentication,
|
|
13
|
-
> user management, camera listing, live/recorded media, video feeds, and
|
|
13
|
+
> user management, camera listing, live/recorded media, video feeds, events, and metrics.
|
|
14
14
|
> For Live Main Video streaming, see `vue-feeds/src/views/Feeds.vue`.
|
|
15
15
|
> For Events API with thumbnails, see `vue-events/src/components/EventsModal.vue`.
|
|
16
|
+
> For Event Metrics with Chart.js visualization, see `vue-alerts-metrics/src/components/MetricsChart.vue`.
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
@@ -212,6 +213,7 @@ Complete Vue 3 applications demonstrating toolkit features:
|
|
|
212
213
|
| [vue-media](../examples/vue-media/) | Live and recorded image viewing | `src/views/LiveCamera.vue`, `RecordedImage.vue`, `HLS.vue` |
|
|
213
214
|
| [vue-feeds](../examples/vue-feeds/) | Live video streaming (preview and main) | `src/views/Feeds.vue` |
|
|
214
215
|
| [vue-events](../examples/vue-events/) | Events with bounding box overlays | `src/components/EventsModal.vue` |
|
|
216
|
+
| [vue-alerts-metrics](../examples/vue-alerts-metrics/) | Event metrics, alerts, and notifications | `src/components/MetricsChart.vue`, `AlertsList.vue` |
|
|
215
217
|
|
|
216
218
|
### Configuration
|
|
217
219
|
|
|
@@ -270,6 +272,33 @@ Complete Vue 3 applications demonstrating toolkit features:
|
|
|
270
272
|
| `listEventTypes(params?)` | List all available event types | `Result<PaginatedResult<EventType>>` |
|
|
271
273
|
| `listEventFieldValues(params)` | Get available event types for a device | `Result<EventFieldValues>` |
|
|
272
274
|
|
|
275
|
+
### Event Metrics Functions
|
|
276
|
+
|
|
277
|
+
| Function | Purpose | Returns |
|
|
278
|
+
|----------|---------|---------|
|
|
279
|
+
| `getEventMetrics(params)` | Get event count metrics over time | `Result<EventMetric[]>` |
|
|
280
|
+
|
|
281
|
+
### Alerts Functions
|
|
282
|
+
|
|
283
|
+
| Function | Purpose | Returns |
|
|
284
|
+
|----------|---------|---------|
|
|
285
|
+
| `listAlerts(params?)` | List alerts with filters | `Result<PaginatedResult<Alert>>` |
|
|
286
|
+
| `getAlert(id, params?)` | Get a specific alert by ID | `Result<Alert>` |
|
|
287
|
+
| `listAlertTypes(params?)` | List all available alert types | `Result<PaginatedResult<AlertType>>` |
|
|
288
|
+
|
|
289
|
+
### Notifications Functions
|
|
290
|
+
|
|
291
|
+
| Function | Purpose | Returns |
|
|
292
|
+
|----------|---------|---------|
|
|
293
|
+
| `listNotifications(params?)` | List notifications with filters | `Result<PaginatedResult<Notification>>` |
|
|
294
|
+
| `getNotification(id)` | Get a specific notification by ID | `Result<Notification>` |
|
|
295
|
+
|
|
296
|
+
### Utility Functions
|
|
297
|
+
|
|
298
|
+
| Function | Purpose | Returns |
|
|
299
|
+
|----------|---------|---------|
|
|
300
|
+
| `formatTimestamp(timestamp)` | Convert ISO timestamp from Z to +00:00 format (required by EEN API) | `string` |
|
|
301
|
+
|
|
273
302
|
---
|
|
274
303
|
|
|
275
304
|
## Core Types
|
|
@@ -741,6 +770,163 @@ interface ListEventFieldValuesParams {
|
|
|
741
770
|
}
|
|
742
771
|
```
|
|
743
772
|
|
|
773
|
+
### Event Metrics Types
|
|
774
|
+
|
|
775
|
+
```typescript
|
|
776
|
+
type MetricActorType = 'bridge' | 'camera' | 'speaker' | 'account' | 'user' | 'layout' | 'job'
|
|
777
|
+
|
|
778
|
+
// Data point: [timestamp_ms, value]
|
|
779
|
+
type MetricDataPoint = [number, number]
|
|
780
|
+
|
|
781
|
+
interface EventMetric {
|
|
782
|
+
eventType: string
|
|
783
|
+
actorId: string
|
|
784
|
+
actorType: MetricActorType
|
|
785
|
+
target: string // e.g., 'count'
|
|
786
|
+
dataPoints: MetricDataPoint[]
|
|
787
|
+
[key: string]: unknown // Additional properties
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
interface GetEventMetricsParams {
|
|
791
|
+
actor: string // Required: 'camera:{id}' format
|
|
792
|
+
eventType: string // Required: e.g., 'een.motionDetectionEvent.v1'
|
|
793
|
+
timestamp__gte?: string // Optional: defaults to 7 days ago
|
|
794
|
+
timestamp__lte?: string // Optional: defaults to now
|
|
795
|
+
aggregateByMinutes?: number // Optional: default 60, minimum 60
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
### Alert Types
|
|
800
|
+
|
|
801
|
+
```typescript
|
|
802
|
+
interface AlertAction {
|
|
803
|
+
name: string
|
|
804
|
+
type: string
|
|
805
|
+
success: boolean
|
|
806
|
+
timestamp: string
|
|
807
|
+
status?: 'fired' | 'success' | 'partialSuccess' | 'silenced' | 'failed' | 'internalError'
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
interface Alert {
|
|
811
|
+
id: string
|
|
812
|
+
timestamp: string
|
|
813
|
+
createTimestamp: string
|
|
814
|
+
creatorId: string
|
|
815
|
+
alertType: string
|
|
816
|
+
alertName?: string
|
|
817
|
+
category?: string
|
|
818
|
+
serviceRuleId?: string
|
|
819
|
+
eventType?: string
|
|
820
|
+
actorId: string
|
|
821
|
+
actorType: string
|
|
822
|
+
actorAccountId: string
|
|
823
|
+
actorName?: string
|
|
824
|
+
ruleId?: string
|
|
825
|
+
eventId?: string
|
|
826
|
+
locationId?: string
|
|
827
|
+
locationName?: string
|
|
828
|
+
priority?: number // 0-20
|
|
829
|
+
dataSchemas?: string[]
|
|
830
|
+
data?: Record<string, unknown>
|
|
831
|
+
actions?: Record<string, AlertAction>
|
|
832
|
+
description?: string
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
interface AlertType {
|
|
836
|
+
type: string
|
|
837
|
+
description: string
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
type AlertInclude = 'data' | 'actions' | 'dataSchemas' | 'description'
|
|
841
|
+
type AlertSort = '+timestamp' | '-timestamp'
|
|
842
|
+
type AlertActionStatus = 'fired' | 'success' | 'partialSuccess' | 'silenced' | 'failed' | 'internalError'
|
|
843
|
+
|
|
844
|
+
interface ListAlertsParams {
|
|
845
|
+
pageSize?: number
|
|
846
|
+
pageToken?: string
|
|
847
|
+
timestamp__lte?: string
|
|
848
|
+
timestamp__gte?: string
|
|
849
|
+
creatorId?: string
|
|
850
|
+
alertType__in?: string[]
|
|
851
|
+
actorId__in?: string[]
|
|
852
|
+
actorType__in?: string[]
|
|
853
|
+
actorAccountId?: string
|
|
854
|
+
ruleId?: string
|
|
855
|
+
ruleId__in?: string[]
|
|
856
|
+
eventId?: string
|
|
857
|
+
locationId__in?: string[]
|
|
858
|
+
priority__gte?: number
|
|
859
|
+
priority__lte?: number
|
|
860
|
+
showInvalidAlerts?: boolean
|
|
861
|
+
alertActionId__in?: string[]
|
|
862
|
+
alertActionStatus__in?: AlertActionStatus[]
|
|
863
|
+
include?: AlertInclude[]
|
|
864
|
+
sort?: AlertSort[]
|
|
865
|
+
language?: string
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
interface GetAlertParams {
|
|
869
|
+
include?: AlertInclude[]
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
interface ListAlertTypesParams {
|
|
873
|
+
pageSize?: number
|
|
874
|
+
pageToken?: string
|
|
875
|
+
}
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
### Notification Types
|
|
879
|
+
|
|
880
|
+
```typescript
|
|
881
|
+
type NotificationCategory = 'health' | 'video' | 'operational' | 'audit' | 'job' | 'security' | 'sharing'
|
|
882
|
+
|
|
883
|
+
type NotificationStatus =
|
|
884
|
+
| 'pending' | 'bounced' | 'dropped' | 'deferred' | 'delivered' | 'sent'
|
|
885
|
+
| 'outsideUsersSchedule' | 'notificationsDisabled' | 'noNotificationActions'
|
|
886
|
+
| 'sendingFailed' | 'throttled' | 'unableToGetSettings'
|
|
887
|
+
|
|
888
|
+
interface Notification {
|
|
889
|
+
id: string
|
|
890
|
+
timestamp: string
|
|
891
|
+
createTimestamp: string
|
|
892
|
+
sentTimestamp?: string
|
|
893
|
+
alertId?: string | null
|
|
894
|
+
alertType?: string
|
|
895
|
+
actorId: string
|
|
896
|
+
actorName?: string
|
|
897
|
+
actorType: string
|
|
898
|
+
actorAccountId: string
|
|
899
|
+
userId: string
|
|
900
|
+
accountId: string
|
|
901
|
+
read: boolean
|
|
902
|
+
status: NotificationStatus
|
|
903
|
+
category: NotificationCategory
|
|
904
|
+
description?: string
|
|
905
|
+
notificationActions: string[]
|
|
906
|
+
dataSchemas: string[]
|
|
907
|
+
data: Record<string, unknown>
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
interface ListNotificationsParams {
|
|
911
|
+
pageSize?: number
|
|
912
|
+
pageToken?: string
|
|
913
|
+
timestamp__lte?: string
|
|
914
|
+
timestamp__gte?: string
|
|
915
|
+
alertId?: string
|
|
916
|
+
alertType?: string
|
|
917
|
+
actorId?: string
|
|
918
|
+
actorType?: string
|
|
919
|
+
actorAccountId?: string
|
|
920
|
+
category?: NotificationCategory
|
|
921
|
+
userId?: string
|
|
922
|
+
read?: boolean
|
|
923
|
+
status?: NotificationStatus
|
|
924
|
+
includeV1Notifications?: boolean
|
|
925
|
+
sort?: ('+timestamp' | '-timestamp')[]
|
|
926
|
+
language?: string
|
|
927
|
+
}
|
|
928
|
+
```
|
|
929
|
+
|
|
744
930
|
---
|
|
745
931
|
|
|
746
932
|
## API Reference
|
|
@@ -1095,6 +1281,40 @@ console.log('Session URL:', data.url)
|
|
|
1095
1281
|
|
|
1096
1282
|
---
|
|
1097
1283
|
|
|
1284
|
+
## Utilities
|
|
1285
|
+
|
|
1286
|
+
### formatTimestamp
|
|
1287
|
+
|
|
1288
|
+
Converts ISO 8601 timestamps from `Z` (Zulu/UTC) format to `+00:00` format, as required by the EEN API.
|
|
1289
|
+
|
|
1290
|
+
**Why this is needed:** JavaScript's `Date.toISOString()` returns timestamps with a `Z` suffix (e.g., `2025-01-15T22:30:00.000Z`), but the EEN API requires the `+00:00` format (e.g., `2025-01-15T22:30:00.000+00:00`).
|
|
1291
|
+
|
|
1292
|
+
```typescript
|
|
1293
|
+
import { formatTimestamp } from 'een-api-toolkit'
|
|
1294
|
+
|
|
1295
|
+
// Convert Z format to +00:00 format
|
|
1296
|
+
formatTimestamp('2025-01-15T22:30:00.000Z')
|
|
1297
|
+
// Returns: '2025-01-15T22:30:00.000+00:00'
|
|
1298
|
+
|
|
1299
|
+
// Already in +00:00 format - returns unchanged
|
|
1300
|
+
formatTimestamp('2025-01-15T22:30:00.000+00:00')
|
|
1301
|
+
// Returns: '2025-01-15T22:30:00.000+00:00'
|
|
1302
|
+
|
|
1303
|
+
// Common usage with Date objects
|
|
1304
|
+
const now = new Date()
|
|
1305
|
+
const apiTimestamp = formatTimestamp(now.toISOString())
|
|
1306
|
+
// Returns timestamp in EEN API format
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
**When to use:**
|
|
1310
|
+
- When displaying timestamps that match the exact format used in API calls (e.g., for debugging)
|
|
1311
|
+
- When making direct API calls outside of the toolkit
|
|
1312
|
+
- When building custom timestamp display components
|
|
1313
|
+
|
|
1314
|
+
**Note:** The toolkit's API functions (`listAlerts`, `getEventMetrics`, `listNotifications`, `listEvents`, etc.) automatically apply `formatTimestamp` internally, so you don't need to pre-format timestamps when using these functions.
|
|
1315
|
+
|
|
1316
|
+
---
|
|
1317
|
+
|
|
1098
1318
|
## Live Video Streaming
|
|
1099
1319
|
|
|
1100
1320
|
The EEN API Toolkit supports two methods for displaying live video from cameras:
|
|
@@ -1345,6 +1565,98 @@ video {
|
|
|
1345
1565
|
|
|
1346
1566
|
---
|
|
1347
1567
|
|
|
1568
|
+
## HLS Video Playback Troubleshooting
|
|
1569
|
+
|
|
1570
|
+
For detailed troubleshooting, see the [HLS Video Troubleshooting Guide](./guides/HLS-VIDEO-TROUBLESHOOTING.md).
|
|
1571
|
+
|
|
1572
|
+
### Overview
|
|
1573
|
+
|
|
1574
|
+
HLS video playback from the EEN API requires:
|
|
1575
|
+
|
|
1576
|
+
1. **Initialize media session** - `initMediaSession()`
|
|
1577
|
+
2. **Find recording intervals** - `listMedia()` with `include: ['hlsUrl']`
|
|
1578
|
+
3. **Extract HLS URL** - From interval containing target timestamp
|
|
1579
|
+
4. **Configure HLS.js with auth** - Bearer token in Authorization header
|
|
1580
|
+
|
|
1581
|
+
### Key Requirements
|
|
1582
|
+
|
|
1583
|
+
| Requirement | Details |
|
|
1584
|
+
|-------------|---------|
|
|
1585
|
+
| Feed Type | HLS only available for `main` feeds, not `preview` |
|
|
1586
|
+
| Timestamp Format | Use `formatTimestamp()` to convert `Z` to `+00:00` |
|
|
1587
|
+
| Authentication | HLS.js requires `xhr.setRequestHeader('Authorization', `Bearer ${token}`)` |
|
|
1588
|
+
| Recording Coverage | Target timestamp must fall within a recording interval |
|
|
1589
|
+
|
|
1590
|
+
### Common Issues
|
|
1591
|
+
|
|
1592
|
+
#### 401 Unauthorized
|
|
1593
|
+
|
|
1594
|
+
**Cause:** Using `withCredentials: true` instead of Authorization header.
|
|
1595
|
+
|
|
1596
|
+
```typescript
|
|
1597
|
+
// WRONG
|
|
1598
|
+
const hls = new Hls({
|
|
1599
|
+
xhrSetup: (xhr) => { xhr.withCredentials = true }
|
|
1600
|
+
})
|
|
1601
|
+
|
|
1602
|
+
// CORRECT
|
|
1603
|
+
import { useAuthStore } from 'een-api-toolkit'
|
|
1604
|
+
const authStore = useAuthStore()
|
|
1605
|
+
|
|
1606
|
+
const hls = new Hls({
|
|
1607
|
+
xhrSetup: (xhr) => {
|
|
1608
|
+
xhr.setRequestHeader('Authorization', `Bearer ${authStore.token}`)
|
|
1609
|
+
}
|
|
1610
|
+
})
|
|
1611
|
+
```
|
|
1612
|
+
|
|
1613
|
+
#### No Video Available for Timestamp
|
|
1614
|
+
|
|
1615
|
+
**Cause:** Search range too narrow or using wrong feed type.
|
|
1616
|
+
|
|
1617
|
+
```typescript
|
|
1618
|
+
import { listMedia, formatTimestamp } from 'een-api-toolkit'
|
|
1619
|
+
|
|
1620
|
+
const targetTime = new Date(alertTimestamp)
|
|
1621
|
+
const searchStart = new Date(targetTime.getTime() - 60 * 60 * 1000) // 1 hour before
|
|
1622
|
+
const searchEnd = new Date(targetTime.getTime() + 60 * 60 * 1000) // 1 hour after
|
|
1623
|
+
|
|
1624
|
+
const result = await listMedia({
|
|
1625
|
+
deviceId: cameraId,
|
|
1626
|
+
type: 'main', // MUST be 'main' for HLS
|
|
1627
|
+
mediaType: 'video',
|
|
1628
|
+
startTimestamp: formatTimestamp(searchStart.toISOString()),
|
|
1629
|
+
endTimestamp: formatTimestamp(searchEnd.toISOString()),
|
|
1630
|
+
include: ['hlsUrl'] // MUST include 'hlsUrl'
|
|
1631
|
+
})
|
|
1632
|
+
|
|
1633
|
+
// Find interval containing target timestamp
|
|
1634
|
+
const intervals = result.data?.results ?? []
|
|
1635
|
+
const targetTimeMs = targetTime.getTime()
|
|
1636
|
+
|
|
1637
|
+
const matchingInterval = intervals.find(i => {
|
|
1638
|
+
if (!i.hlsUrl) return false
|
|
1639
|
+
const start = new Date(i.startTimestamp).getTime()
|
|
1640
|
+
const end = new Date(i.endTimestamp).getTime()
|
|
1641
|
+
return targetTimeMs >= start && targetTimeMs <= end
|
|
1642
|
+
})
|
|
1643
|
+
```
|
|
1644
|
+
|
|
1645
|
+
#### Timestamp Format Error
|
|
1646
|
+
|
|
1647
|
+
**Cause:** Using `Z` suffix instead of `+00:00`.
|
|
1648
|
+
|
|
1649
|
+
```typescript
|
|
1650
|
+
// WRONG
|
|
1651
|
+
const timestamp = new Date().toISOString() // "2025-01-15T22:30:00.000Z"
|
|
1652
|
+
|
|
1653
|
+
// CORRECT
|
|
1654
|
+
import { formatTimestamp } from 'een-api-toolkit'
|
|
1655
|
+
const timestamp = formatTimestamp(new Date().toISOString()) // "2025-01-15T22:30:00.000+00:00"
|
|
1656
|
+
```
|
|
1657
|
+
|
|
1658
|
+
---
|
|
1659
|
+
|
|
1348
1660
|
## Common Patterns
|
|
1349
1661
|
|
|
1350
1662
|
### Error Handling
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# vue-alerts-metrics
|
|
2
|
+
|
|
3
|
+
A Vue 3 example application demonstrating the Event Metrics, Alerts, and Notifications APIs from the `een-api-toolkit`.
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
| Feature | Status |
|
|
8
|
+
|---------|--------|
|
|
9
|
+
| Event Metrics | Supported |
|
|
10
|
+
| Alerts | Work in Progress |
|
|
11
|
+
| Notifications | Work in Progress |
|
|
12
|
+
|
|
13
|
+
> **Note:** The Event Metrics feature is fully functional. Alerts and Notifications UI components are present but the underlying API integration may have limitations.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **OAuth Authentication** - Secure login via Eagle Eye Networks
|
|
18
|
+
- **Camera Selection** - Browse and select cameras from your account
|
|
19
|
+
- **Time Range Selection** - View data for 1h, 6h, 24h, or 7 days
|
|
20
|
+
- **Event Metrics Chart** - Line chart visualization of event counts over time
|
|
21
|
+
- **Event Type Selection** - Filter metrics by specific event types
|
|
22
|
+
- **Alert Type Filtering** - Filter alerts by type (work in progress)
|
|
23
|
+
- **Notifications List** - View notifications for selected camera (work in progress)
|
|
24
|
+
|
|
25
|
+
## Prerequisites
|
|
26
|
+
|
|
27
|
+
1. **OAuth Proxy** - Running instance of [een-oauth-proxy](https://github.com/klaushofrichter/een-oauth-proxy)
|
|
28
|
+
2. **EEN Account** - Valid Eagle Eye Networks account with API access
|
|
29
|
+
3. **Node.js** - Version 20 or higher
|
|
30
|
+
|
|
31
|
+
## Setup
|
|
32
|
+
|
|
33
|
+
1. Install dependencies:
|
|
34
|
+
```bash
|
|
35
|
+
npm install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
2. Create a `.env` file (or copy from parent):
|
|
39
|
+
```bash
|
|
40
|
+
VITE_PROXY_URL=http://127.0.0.1:8787
|
|
41
|
+
VITE_EEN_CLIENT_ID=your-client-id
|
|
42
|
+
VITE_REDIRECT_URI=http://127.0.0.1:3333
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
3. Start the development server:
|
|
46
|
+
```bash
|
|
47
|
+
npm run dev
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
4. Open http://127.0.0.1:3333 in your browser
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
1. Click **Login** to authenticate with Eagle Eye Networks
|
|
55
|
+
2. After login, you'll be redirected to the Dashboard
|
|
56
|
+
3. Select a **Camera** from the dropdown
|
|
57
|
+
4. Select an **Event Type** to view metrics in the chart
|
|
58
|
+
5. Use the **Time Range** buttons to change the data window
|
|
59
|
+
6. View Alerts and Notifications in the panels below (work in progress)
|
|
60
|
+
|
|
61
|
+
## Project Structure
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
vue-alerts-metrics/
|
|
65
|
+
├── src/
|
|
66
|
+
│ ├── components/
|
|
67
|
+
│ │ ├── AlertsList.vue # Alerts display with type filter
|
|
68
|
+
│ │ ├── CameraSelector.vue # Camera dropdown
|
|
69
|
+
│ │ ├── MetricsChart.vue # Chart.js line chart
|
|
70
|
+
│ │ ├── NotificationsList.vue # Notifications display
|
|
71
|
+
│ │ └── TimeRangeSelector.vue # Time range buttons
|
|
72
|
+
│ ├── views/
|
|
73
|
+
│ │ ├── Callback.vue # OAuth callback handler
|
|
74
|
+
│ │ ├── Dashboard.vue # Main dashboard view
|
|
75
|
+
│ │ ├── Home.vue # Landing page
|
|
76
|
+
│ │ ├── Login.vue # Login page
|
|
77
|
+
│ │ └── Logout.vue # Logout handler
|
|
78
|
+
│ ├── router/
|
|
79
|
+
│ │ └── index.ts # Vue Router config
|
|
80
|
+
│ ├── App.vue # Root component
|
|
81
|
+
│ └── main.ts # App entry point
|
|
82
|
+
├── e2e/
|
|
83
|
+
│ ├── app.spec.ts # Basic navigation tests
|
|
84
|
+
│ └── auth.spec.ts # OAuth flow tests
|
|
85
|
+
├── playwright.config.ts # Playwright configuration
|
|
86
|
+
└── package.json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Scripts
|
|
90
|
+
|
|
91
|
+
| Command | Description |
|
|
92
|
+
|---------|-------------|
|
|
93
|
+
| `npm run dev` | Start development server |
|
|
94
|
+
| `npm run build` | Build for production |
|
|
95
|
+
| `npm run preview` | Preview production build |
|
|
96
|
+
| `npm run test:e2e` | Run Playwright E2E tests |
|
|
97
|
+
|
|
98
|
+
## E2E Testing
|
|
99
|
+
|
|
100
|
+
The example includes Playwright E2E tests that verify:
|
|
101
|
+
- Basic navigation and page rendering
|
|
102
|
+
- OAuth login flow
|
|
103
|
+
- Dashboard functionality
|
|
104
|
+
- Camera and event type selection
|
|
105
|
+
- Alerts and notifications loading
|
|
106
|
+
|
|
107
|
+
To run E2E tests:
|
|
108
|
+
```bash
|
|
109
|
+
# Ensure OAuth proxy is running
|
|
110
|
+
npm run test:e2e
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Required environment variables for E2E tests:
|
|
114
|
+
- `TEST_USER` - Test account email
|
|
115
|
+
- `TEST_PASSWORD` - Test account password
|
|
116
|
+
|
|
117
|
+
## API Functions Used
|
|
118
|
+
|
|
119
|
+
This example demonstrates the following `een-api-toolkit` functions:
|
|
120
|
+
|
|
121
|
+
- `initEenToolkit()` - Initialize the toolkit
|
|
122
|
+
- `getAuthUrl()` - Get OAuth authorization URL
|
|
123
|
+
- `handleAuthCallback()` - Handle OAuth callback
|
|
124
|
+
- `useAuthStore()` - Access authentication state
|
|
125
|
+
- `getCameras()` - List available cameras
|
|
126
|
+
- `listEventFieldValues()` - Get available event types for a camera
|
|
127
|
+
- `getEventMetrics()` - Fetch event metrics time-series data
|
|
128
|
+
- `listAlertTypes()` - Get available alert types
|
|
129
|
+
- `listAlerts()` - Fetch alerts for a camera
|
|
130
|
+
- `listNotifications()` - Fetch notifications for a camera
|
|
131
|
+
|
|
132
|
+
## Known Limitations
|
|
133
|
+
|
|
134
|
+
- **Event Metrics aggregation** - The EEN API requires a minimum 60-minute aggregation period. Shorter time ranges (1h, 6h) will have fewer data points.
|
|
135
|
+
- **Alerts API** - Alert type filtering is functional, but some alert types may not have data.
|
|
136
|
+
- **Notifications API** - Notification display is implemented but may have limited data depending on account configuration.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test.describe('Alerts & Metrics Example App', () => {
|
|
4
|
+
test('should display the home page', async ({ page }) => {
|
|
5
|
+
await page.goto('/')
|
|
6
|
+
|
|
7
|
+
// Check title
|
|
8
|
+
await expect(page).toHaveTitle('EEN Alerts & Metrics Example')
|
|
9
|
+
|
|
10
|
+
// Check header
|
|
11
|
+
await expect(page.locator('h1')).toContainText('EEN Alerts & Metrics Example')
|
|
12
|
+
|
|
13
|
+
// Check navigation links
|
|
14
|
+
await expect(page.locator('nav')).toContainText('Home')
|
|
15
|
+
await expect(page.locator('nav')).toContainText('Login')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('should show welcome message on home page', async ({ page }) => {
|
|
19
|
+
await page.goto('/')
|
|
20
|
+
|
|
21
|
+
await expect(page.locator('h2')).toContainText('Welcome to the EEN Alerts & Metrics Example')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('should display login prompt when not authenticated', async ({ page }) => {
|
|
25
|
+
await page.goto('/')
|
|
26
|
+
|
|
27
|
+
// Should show login prompt
|
|
28
|
+
await expect(page.locator('.login-prompt')).toBeVisible()
|
|
29
|
+
await expect(page.locator('.login-prompt')).toContainText('Please log in to view alerts, notifications, and metrics')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('should navigate to login page', async ({ page }) => {
|
|
33
|
+
await page.goto('/')
|
|
34
|
+
|
|
35
|
+
// Click login in nav
|
|
36
|
+
await page.locator('nav a:has-text("Login")').click()
|
|
37
|
+
|
|
38
|
+
// Should be on login page
|
|
39
|
+
await expect(page.locator('h2')).toContainText('Login')
|
|
40
|
+
await expect(page.locator('button')).toContainText('Login with Eagle Eye Networks')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('should redirect to login when accessing dashboard without auth', async ({ page }) => {
|
|
44
|
+
// Try to access dashboard directly
|
|
45
|
+
await page.goto('/dashboard')
|
|
46
|
+
|
|
47
|
+
// Should be redirected to login
|
|
48
|
+
await expect(page.locator('h2')).toContainText('Login')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('should show about section on home page', async ({ page }) => {
|
|
52
|
+
await page.goto('/')
|
|
53
|
+
|
|
54
|
+
// Check the about section
|
|
55
|
+
await expect(page.locator('.description h3')).toContainText('About This Example')
|
|
56
|
+
await expect(page.locator('.description')).toContainText('getEventMetrics')
|
|
57
|
+
await expect(page.locator('.description')).toContainText('listAlerts')
|
|
58
|
+
await expect(page.locator('.description')).toContainText('listNotifications')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('should have correct navigation structure', async ({ page }) => {
|
|
62
|
+
await page.goto('/')
|
|
63
|
+
|
|
64
|
+
// Check all expected nav links for unauthenticated state
|
|
65
|
+
const navLinks = page.locator('nav a')
|
|
66
|
+
await expect(navLinks).toHaveCount(2) // Home, Login
|
|
67
|
+
|
|
68
|
+
// Verify Home link
|
|
69
|
+
await expect(navLinks.nth(0)).toHaveAttribute('href', '/')
|
|
70
|
+
|
|
71
|
+
// Verify Login link
|
|
72
|
+
await expect(navLinks.nth(1)).toHaveAttribute('href', '/login')
|
|
73
|
+
})
|
|
74
|
+
})
|