Skip to content

Commit af0a5e7

Browse files
authored
fix(hub-ui): support persistent toast notifications (#299)
1 parent 87dafe9 commit af0a5e7

4 files changed

Lines changed: 80 additions & 6 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import type { DevframeMessageEntry } from '@devframes/hub'
2+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
3+
import { addToast, dismissToast, useToasts } from './toasts'
4+
5+
function createMessage(id: string, autoDismiss: number | false): DevframeMessageEntry {
6+
return {
7+
id,
8+
message: id,
9+
level: 'info',
10+
from: 'browser',
11+
timestamp: 0,
12+
autoDismiss,
13+
}
14+
}
15+
16+
function dismissAllToasts(): void {
17+
for (const toast of [...useToasts()])
18+
dismissToast(toast.id)
19+
}
20+
21+
describe('toast auto-dismiss', () => {
22+
beforeEach(() => {
23+
vi.useFakeTimers()
24+
dismissAllToasts()
25+
})
26+
27+
afterEach(() => {
28+
dismissAllToasts()
29+
vi.useRealTimers()
30+
})
31+
32+
it('keeps a persistent toast visible until it is explicitly dismissed', () => {
33+
addToast(createMessage('persistent', false))
34+
35+
expect(vi.getTimerCount()).toBe(0)
36+
37+
vi.advanceTimersByTime(60_000)
38+
39+
expect(useToasts()).toHaveLength(1)
40+
41+
dismissToast('persistent')
42+
43+
expect(useToasts()).toHaveLength(0)
44+
})
45+
46+
it('cancels an existing auto-dismiss timer when its toast becomes persistent', () => {
47+
addToast(createMessage('updated', 1_000))
48+
49+
expect(vi.getTimerCount()).toBe(1)
50+
51+
addToast(createMessage('updated', false))
52+
53+
expect(vi.getTimerCount()).toBe(0)
54+
55+
vi.advanceTimersByTime(60_000)
56+
57+
expect(useToasts()).toHaveLength(1)
58+
})
59+
60+
it('continues to auto-dismiss timed toasts', () => {
61+
addToast(createMessage('timed', 1_000))
62+
63+
vi.advanceTimersByTime(999)
64+
expect(useToasts()).toHaveLength(1)
65+
66+
vi.advanceTimersByTime(1)
67+
expect(useToasts()).toHaveLength(0)
68+
})
69+
})

packages/hub-ui/src/client/state/toasts.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,22 @@ export function addToast(entry: DevframeMessageEntry): void {
2121
existing.entry = entry
2222
// Reset auto-dismiss timer
2323
const timer = timers.get(entry.id)
24-
if (timer)
24+
if (timer) {
2525
clearTimeout(timer)
26+
timers.delete(entry.id)
27+
}
2628
const timeout = entry.autoDismiss ?? 5000
27-
timers.set(entry.id, setTimeout(dismissToast, timeout, entry.id))
29+
if (timeout !== false)
30+
timers.set(entry.id, setTimeout(dismissToast, timeout, entry.id))
2831
return
2932
}
3033

3134
const item: ToastItem = { id: entry.id, entry }
3235
toasts.push(item)
3336

3437
const timeout = entry.autoDismiss ?? 5000
35-
timers.set(entry.id, setTimeout(dismissToast, timeout, entry.id))
38+
if (timeout !== false)
39+
timers.set(entry.id, setTimeout(dismissToast, timeout, entry.id))
3640
}
3741

3842
export function dismissToast(id: string): void {

packages/hub/src/types/messages.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,10 @@ export interface DevframeMessageEntry {
109109
*/
110110
actions?: DevframeMessageAction[]
111111
/**
112-
* Time in ms to auto-dismiss the toast notification (client-side)
112+
* Time in ms to auto-dismiss the toast notification (client-side) or
113+
* `false` to keep it indefinitely.
113114
*/
114-
autoDismiss?: number
115+
autoDismiss?: number | false
115116
/**
116117
* Time in ms to auto-delete this message entry (server-side)
117118
*/

tests/__snapshots__/tsnapi/@devframes/hub/index.snapshot.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export interface DevframeMessageEntry {
173173
category?: string;
174174
labels?: string[];
175175
actions?: DevframeMessageAction[];
176-
autoDismiss?: number;
176+
autoDismiss?: number | false;
177177
autoDelete?: number;
178178
timestamp: number;
179179
status?: 'loading' | 'idle';

0 commit comments

Comments
 (0)