Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions packages/hub-ui/src/client/state/toasts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { DevframeMessageEntry } from '@devframes/hub'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { addToast, dismissToast, useToasts } from './toasts'

function createMessage(id: string, autoDismiss: number | false): DevframeMessageEntry {
return {
id,
message: id,
level: 'info',
from: 'browser',
timestamp: 0,
autoDismiss,
}
}

function dismissAllToasts(): void {
for (const toast of [...useToasts()])
dismissToast(toast.id)
}

describe('toast auto-dismiss', () => {
beforeEach(() => {
vi.useFakeTimers()
dismissAllToasts()
})

afterEach(() => {
dismissAllToasts()
vi.useRealTimers()
})

it('keeps a persistent toast visible until it is explicitly dismissed', () => {
addToast(createMessage('persistent', false))

expect(vi.getTimerCount()).toBe(0)

vi.advanceTimersByTime(60_000)

expect(useToasts()).toHaveLength(1)

dismissToast('persistent')

expect(useToasts()).toHaveLength(0)
})

it('cancels an existing auto-dismiss timer when its toast becomes persistent', () => {
addToast(createMessage('updated', 1_000))

expect(vi.getTimerCount()).toBe(1)

addToast(createMessage('updated', false))

expect(vi.getTimerCount()).toBe(0)

vi.advanceTimersByTime(60_000)

expect(useToasts()).toHaveLength(1)
})

it('continues to auto-dismiss timed toasts', () => {
addToast(createMessage('timed', 1_000))

vi.advanceTimersByTime(999)
expect(useToasts()).toHaveLength(1)

vi.advanceTimersByTime(1)
expect(useToasts()).toHaveLength(0)
})
})
10 changes: 7 additions & 3 deletions packages/hub-ui/src/client/state/toasts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,22 @@ export function addToast(entry: DevframeMessageEntry): void {
existing.entry = entry
// Reset auto-dismiss timer
const timer = timers.get(entry.id)
if (timer)
if (timer) {
clearTimeout(timer)
timers.delete(entry.id)
}
const timeout = entry.autoDismiss ?? 5000
timers.set(entry.id, setTimeout(dismissToast, timeout, entry.id))
if (timeout !== false)
timers.set(entry.id, setTimeout(dismissToast, timeout, entry.id))
return
}

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

const timeout = entry.autoDismiss ?? 5000
timers.set(entry.id, setTimeout(dismissToast, timeout, entry.id))
if (timeout !== false)
timers.set(entry.id, setTimeout(dismissToast, timeout, entry.id))
}

export function dismissToast(id: string): void {
Expand Down
5 changes: 3 additions & 2 deletions packages/hub/src/types/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,10 @@ export interface DevframeMessageEntry {
*/
actions?: DevframeMessageAction[]
/**
* Time in ms to auto-dismiss the toast notification (client-side)
* Time in ms to auto-dismiss the toast notification (client-side) or
* `false` to keep it indefinitely.
*/
autoDismiss?: number
autoDismiss?: number | false
Comment thread
dvcolomban marked this conversation as resolved.
/**
* Time in ms to auto-delete this message entry (server-side)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export interface DevframeMessageEntry {
category?: string;
labels?: string[];
actions?: DevframeMessageAction[];
autoDismiss?: number;
autoDismiss?: number | false;
autoDelete?: number;
timestamp: number;
status?: 'loading' | 'idle';
Expand Down
Loading