een-api-toolkit 0.0.18 → 0.1.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 +52 -5
- package/README.md +29 -41
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +23 -821
- package/dist/index.js +234 -357
- package/dist/index.js.map +1 -1
- package/docs/AI-CONTEXT.md +38 -257
- package/examples/vue-cameras/e2e/app.spec.ts +2 -2
- package/examples/vue-cameras/e2e/auth.spec.ts +206 -0
- package/examples/vue-cameras/src/App.vue +4 -4
- package/examples/vue-cameras/src/views/CameraDetail.vue +57 -9
- package/examples/vue-cameras/src/views/Cameras.vue +69 -18
- package/examples/vue-cameras/src/views/Home.vue +36 -11
- package/examples/{vue-basic → vue-users}/README.md +4 -4
- package/examples/{vue-basic → vue-users}/e2e/app.spec.ts +3 -3
- package/examples/{vue-basic → vue-users}/e2e/auth.spec.ts +2 -2
- package/examples/{vue-basic → vue-users}/index.html +1 -1
- package/examples/{vue-basic → vue-users}/package-lock.json +3 -3
- package/examples/{vue-basic → vue-users}/package.json +1 -1
- package/examples/{vue-basic → vue-users}/src/App.vue +1 -1
- package/examples/{vue-basic → vue-users}/src/views/Home.vue +27 -12
- package/examples/{vue-basic → vue-users}/src/views/Users.vue +51 -10
- package/package.json +1 -1
- /package/examples/{vue-basic → vue-users}/.env.example +0 -0
- /package/examples/{vue-basic → vue-users}/playwright.config.ts +0 -0
- /package/examples/{vue-basic → vue-users}/src/main.ts +0 -0
- /package/examples/{vue-basic → vue-users}/src/router/index.ts +0 -0
- /package/examples/{vue-basic → vue-users}/src/views/Callback.vue +0 -0
- /package/examples/{vue-basic → vue-users}/src/views/Login.vue +0 -0
- /package/examples/{vue-basic → vue-users}/src/views/Logout.vue +0 -0
- /package/examples/{vue-basic → vue-users}/src/vite-env.d.ts +0 -0
- /package/examples/{vue-basic → vue-users}/tsconfig.json +0 -0
- /package/examples/{vue-basic → vue-users}/tsconfig.node.json +0 -0
- /package/examples/{vue-basic → vue-users}/vite.config.ts +0 -0
|
@@ -1,20 +1,54 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { ref, onMounted, watch } from 'vue'
|
|
2
3
|
import { useRoute } from 'vue-router'
|
|
3
|
-
import {
|
|
4
|
+
import { getCamera, type Camera, type CameraStatus, type EenError } from 'een-api-toolkit'
|
|
4
5
|
|
|
5
6
|
const route = useRoute()
|
|
6
7
|
|
|
7
|
-
//
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
// Reactive state
|
|
9
|
+
const camera = ref<Camera | null>(null)
|
|
10
|
+
const loading = ref(false)
|
|
11
|
+
const error = ref<EenError | null>(null)
|
|
12
|
+
|
|
13
|
+
async function fetchCamera() {
|
|
14
|
+
const id = route.params.id as string
|
|
15
|
+
if (!id) {
|
|
16
|
+
error.value = { code: 'VALIDATION_ERROR', message: 'Camera ID is required' }
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
loading.value = true
|
|
21
|
+
error.value = null
|
|
22
|
+
|
|
23
|
+
const result = await getCamera(id, {
|
|
11
24
|
include: ['deviceInfo', 'status', 'shareDetails', 'devicePosition', 'networkInfo', 'tags']
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
if (result.error) {
|
|
28
|
+
error.value = result.error
|
|
29
|
+
camera.value = null
|
|
30
|
+
} else {
|
|
31
|
+
camera.value = result.data
|
|
12
32
|
}
|
|
13
|
-
|
|
33
|
+
|
|
34
|
+
loading.value = false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function refresh() {
|
|
38
|
+
return fetchCamera()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Helper to extract status string from the union type
|
|
42
|
+
function getStatusString(status?: CameraStatus | { connectionStatus?: CameraStatus }): CameraStatus | undefined {
|
|
43
|
+
if (!status) return undefined
|
|
44
|
+
if (typeof status === 'string') return status
|
|
45
|
+
return status.connectionStatus
|
|
46
|
+
}
|
|
14
47
|
|
|
15
48
|
// Get status badge class
|
|
16
|
-
function getStatusClass(status?: CameraStatus): string {
|
|
17
|
-
|
|
49
|
+
function getStatusClass(status?: CameraStatus | { connectionStatus?: CameraStatus }): string {
|
|
50
|
+
const statusStr = getStatusString(status)
|
|
51
|
+
switch (statusStr) {
|
|
18
52
|
case 'online':
|
|
19
53
|
case 'streaming':
|
|
20
54
|
return 'status-online'
|
|
@@ -29,6 +63,20 @@ function getStatusClass(status?: CameraStatus): string {
|
|
|
29
63
|
return 'status-unknown'
|
|
30
64
|
}
|
|
31
65
|
}
|
|
66
|
+
|
|
67
|
+
onMounted(() => {
|
|
68
|
+
fetchCamera()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
// Watch for route param changes
|
|
72
|
+
watch(
|
|
73
|
+
() => route.params.id,
|
|
74
|
+
(newId, oldId) => {
|
|
75
|
+
if (newId && newId !== oldId) {
|
|
76
|
+
fetchCamera()
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
)
|
|
32
80
|
</script>
|
|
33
81
|
|
|
34
82
|
<template>
|
|
@@ -53,7 +101,7 @@ function getStatusClass(status?: CameraStatus): string {
|
|
|
53
101
|
</div>
|
|
54
102
|
<div class="header-actions">
|
|
55
103
|
<span :class="['status-badge', getStatusClass(camera.status)]">
|
|
56
|
-
{{ camera.status || 'Unknown' }}
|
|
104
|
+
{{ getStatusString(camera.status) || 'Unknown' }}
|
|
57
105
|
</span>
|
|
58
106
|
<button @click="refresh">Refresh</button>
|
|
59
107
|
</div>
|
|
@@ -1,26 +1,65 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, watch } from 'vue'
|
|
3
|
-
import {
|
|
2
|
+
import { ref, computed, watch, onMounted } from 'vue'
|
|
3
|
+
import { getCameras, type Camera, type CameraStatus, type EenError, type ListCamerasParams } from 'een-api-toolkit'
|
|
4
4
|
|
|
5
5
|
// Status filter
|
|
6
6
|
const statusFilter = ref<CameraStatus | ''>('')
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
fetch
|
|
19
|
-
} = useCameras({
|
|
8
|
+
// Reactive state
|
|
9
|
+
const cameras = ref<Camera[]>([])
|
|
10
|
+
const loading = ref(false)
|
|
11
|
+
const error = ref<EenError | null>(null)
|
|
12
|
+
const nextPageToken = ref<string | undefined>(undefined)
|
|
13
|
+
const totalSize = ref<number | undefined>(undefined)
|
|
14
|
+
|
|
15
|
+
const hasNextPage = computed(() => !!nextPageToken.value)
|
|
16
|
+
|
|
17
|
+
const params = ref<ListCamerasParams>({
|
|
20
18
|
pageSize: 20,
|
|
21
19
|
include: ['deviceInfo', 'status']
|
|
22
20
|
})
|
|
23
21
|
|
|
22
|
+
async function fetchCameras(fetchParams?: ListCamerasParams, append = false) {
|
|
23
|
+
loading.value = true
|
|
24
|
+
error.value = null
|
|
25
|
+
|
|
26
|
+
const mergedParams = { ...params.value, ...fetchParams }
|
|
27
|
+
const result = await getCameras(mergedParams)
|
|
28
|
+
|
|
29
|
+
if (result.error) {
|
|
30
|
+
error.value = result.error
|
|
31
|
+
if (!append) {
|
|
32
|
+
cameras.value = []
|
|
33
|
+
totalSize.value = undefined
|
|
34
|
+
}
|
|
35
|
+
nextPageToken.value = undefined
|
|
36
|
+
} else {
|
|
37
|
+
if (append) {
|
|
38
|
+
cameras.value = [...cameras.value, ...result.data.results]
|
|
39
|
+
} else {
|
|
40
|
+
cameras.value = result.data.results
|
|
41
|
+
}
|
|
42
|
+
nextPageToken.value = result.data.nextPageToken
|
|
43
|
+
totalSize.value = result.data.totalSize
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
loading.value = false
|
|
47
|
+
return result
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function refresh() {
|
|
51
|
+
return fetchCameras()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function fetchNextPage() {
|
|
55
|
+
if (!nextPageToken.value) return
|
|
56
|
+
return fetchCameras({ ...params.value, pageToken: nextPageToken.value }, true)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function setParams(newParams: ListCamerasParams) {
|
|
60
|
+
params.value = newParams
|
|
61
|
+
}
|
|
62
|
+
|
|
24
63
|
// Watch for status filter changes
|
|
25
64
|
watch(statusFilter, async (newStatus) => {
|
|
26
65
|
if (newStatus) {
|
|
@@ -35,12 +74,20 @@ watch(statusFilter, async (newStatus) => {
|
|
|
35
74
|
include: ['deviceInfo', 'status']
|
|
36
75
|
})
|
|
37
76
|
}
|
|
38
|
-
await
|
|
77
|
+
await fetchCameras()
|
|
39
78
|
})
|
|
40
79
|
|
|
80
|
+
// Helper to extract status string from the union type
|
|
81
|
+
function getStatusString(status?: CameraStatus | { connectionStatus?: CameraStatus }): CameraStatus | undefined {
|
|
82
|
+
if (!status) return undefined
|
|
83
|
+
if (typeof status === 'string') return status
|
|
84
|
+
return status.connectionStatus
|
|
85
|
+
}
|
|
86
|
+
|
|
41
87
|
// Get status badge class
|
|
42
|
-
function getStatusClass(status?: CameraStatus): string {
|
|
43
|
-
|
|
88
|
+
function getStatusClass(status?: CameraStatus | { connectionStatus?: CameraStatus }): string {
|
|
89
|
+
const statusStr = getStatusString(status)
|
|
90
|
+
switch (statusStr) {
|
|
44
91
|
case 'online':
|
|
45
92
|
case 'streaming':
|
|
46
93
|
return 'status-online'
|
|
@@ -55,6 +102,10 @@ function getStatusClass(status?: CameraStatus): string {
|
|
|
55
102
|
return 'status-unknown'
|
|
56
103
|
}
|
|
57
104
|
}
|
|
105
|
+
|
|
106
|
+
onMounted(() => {
|
|
107
|
+
fetchCameras()
|
|
108
|
+
})
|
|
58
109
|
</script>
|
|
59
110
|
|
|
60
111
|
<template>
|
|
@@ -100,7 +151,7 @@ function getStatusClass(status?: CameraStatus): string {
|
|
|
100
151
|
<div class="camera-header">
|
|
101
152
|
<h3>{{ camera.name }}</h3>
|
|
102
153
|
<span :class="['status-badge', getStatusClass(camera.status)]">
|
|
103
|
-
{{ camera.status || 'Unknown' }}
|
|
154
|
+
{{ getStatusString(camera.status) || 'Unknown' }}
|
|
104
155
|
</span>
|
|
105
156
|
</div>
|
|
106
157
|
<div class="camera-details">
|
|
@@ -1,45 +1,70 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { useAuthStore,
|
|
3
|
-
import { computed } from 'vue'
|
|
2
|
+
import { useAuthStore, getCurrentUser, type UserProfile, type EenError } from 'een-api-toolkit'
|
|
3
|
+
import { computed, ref, onMounted } from 'vue'
|
|
4
4
|
|
|
5
5
|
const authStore = useAuthStore()
|
|
6
6
|
const isAuthenticated = computed(() => authStore.isAuthenticated)
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
const
|
|
8
|
+
// Reactive state for current user
|
|
9
|
+
const user = ref<UserProfile | null>(null)
|
|
10
|
+
const loading = ref(false)
|
|
11
|
+
const error = ref<EenError | null>(null)
|
|
12
|
+
|
|
13
|
+
async function fetchUser() {
|
|
14
|
+
if (!isAuthenticated.value) return
|
|
15
|
+
|
|
16
|
+
loading.value = true
|
|
17
|
+
error.value = null
|
|
18
|
+
|
|
19
|
+
const result = await getCurrentUser()
|
|
20
|
+
if (result.error) {
|
|
21
|
+
error.value = result.error
|
|
22
|
+
user.value = null
|
|
23
|
+
} else {
|
|
24
|
+
user.value = result.data
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
loading.value = false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
onMounted(() => {
|
|
31
|
+
if (isAuthenticated.value) {
|
|
32
|
+
fetchUser()
|
|
33
|
+
}
|
|
34
|
+
})
|
|
10
35
|
</script>
|
|
11
36
|
|
|
12
37
|
<template>
|
|
13
38
|
<div class="home">
|
|
14
39
|
<h2>Welcome to the EEN Cameras Example</h2>
|
|
15
40
|
|
|
16
|
-
<div v-if="isAuthenticated">
|
|
41
|
+
<div v-if="isAuthenticated" data-testid="authenticated">
|
|
17
42
|
<div v-if="loading" class="loading">Loading user info...</div>
|
|
18
43
|
<div v-else-if="error" class="error">{{ error.message }}</div>
|
|
19
|
-
<div v-else-if="user" class="user-info">
|
|
44
|
+
<div v-else-if="user" class="user-info" data-testid="user-info">
|
|
20
45
|
<p>Logged in as: <strong>{{ user.firstName }} {{ user.lastName }}</strong></p>
|
|
21
46
|
<p>Email: {{ user.email }}</p>
|
|
22
47
|
</div>
|
|
23
48
|
|
|
24
49
|
<div class="actions">
|
|
25
50
|
<router-link to="/cameras">
|
|
26
|
-
<button>View Cameras</button>
|
|
51
|
+
<button data-testid="view-cameras-button">View Cameras</button>
|
|
27
52
|
</router-link>
|
|
28
53
|
</div>
|
|
29
54
|
</div>
|
|
30
55
|
|
|
31
|
-
<div v-else class="login-prompt">
|
|
56
|
+
<div v-else class="login-prompt" data-testid="not-authenticated">
|
|
32
57
|
<p>Please log in to view your cameras.</p>
|
|
33
58
|
<router-link to="/login">
|
|
34
|
-
<button>Login</button>
|
|
59
|
+
<button data-testid="login-button">Login</button>
|
|
35
60
|
</router-link>
|
|
36
61
|
</div>
|
|
37
62
|
|
|
38
63
|
<div class="description">
|
|
39
64
|
<h3>About This Example</h3>
|
|
40
65
|
<p>
|
|
41
|
-
This example demonstrates how to use the <code>
|
|
42
|
-
<code>
|
|
66
|
+
This example demonstrates how to use the <code>getCameras</code> and
|
|
67
|
+
<code>getCamera</code> functions from the EEN API Toolkit to display
|
|
43
68
|
and manage cameras from the Eagle Eye Networks platform.
|
|
44
69
|
</p>
|
|
45
70
|
<h4>Features</h4>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# EEN API Toolkit - Vue
|
|
1
|
+
# EEN API Toolkit - Vue Users Example
|
|
2
2
|
|
|
3
3
|
A complete example showing how to use the een-api-toolkit in a Vue 3 application.
|
|
4
4
|
|
|
@@ -30,11 +30,11 @@ A complete example showing how to use the een-api-toolkit in a Vue 3 application
|
|
|
30
30
|
|
|
31
31
|
### Example Setup
|
|
32
32
|
|
|
33
|
-
All commands below should be run from this example directory (`examples/vue-
|
|
33
|
+
All commands below should be run from this example directory (`examples/vue-users/`):
|
|
34
34
|
|
|
35
35
|
2. Copy the environment file:
|
|
36
36
|
```bash
|
|
37
|
-
# From examples/vue-
|
|
37
|
+
# From examples/vue-users/
|
|
38
38
|
cp .env.example .env
|
|
39
39
|
```
|
|
40
40
|
|
|
@@ -48,7 +48,7 @@ All commands below should be run from this example directory (`examples/vue-basi
|
|
|
48
48
|
|
|
49
49
|
4. Install dependencies and start:
|
|
50
50
|
```bash
|
|
51
|
-
# From examples/vue-
|
|
51
|
+
# From examples/vue-users/
|
|
52
52
|
npm install
|
|
53
53
|
npm run dev
|
|
54
54
|
```
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { test, expect } from '@playwright/test'
|
|
2
2
|
|
|
3
|
-
test.describe('Vue
|
|
3
|
+
test.describe('Vue Users Example - App', () => {
|
|
4
4
|
test.beforeEach(async ({ page }) => {
|
|
5
5
|
await page.goto('/')
|
|
6
6
|
})
|
|
7
7
|
|
|
8
8
|
test('app loads with correct title', async ({ page }) => {
|
|
9
|
-
await expect(page).toHaveTitle(/EEN
|
|
9
|
+
await expect(page).toHaveTitle(/EEN Users/)
|
|
10
10
|
})
|
|
11
11
|
|
|
12
12
|
test('header displays app name', async ({ page }) => {
|
|
13
|
-
await expect(page.locator('[data-testid="app-title"]')).toHaveText('EEN
|
|
13
|
+
await expect(page.locator('[data-testid="app-title"]')).toHaveText('EEN Users Example')
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
test('navigation shows Home and Login links when not authenticated', async ({ page }) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { test, expect, Page } from '@playwright/test'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* E2E tests for the Vue
|
|
4
|
+
* E2E tests for the Vue Users Example
|
|
5
5
|
*
|
|
6
6
|
* Tests the OAuth login flow through the UI:
|
|
7
7
|
* 1. Click login button in the example app
|
|
@@ -111,7 +111,7 @@ async function clearAuthState(page: Page): Promise<void> {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
test.describe('Vue
|
|
114
|
+
test.describe('Vue Users Example', () => {
|
|
115
115
|
// Check proxy accessibility once before all tests
|
|
116
116
|
let proxyAccessible = false
|
|
117
117
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>EEN
|
|
7
|
+
<title>EEN Users Example</title>
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<div id="app"></div>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "een-api-toolkit-example",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "een-api-toolkit-example",
|
|
9
|
-
"version": "0.0.
|
|
9
|
+
"version": "0.0.12",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"een-api-toolkit": "file:../..",
|
|
12
12
|
"pinia": "^2.1.7",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"../..": {
|
|
26
|
-
"version": "0.
|
|
26
|
+
"version": "0.1.1",
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@playwright/test": "^1.57.0",
|
|
@@ -9,7 +9,7 @@ const isAuthenticated = computed(() => authStore.isAuthenticated)
|
|
|
9
9
|
<template>
|
|
10
10
|
<div class="app">
|
|
11
11
|
<header>
|
|
12
|
-
<h1 data-testid="app-title">EEN
|
|
12
|
+
<h1 data-testid="app-title">EEN Users Example</h1>
|
|
13
13
|
<nav>
|
|
14
14
|
<router-link data-testid="nav-home" to="/">Home</router-link>
|
|
15
15
|
<router-link data-testid="nav-users" v-if="isAuthenticated" to="/users">Users</router-link>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { useAuthStore,
|
|
2
|
+
import { useAuthStore, getCurrentUser, getAuthUrl, type UserProfile, type EenError } from 'een-api-toolkit'
|
|
3
3
|
import { computed, ref, watch } from 'vue'
|
|
4
4
|
|
|
5
5
|
const authStore = useAuthStore()
|
|
@@ -17,25 +17,40 @@ function login() {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
//
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
// Reactive state for current user
|
|
21
|
+
const user = ref<UserProfile | null>(null)
|
|
22
|
+
const loading = ref(false)
|
|
23
|
+
const error = ref<EenError | null>(null)
|
|
24
24
|
|
|
25
25
|
// Guard to prevent concurrent fetch calls
|
|
26
26
|
let fetchInProgress = false
|
|
27
27
|
|
|
28
|
+
async function fetchUser() {
|
|
29
|
+
if (fetchInProgress) return
|
|
30
|
+
fetchInProgress = true
|
|
31
|
+
loading.value = true
|
|
32
|
+
error.value = null
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const result = await getCurrentUser()
|
|
36
|
+
if (result.error) {
|
|
37
|
+
error.value = result.error
|
|
38
|
+
user.value = null
|
|
39
|
+
} else {
|
|
40
|
+
user.value = result.data
|
|
41
|
+
}
|
|
42
|
+
} finally {
|
|
43
|
+
loading.value = false
|
|
44
|
+
fetchInProgress = false
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
28
48
|
// Fetch user when authentication state changes
|
|
29
49
|
watch(
|
|
30
50
|
isAuthenticated,
|
|
31
51
|
async (isAuth) => {
|
|
32
52
|
if (isAuth && !user.value && !fetchInProgress) {
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
await fetch()
|
|
36
|
-
} finally {
|
|
37
|
-
fetchInProgress = false
|
|
38
|
-
}
|
|
53
|
+
await fetchUser()
|
|
39
54
|
}
|
|
40
55
|
},
|
|
41
56
|
{ immediate: true }
|
|
@@ -44,7 +59,7 @@ watch(
|
|
|
44
59
|
|
|
45
60
|
<template>
|
|
46
61
|
<div class="home">
|
|
47
|
-
<h2>Welcome to the EEN
|
|
62
|
+
<h2>Welcome to the EEN Users Example</h2>
|
|
48
63
|
|
|
49
64
|
<div v-if="!isAuthenticated" class="not-authenticated" data-testid="not-authenticated">
|
|
50
65
|
<p data-testid="not-authenticated-message">You are not logged in.</p>
|
|
@@ -1,14 +1,55 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
import { ref, computed, onMounted } from 'vue'
|
|
3
|
+
import { getUsers, type User, type EenError, type ListUsersParams } from 'een-api-toolkit'
|
|
4
|
+
|
|
5
|
+
// Reactive state
|
|
6
|
+
const users = ref<User[]>([])
|
|
7
|
+
const loading = ref(false)
|
|
8
|
+
const error = ref<EenError | null>(null)
|
|
9
|
+
const nextPageToken = ref<string | undefined>(undefined)
|
|
10
|
+
|
|
11
|
+
const hasNextPage = computed(() => !!nextPageToken.value)
|
|
12
|
+
|
|
13
|
+
const params = ref<ListUsersParams>({ pageSize: 10 })
|
|
14
|
+
|
|
15
|
+
async function fetchUsers(fetchParams?: ListUsersParams, append = false) {
|
|
16
|
+
loading.value = true
|
|
17
|
+
error.value = null
|
|
18
|
+
|
|
19
|
+
const mergedParams = { ...params.value, ...fetchParams }
|
|
20
|
+
const result = await getUsers(mergedParams)
|
|
21
|
+
|
|
22
|
+
if (result.error) {
|
|
23
|
+
error.value = result.error
|
|
24
|
+
if (!append) {
|
|
25
|
+
users.value = []
|
|
26
|
+
}
|
|
27
|
+
nextPageToken.value = undefined
|
|
28
|
+
} else {
|
|
29
|
+
if (append) {
|
|
30
|
+
users.value = [...users.value, ...result.data.results]
|
|
31
|
+
} else {
|
|
32
|
+
users.value = result.data.results
|
|
33
|
+
}
|
|
34
|
+
nextPageToken.value = result.data.nextPageToken
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
loading.value = false
|
|
38
|
+
return result
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function refresh() {
|
|
42
|
+
return fetchUsers()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function fetchNextPage() {
|
|
46
|
+
if (!nextPageToken.value) return
|
|
47
|
+
return fetchUsers({ ...params.value, pageToken: nextPageToken.value }, true)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
onMounted(() => {
|
|
51
|
+
fetchUsers()
|
|
52
|
+
})
|
|
12
53
|
</script>
|
|
13
54
|
|
|
14
55
|
<template>
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|