From d06b5c8d5b21ec6ab8afb6cfdda1d08afe539087 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 04:35:47 +0000 Subject: [PATCH 1/2] Initial plan From 56249f5345cc8edacc0b0e082e59c8e31c3d7ee2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 04:53:51 +0000 Subject: [PATCH 2/2] fix: children not removed when parent is removed via removeCells Co-authored-by: hustcc <7856674+hustcc@users.noreply.github.com> --- __tests__/model/cell.spec.ts | 26 ++++++++++++++++++++++++++ src/model/cell.ts | 15 ++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/__tests__/model/cell.spec.ts b/__tests__/model/cell.spec.ts index 3396a092d2a..a46fe20776e 100644 --- a/__tests__/model/cell.spec.ts +++ b/__tests__/model/cell.spec.ts @@ -186,6 +186,32 @@ describe('Cell core API', () => { expect(parent.getChildren()?.map((c) => c.id)).toEqual(['child']) }) + it('removeCells on parent removes children even when model is null (simulates collection flow)', () => { + const parent = new Cell({ id: 'parent' } as any) + const child1 = new Cell({ id: 'child1' } as any) + const child2 = new Cell({ id: 'child2' } as any) + parent.model = model as any + child1.model = model as any + child2.model = model as any + + model.addCell(parent) + model.addCell(child1) + model.addCell(child2) + + parent.addChild(child1) + parent.addChild(child2) + expect((parent.getProp('children') as any as string[])?.length).toBe(2) + + // Simulate what collection.removeCells does: + // it sets model=null before calling cell.remove() + parent.model = null + parent.remove() + + // Children should have been removed from the model + expect(model.map['child1']).toBeUndefined() + expect(model.map['child2']).toBeUndefined() + }) + it('tools APIs: normalizeTools, set/get/add/remove/has', () => { expect(Cell.normalizeTools('a').items[0]).toBe('a') expect(Cell.normalizeTools(['a', 'b']).items.length).toBe(2) diff --git a/src/model/cell.ts b/src/model/cell.ts index 1afa5588a53..9da1def3599 100644 --- a/src/model/cell.ts +++ b/src/model/cell.ts @@ -1248,8 +1248,14 @@ export class Cell< if (nextChildrenIds.length !== childrenIds.length) { if (nextChildrenIds.length) { parent.store.set('children', nextChildrenIds, options) + if (parent._children) { + parent._children = parent._children.filter( + (c) => c.id !== this.id, + ) + } } else { parent.store.remove('children', options) + parent._children = null } } } @@ -1257,7 +1263,14 @@ export class Cell< this.setParent(null, options) if (options.deep !== false) { - this.eachChild((child) => child.remove(options)) + // When called from collection.removeCells, this.model is already null. + // Fall back to _children cache so children are still recursively removed. + const children = + this.getChildren() ?? + (this._children ? [...this._children] : null) + if (children) { + children.forEach((child) => child.remove(options)) + } } if (this.model) {