diff --git a/frontend/src/components/Chat/FindingEvidenceDialog.test.tsx b/frontend/src/components/Chat/FindingEvidenceDialog.test.tsx index b30efff3dd..8e6de34f32 100644 --- a/frontend/src/components/Chat/FindingEvidenceDialog.test.tsx +++ b/frontend/src/components/Chat/FindingEvidenceDialog.test.tsx @@ -365,6 +365,62 @@ it('does not keep a cancelled selection when the picker reopens', async () => { expect(screen.getByRole('button', { name: 'Attach attack' })).toBeDisabled() }) +it('restarts pagination and search when the picker reopens', async () => { + const user = userEvent.setup() + ;(operationsApi.listFindings as jest.Mock).mockResolvedValue({ + items: [FINDING], has_more: true, next_offset: 20, + }) + renderDialog() + await waitFor(() => { expect(screen.getByRole('button', { name: 'Link to finding' })).toBeEnabled() }) + await user.click(screen.getByRole('button', { name: 'Link to finding' })) + await screen.findByRole('radio') + await user.click(screen.getByRole('button', { name: 'Next findings' })) + await waitFor(() => { + expect(operationsApi.listFindings).toHaveBeenLastCalledWith('saved', { limit: 20, offset: 20, title: '' }) + }) + + await user.type(screen.getByRole('textbox'), 'Proof') + await waitFor(() => { + expect(operationsApi.listFindings).toHaveBeenLastCalledWith('saved', { limit: 20, offset: 0, title: 'Proof' }) + }) + await user.click(screen.getByRole('button', { name: 'Next findings' })) + await waitFor(() => { + expect(operationsApi.listFindings).toHaveBeenLastCalledWith('saved', { limit: 20, offset: 20, title: 'Proof' }) + }) + + await user.click(screen.getByRole('button', { name: 'Cancel' })) + await waitFor(() => { expect(screen.queryByRole('dialog')).not.toBeInTheDocument() }) + await user.click(screen.getByRole('button', { name: 'Link to finding' })) + await screen.findByRole('radio') + expect(screen.getByRole('textbox')).toHaveValue('') + await waitFor(() => { + expect(operationsApi.listFindings).toHaveBeenLastCalledWith('saved', { limit: 20, offset: 0, title: '' }) + }) +}) + +it('restarts pagination when the picker reopens without a search', async () => { + const user = userEvent.setup() + ;(operationsApi.listFindings as jest.Mock).mockResolvedValue({ + items: [FINDING], has_more: true, next_offset: 20, + }) + renderDialog() + await waitFor(() => { expect(screen.getByRole('button', { name: 'Link to finding' })).toBeEnabled() }) + await user.click(screen.getByRole('button', { name: 'Link to finding' })) + await screen.findByRole('radio') + await user.click(screen.getByRole('button', { name: 'Next findings' })) + await waitFor(() => { + expect(operationsApi.listFindings).toHaveBeenLastCalledWith('saved', { limit: 20, offset: 20, title: '' }) + }) + + await user.click(screen.getByRole('button', { name: 'Cancel' })) + await waitFor(() => { expect(screen.queryByRole('dialog')).not.toBeInTheDocument() }) + await user.click(screen.getByRole('button', { name: 'Link to finding' })) + await screen.findByRole('radio') + await waitFor(() => { + expect(operationsApi.listFindings).toHaveBeenLastCalledWith('saved', { limit: 20, offset: 0, title: '' }) + }) +}) + it('drops the selection when the viewed attack changes while the picker is open', async () => { const user = userEvent.setup() const { rerender } = render( diff --git a/frontend/src/components/Chat/FindingEvidenceDialog.tsx b/frontend/src/components/Chat/FindingEvidenceDialog.tsx index a9ab5adcd3..dbb4b423df 100644 --- a/frontend/src/components/Chat/FindingEvidenceDialog.tsx +++ b/frontend/src/components/Chat/FindingEvidenceDialog.tsx @@ -60,10 +60,12 @@ export default function FindingEvidenceDialog({ const newFindingRef = useRef(null) const wasOpen = useRef(false) const wasCreating = useRef(false) - // Each opening starts without a previous selection or result. + // Each opening starts without a previous selection or result, and back at the + // first page of an unfiltered finding list, so a later opening never resumes + // the previous opening's pagination or search. if (open !== shownOpen) { setShownOpen(open) - if (open) { setPicked(null); setNotice(null); setAttachError('') } + if (open) { setPicked(null); setNotice(null); setAttachError(''); setOffset(0); setTitle('') } } // Evidence can come from any attack; the user picks whose findings to link, defaulting to the attack's own Operation. const operation = chosen?.key === viewKey ? chosen.operation