mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 12:25:05 +03:00
## Summary - Joshen's `state/notebooks/types.ts` (Explorer/notebook editor UI) redefined its own `TimeRange`, cell union, and `NotebookContent` shapes, duplicating the canonical schema from `data/content/notebooks/notebook-schema.ts` (#48813, #48815). - Points `Notebook.content` and `notebooksState.updateCells` at the canonical `Notebooks.Content` / `Notebooks.Cell` types (via `@/types`) instead, and fixes the handful of call sites that constructed notebook content by hand to match the real wire shape: `schema_version: 1` (not `'1.0'`) and `_tag`-discriminated cells (e.g. `{ _tag: 'markdown_cell', id, text }` instead of `{ type: 'markdown', content }`). - No behavioral changes — Joshen's state management, editor component, and hooks are untouched aside from the type-level fixes needed to compile against the canonical schema. ## Test plan - [x] `pnpm exec tsc --noEmit` — no new errors - [x] `pnpm exec vitest run state/notebooks/notebooks-state.test.ts components/interfaces/Explorer/__tests__/NotebookEditor.test.tsx` — 8/8 passing - [x] `pnpm exec eslint` on changed files — clean - [x] `pnpm exec prettier --check` on changed files — clean <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Updated notebook content handling to use the current schema version format. * Improved compatibility for markdown cells, including their identifiers and text. * Standardized notebook content and cell updates for more consistent behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
import { beforeEach, describe, expect, it } from 'vitest'
|
|
|
|
import { notebooksState } from './notebooks-state'
|
|
import type { Notebook } from './types'
|
|
|
|
function makeNotebook(id: string, overrides: Partial<Notebook> = {}): Notebook {
|
|
return {
|
|
id,
|
|
type: 'notebook',
|
|
name: 'My Notebook',
|
|
description: '',
|
|
visibility: 'project',
|
|
favorite: false,
|
|
owner_id: 7,
|
|
project_id: 42,
|
|
content: { schema_version: 1, cells: [] },
|
|
...overrides,
|
|
}
|
|
}
|
|
|
|
describe('notebooksState', () => {
|
|
beforeEach(() => {
|
|
// notebooksState is a module-level singleton, so reset the state these tests touch
|
|
for (const id of Object.keys(notebooksState.notebooks)) {
|
|
delete notebooksState.notebooks[id]
|
|
}
|
|
notebooksState.needsSaving.clear()
|
|
})
|
|
|
|
it('addNotebook marks a locally-created notebook as new', () => {
|
|
notebooksState.addNotebook({ projectRef: 'ref', notebook: makeNotebook('notebook-1') })
|
|
|
|
expect(notebooksState.notebooks['notebook-1'].status).toBe('new')
|
|
})
|
|
|
|
it('setNotebook marks a notebook not yet in the store as saved', () => {
|
|
notebooksState.setNotebook({ projectRef: 'ref', notebook: makeNotebook('notebook-1') })
|
|
|
|
expect(notebooksState.notebooks['notebook-1'].status).toBe('saved')
|
|
})
|
|
|
|
it('editing a loaded (saved) notebook transitions it to unsaved and queues it for saving', () => {
|
|
notebooksState.setNotebook({ projectRef: 'ref', notebook: makeNotebook('notebook-1') })
|
|
|
|
notebooksState.updateCells({
|
|
id: 'notebook-1',
|
|
cells: [{ _tag: 'markdown_cell', id: 'cell-1', text: 'hello' }],
|
|
})
|
|
|
|
expect(notebooksState.notebooks['notebook-1'].status).toBe('unsaved')
|
|
expect(notebooksState.needsSaving.get('notebook-1')).toBe(false)
|
|
})
|
|
|
|
it('editing a notebook that has never been saved keeps it as new', () => {
|
|
notebooksState.addNotebook({ projectRef: 'ref', notebook: makeNotebook('notebook-1') })
|
|
|
|
notebooksState.updateCells({
|
|
id: 'notebook-1',
|
|
cells: [{ _tag: 'markdown_cell', id: 'cell-1', text: 'hello' }],
|
|
})
|
|
|
|
expect(notebooksState.notebooks['notebook-1'].status).toBe('new')
|
|
})
|
|
|
|
it('setNotebook does not downgrade an already-loaded notebook back to saved after edits', () => {
|
|
notebooksState.setNotebook({ projectRef: 'ref', notebook: makeNotebook('notebook-1') })
|
|
notebooksState.updateCells({
|
|
id: 'notebook-1',
|
|
cells: [{ _tag: 'markdown_cell', id: 'cell-1', text: 'hello' }],
|
|
})
|
|
expect(notebooksState.notebooks['notebook-1'].status).toBe('unsaved')
|
|
|
|
// Re-fetching/merging content for the same notebook (e.g. a second setNotebook
|
|
// call) must not reset its status back to 'saved' while edits are pending.
|
|
notebooksState.setNotebook({ projectRef: 'ref', notebook: makeNotebook('notebook-1') })
|
|
|
|
expect(notebooksState.notebooks['notebook-1'].status).toBe('unsaved')
|
|
})
|
|
})
|