mirror of
https://github.com/stablyai/orca.git
synced 2026-09-25 00:02:35 +00:00
Reuse single toast slot for composer drop failures
Multiple drop failures now replace the previous toast instead of stacking, preventing notification clutter. Uses a dedicated toast ID separate from Source Control's stage/discard notifications.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const { toastError } = vi.hoisted(() => ({
|
||||
toastError: vi.fn<(title: string, options?: { description?: string }) => void>()
|
||||
toastError: vi.fn<(title: string, options?: { id?: string; description?: string }) => void>()
|
||||
}))
|
||||
vi.mock('sonner', () => ({ toast: { error: toastError } }))
|
||||
|
||||
@@ -15,10 +15,11 @@ const SKIP_REASON_COPY = [
|
||||
['unsupported', 'Unsupported file type.']
|
||||
] as const satisfies readonly (readonly [ImportSkipReason, string])[]
|
||||
|
||||
function lastToast(): { title: string; description?: string } {
|
||||
function lastToast(): { title: string; id?: string; description?: string } {
|
||||
const call = toastError.mock.calls.at(-1)
|
||||
return {
|
||||
title: String(call?.[0]),
|
||||
id: call?.[1]?.id,
|
||||
description: call?.[1]?.description
|
||||
}
|
||||
}
|
||||
@@ -74,6 +75,14 @@ describe('showComposerDropFailureToast', () => {
|
||||
expect(lastToast().description).toBe('EACCES: permission denied')
|
||||
})
|
||||
|
||||
it('reuses one slot so a second failed drop replaces the first instead of stacking', () => {
|
||||
showComposerDropFailureToast({ failureCount: 1, total: 2 })
|
||||
const first = lastToast().id
|
||||
showComposerDropFailureToast({ failureCount: 2, total: 3 })
|
||||
expect(first).toBeDefined()
|
||||
expect(lastToast().id).toBe(first)
|
||||
})
|
||||
|
||||
it('gives no reason at all when the batch failed for differing reasons', () => {
|
||||
showComposerDropFailureToast({ failureCount: 3, total: 6 })
|
||||
expect(lastToast().title).toBe('3 of 6 items could not be attached.')
|
||||
|
||||
@@ -4,6 +4,9 @@ import { compactIpcErrorMessage } from '@/lib/ipc-error'
|
||||
import type { ComposerDropFailure } from './composer-drop-result'
|
||||
import type { ImportSkipReason } from '../../../shared/filesystem-import-result-types'
|
||||
|
||||
// Own slot, not Source Control's: a drop failure must not erase an unread stage/discard failure.
|
||||
const DROP_FAILURE_TOAST_ID = 'composer-drop-failure'
|
||||
|
||||
const SKIP_REASON_COPY: Record<ImportSkipReason, { key: string; fallback: string }> = {
|
||||
missing: {
|
||||
key: 'auto.hooks.useComposerState.attachSkipMissing',
|
||||
@@ -46,6 +49,9 @@ export function showComposerDropFailureToast({
|
||||
'{{failureCount}} of {{count}} items could not be attached.',
|
||||
{ failureCount, count: total }
|
||||
),
|
||||
{ description: commonFailure ? failureDescription(commonFailure) : undefined }
|
||||
{
|
||||
id: DROP_FAILURE_TOAST_ID,
|
||||
description: commonFailure ? failureDescription(commonFailure) : undefined
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user