Skip to content

Commit 0f751f9

Browse files
authored
Merge pull request #29 from viamrobotics/add-slow-response-indicator-to-vision-service
APP-15593 Add slow response indicator to vision service
2 parents 8b66d10 + e4ff3c7 commit 0f751f9

4 files changed

Lines changed: 168 additions & 0 deletions

File tree

.changeset/lazy-zoos-hammer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@viamrobotics/test-widgets': patch
3+
---
4+
5+
Show slow loading indicator for vision service widget
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { flushSync } from 'svelte'
2+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
3+
4+
import { useSlowRequest } from '../use-slow-request.svelte.ts'
5+
6+
describe('useSlowRequest', () => {
7+
beforeEach(() => {
8+
vi.useFakeTimers()
9+
})
10+
11+
afterEach(() => {
12+
vi.useRealTimers()
13+
})
14+
15+
it('is not slow initially when not fetching', () => {
16+
const cleanup = $effect.root(() => {
17+
const result = useSlowRequest(() => false)
18+
flushSync()
19+
expect(result.isSlow).toBe(false)
20+
})
21+
cleanup()
22+
})
23+
24+
it('is not slow before the 5s threshold elapses', () => {
25+
let isFetching = $state(false)
26+
const cleanup = $effect.root(() => {
27+
const result = useSlowRequest(() => isFetching)
28+
flushSync()
29+
30+
isFetching = true
31+
flushSync()
32+
vi.advanceTimersByTime(4999)
33+
expect(result.isSlow).toBe(false)
34+
})
35+
cleanup()
36+
})
37+
38+
it('becomes slow after the 5s threshold elapses while fetching', () => {
39+
let isFetching = $state(false)
40+
const cleanup = $effect.root(() => {
41+
const result = useSlowRequest(() => isFetching)
42+
flushSync()
43+
44+
isFetching = true
45+
flushSync()
46+
vi.advanceTimersByTime(5000)
47+
expect(result.isSlow).toBe(true)
48+
})
49+
cleanup()
50+
})
51+
52+
it('resets to not slow when fetching completes', () => {
53+
let isFetching = $state(false)
54+
const cleanup = $effect.root(() => {
55+
const result = useSlowRequest(() => isFetching)
56+
flushSync()
57+
58+
isFetching = true
59+
flushSync()
60+
vi.advanceTimersByTime(5000)
61+
expect(result.isSlow).toBe(true)
62+
63+
isFetching = false
64+
flushSync()
65+
expect(result.isSlow).toBe(false)
66+
})
67+
cleanup()
68+
})
69+
70+
it('does not become slow if fetching completes before the threshold', () => {
71+
let isFetching = $state(false)
72+
const cleanup = $effect.root(() => {
73+
const result = useSlowRequest(() => isFetching)
74+
flushSync()
75+
76+
isFetching = true
77+
flushSync()
78+
vi.advanceTimersByTime(4000)
79+
isFetching = false
80+
flushSync()
81+
vi.advanceTimersByTime(5000)
82+
expect(result.isSlow).toBe(false)
83+
})
84+
cleanup()
85+
})
86+
87+
it('restarts the timer when a new fetch begins', () => {
88+
let isFetching = $state(false)
89+
const cleanup = $effect.root(() => {
90+
const result = useSlowRequest(() => isFetching)
91+
flushSync()
92+
93+
isFetching = true
94+
flushSync()
95+
vi.advanceTimersByTime(5000)
96+
expect(result.isSlow).toBe(true)
97+
98+
isFetching = false
99+
flushSync()
100+
expect(result.isSlow).toBe(false)
101+
102+
isFetching = true
103+
flushSync()
104+
vi.advanceTimersByTime(4999)
105+
expect(result.isSlow).toBe(false)
106+
vi.advanceTimersByTime(1)
107+
expect(result.isSlow).toBe(true)
108+
})
109+
cleanup()
110+
})
111+
})
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const SLOW_REQUEST_THRESHOLD_MS = 5000
2+
3+
export const useSlowRequest = (isFetching: () => boolean) => {
4+
let isSlow = $state(false)
5+
6+
$effect(() => {
7+
if (!isFetching()) {
8+
isSlow = false
9+
return
10+
}
11+
12+
isSlow = false
13+
const timeout = setTimeout(() => {
14+
isSlow = true
15+
}, SLOW_REQUEST_THRESHOLD_MS)
16+
17+
return () => {
18+
clearTimeout(timeout)
19+
}
20+
})
21+
22+
return {
23+
get isSlow() {
24+
return isSlow
25+
},
26+
}
27+
}

src/lib/components/widgets/vision-service/vision-service.svelte

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
1616
import Image from './image.svelte'
1717
import ObjectPointClouds from './object-point-clouds.svelte'
18+
import { useSlowRequest } from './use-slow-request.svelte.ts'
1819
1920
const { addImageToDataset } = useAddImageToDataset()
2021
@@ -106,10 +107,16 @@
106107
: (Math.max(getObjectPointCloudsRefetchInterval.current, 1000 / 20) as number | false),
107108
}))
108109
110+
const captureAllSlow = useSlowRequest(() => captureAllQuery.isFetching)
111+
const propertiesSlow = useSlowRequest(() => propertiesQuery.isFetching)
112+
const objectPointCloudsSlow = useSlowRequest(() => getObjectPointCloudsQuery.isFetching)
113+
109114
const onCameraSelect = (event: Event) => {
110115
const { value } = event.target as HTMLSelectElement
111116
cameraName = value
112117
}
118+
119+
const detectionsSlow = $derived(captureAllSlow.isSlow || propertiesSlow.isSlow)
113120
</script>
114121

115122
<ConnectionStatus {partID}>
@@ -183,10 +190,19 @@
183190
{/if}
184191
</div>
185192

193+
{#if detectionsSlow}
194+
<p class="text-subtle-2 text-xs italic">This request is taking a long time to complete.</p>
195+
{/if}
196+
186197
<Queries
187198
queries={[propertiesQuery, captureAllQuery]}
188199
contentCx="p-4 h-14"
189200
>
201+
{#if detectionsSlow}
202+
<p class="text-subtle-2 text-xs italic">
203+
This request is taking a long time to complete.
204+
</p>
205+
{/if}
190206
{#if captureAllQuery.data}
191207
<Image
192208
data={captureAllQuery.data}
@@ -213,11 +229,20 @@
213229
/>
214230
</div>
215231

232+
{#if showObjectPointClouds && objectPointCloudsSlow}
233+
<p class="text-subtle-2 text-xs italic">This request is taking a long time to complete.</p>
234+
{/if}
235+
216236
{#if showObjectPointClouds}
217237
<Queries
218238
queries={[getObjectPointCloudsQuery]}
219239
contentCx="p-4 h-14"
220240
>
241+
{#if objectPointCloudsSlow.isSlow}
242+
<p class="text-subtle-2 text-xs italic">
243+
This request is taking a long time to complete.
244+
</p>
245+
{/if}
221246
{#if getObjectPointCloudsQuery.data !== undefined}
222247
<ObjectPointClouds objects={getObjectPointCloudsQuery.data} />
223248
{/if}

0 commit comments

Comments
 (0)