Files
supabase/apps/studio/components/ui/AIAssistantPanel/Confirm.test.tsx
CharisandJoshen Lim 89b4f1aca4 feat(studio): add delete_notebook tool to AI assistant (#49413)
## Summary

* Adds a `delete_notebook` AI assistant tool (`needsApproval: true`)
that lets the assistant delete a notebook with explicit user approval,
mirroring the existing `create_notebook`/`update_notebook` tools.
* Wires up a destructive-styled approval card in the AI Assistant Panel
(fetches the notebook to show its name, warns the deletion is permanent)
using the same `Confirm`/tool-approval plumbing as the other notebook
tools.
* Updates `tool-filter.ts` opt-in gating, the assistant system prompt,
the eval-harness mock tools, and the eval dataset with `delete_notebook`
coverage.
* Adds test coverage in `notebook-tools.test.ts`, `mock-tools.test.ts`,
and `NotebookProposalRenderer.test.tsx`.

Closes
[FE-4242](https://linear.app/supabase/issue/FE-4242/assistant-delete-notebook-tool).

## Test plan

- [X] `pnpm typecheck --filter=studio` passes
- [X] `pnpm --filter studio exec vitest run` for the touched files
(notebook-tools, mock-tools, NotebookProposalRenderer,
[Message.Parts](<http://Message.Parts>), and existing consumers of
`content-delete-mutation`) — all passing
- [X] `eslint` and `prettier --check` clean on all touched files
- [X] Manual verification of the approval UI in a running Studio
instance (not done in this session)

## Summary by CodeRabbit

* **New Features**
* Added AI-assisted notebook deletion with explicit confirmation and
irreversible-action warnings.
* Added safeguards to distinguish deleting an entire notebook from
removing individual panels.
* Completed deletions now display the deleted notebook’s name without an
option to reopen it.
* **Bug Fixes**
* Improved handling of missing notebooks and invalid deletion requests.
* **Tests**
* Added coverage for deletion approval, denial, errors, and successful
completion.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added AI-assisted notebook deletion with explicit approval and
irreversible-action warnings.
* Added confirmation, loading, error, and completion states for notebook
deletion.
* Prevented accidental full-notebook deletion when only a panel or
section should be removed.
* Improved notebook update results by showing applied changes when
available.

* **Bug Fixes**
  * Notebook deletion now uses the required API version.
* Improved handling and validation of missing notebooks during deletion.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-08-24 13:18:12 -04:00

71 lines
2.3 KiB
TypeScript

import { screen } from '@testing-library/react'
import { describe, expect, it } from 'vitest'
import { Confirm } from './Confirm'
import { customRender as render } from '@/tests/lib/custom-render'
describe('Confirm', () => {
it('keeps its content visible and replaces actions with a success status', () => {
render(
<Confirm state="success" message="Run query" successMessage="Query executed">
<div>Query preview</div>
</Confirm>
)
expect(screen.getByText('Query preview')).toBeInTheDocument()
expect(screen.getByText('Query executed')).toBeInTheDocument()
expect(screen.queryByRole('button')).not.toBeInTheDocument()
})
it('keeps its content visible and replaces actions with an error status', () => {
render(
<Confirm state="error" message="Run query" errorMessage="Failed to execute SQL">
<div>Query preview</div>
</Confirm>
)
expect(screen.getByText('Query preview')).toBeInTheDocument()
expect(screen.getByText('Failed to execute SQL')).toBeInTheDocument()
expect(screen.queryByRole('button')).not.toBeInTheDocument()
})
it('keeps the confirm and cancel buttons visible but disabled while loading after approval', () => {
render(
<Confirm
state="approval-responded"
message="Run query"
confirmLabel="Confirm"
confirmLabelLoading="Running..."
>
<div>Query preview</div>
</Confirm>
)
const cancelButton = screen.getByRole('button', { name: 'Skip' })
const confirmButton = screen.getByRole('button', { name: 'Running...' })
expect(cancelButton).toBeDisabled()
expect(confirmButton).toBeDisabled()
})
it('announces outcome updates in the existing status region', () => {
const { rerender } = render(
<Confirm state="approval-requested" message="Run query" successMessage="Query executed">
<div>Query preview</div>
</Confirm>
)
const status = screen.getByRole('status')
expect(status).toHaveTextContent('Run query')
rerender(
<Confirm state="success" message="Run query" successMessage="Query executed">
<div>Query preview</div>
</Confirm>
)
expect(screen.getByRole('status')).toBe(status)
expect(status).toHaveTextContent('Query executed')
})
})