fix(notebooks): reset insert offset when anchor cell moves (#49694)

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Bug fix

## What is the current behavior?

When a cell gets moved via `move_cell` operation in
`deriveNotebookDiff`, the `insertedAfter` offset map is not cleared for
that anchor cell. This causes later `insert_cell` operations anchored on
the same (now-moved) cell to apply the stale offset on top of the
correct current-position lookup, resulting in the new cell landing after
the wrong position.

## What is the new behavior?

The offset for an anchor cell is now cleared from `insertedAfter` when
it gets moved, since cells previously inserted after it stay behind at
its old location and should not affect subsequent inserts at its new
position.

A regression test has been added that reproduces the exact ticket
scenario (insert after cell-1, move cell-1 after cell-3, insert after
cell-1 again) and verifies the correct final cell order.

## Additional context

Fixes:
https://linear.app/supabase/issue/FE-4308/insert-anchored-to-a-previously-moved-cell-lands-after-the-wrong-cell

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

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed notebook cell insertions after moving an anchor cell, ensuring
new inserts appear relative to the anchor’s updated position.
* Preserved the placement of inserts made before the anchor cell was
moved.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Charis authored and GitHub committed 2026-08-28 12:12:04 -04:00
1 parent 8790e657e9
commit 86c813ec03
2 files changed
+38

No files matched your search

@@ -121,6 +121,41 @@ describe('applyNotebookOperations', () => {
])
})
it('resets the insert offset for an anchor cell once it gets moved', () => {
// cell-1 gets an insert right after it, then cell-1 itself moves after cell-3. A later
// insert anchored on cell-1 must land right after its *new* position — the first insert
// stayed behind at cell-1's old spot, so it shouldn't count toward this offset anymore.
const notebook: NotebookWire = {
schema_version: 1,
cells: [
{ _tag: 'markdown_cell', _id: 'cell-1', text: '1' },
{ _tag: 'markdown_cell', _id: 'cell-2', text: '2' },
{ _tag: 'markdown_cell', _id: 'cell-3', text: '3' },
{ _tag: 'markdown_cell', _id: 'cell-4', text: '4' },
],
}
const ops: NotebookOperation[] = [
{
_tag: 'insert_cell',
after_cell_id: 'cell-1',
cell: { _tag: 'markdown_cell', text: 'first' },
},
{ _tag: 'move_cell', cell_id: 'cell-1', after_cell_id: 'cell-3' },
{
_tag: 'insert_cell',
after_cell_id: 'cell-1',
cell: { _tag: 'markdown_cell', text: 'second' },
},
]
const result = applyNotebookOperations(notebook, ops)
expect(result.success).toBe(true)
if (!result.success) return
const texts = result.notebook.cells.map((cell) => ('text' in cell ? cell.text : undefined))
expect(texts).toEqual(['first', '2', '3', '1', 'second', '4'])
})
it('resolves a move anchored on another moved cell using its new position', () => {
// cell-1 moves after cell-3 first, landing at [cell-2, cell-3, cell-1]; cell-2 then moves
// after cell-1's *new* position, giving [cell-3, cell-1, cell-2].
@@ -256,6 +256,9 @@ export function deriveNotebookDiff(
}
entries.splice(found.index, 1)
// Cells already inserted after this anchor stay behind at its old position, so a
// later insert anchored on it should start counting from its new position again.
insertedAfter.delete(operation.cell_id)
const error = insertAfter(operation.after_cell_id, {
_tag: 'moved',
cell: found.cell,