@marimo-team/islands 0.25.3-dev173 → 0.25.3-dev175
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ErrorBoundary-wT3f3iJ1.js → ErrorBoundary-DNvcAIsP.js} +1 -1
- package/dist/{any-language-editor-B92WMzoC.js → any-language-editor-BVFHDDQ3.js} +2 -2
- package/dist/{chat-ui-CuORr6fL.js → chat-ui-X-cWrL9u.js} +1222 -1222
- package/dist/{code-visibility-ZReaeMaF.js → code-visibility-CH1lmM1h.js} +2 -2
- package/dist/{common-DCevHg1m.js → common-DIrS1UR9.js} +1074 -1078
- package/dist/{data-grid-overlay-editor-CTC-bJus.js → data-grid-overlay-editor-DFLZvFK0.js} +1 -1
- package/dist/{dist-F8Ep36rk.js → dist-B1M0bGO3.js} +1 -1
- package/dist/{dist-D6d86eNJ.js → dist-BA13RJj5.js} +1 -1
- package/dist/{dist-Bvs24R_E.js → dist-BJtmSgcE.js} +48 -48
- package/dist/{dist-CN_BeG2I.js → dist-Ba2VIn1K.js} +53 -53
- package/dist/{dist-PXYI_yuP.js → dist-Bj4bmwUm.js} +12 -12
- package/dist/{dist-DoE4XJBC.js → dist-BmS-ZGjl.js} +8626 -8626
- package/dist/{dist-BorMD-uX.js → dist-Bzogh7CW.js} +87 -87
- package/dist/{dist-CN8zI-XC.js → dist-CThPVKaP.js} +1385 -1382
- package/dist/{dist-DiDibOYr.js → dist-CTi5FTiV.js} +87 -87
- package/dist/{dist-diIx5qJW.js → dist-Ck_C32ye.js} +2 -2
- package/dist/{dist-BLfKmR-l.js → dist-D1fnFp1J.js} +1 -1
- package/dist/{dist-OR1OnN-y.js → dist-D3x9__Fu.js} +46 -46
- package/dist/{dist-BMQf5zIS.js → dist-D7mrh5sO.js} +36 -36
- package/dist/{dist-CSJ0MDRw.js → dist-D9Q3xjiP.js} +1 -1
- package/dist/{dist-BuaRHxOc.js → dist-DP60Ubh8.js} +2 -2
- package/dist/{dist-CSbh1PNP.js → dist-DTv9KkpW.js} +12 -12
- package/dist/{dist-D-wwqlzJ.js → dist-DVVwOfrD.js} +109 -109
- package/dist/{dist-C8fAKSH1.js → dist-DYXM73-k.js} +36 -36
- package/dist/{dist-DBtSl3sf.js → dist-DjeybPOb.js} +1 -1
- package/dist/{dist-CrSP_H1M.js → dist-DtGn9N4h.js} +197 -197
- package/dist/{dist-CLdpGQVr.js → dist-KN80qWCP.js} +2 -2
- package/dist/{dist-Cg7gzw-a.js → dist-O0qFpEJh.js} +56 -56
- package/dist/{dist-CkTTIdBe.js → dist-OUle2RT7.js} +207 -207
- package/dist/{dist-BK4Oj99o.js → dist-T5rh6JvL.js} +1 -1
- package/dist/{error-entries-CmWMEsY_.js → error-entries-mpoD5t79.js} +4939 -4983
- package/dist/{esm-D2gTsXEV.js → esm-Bbw_Njjx.js} +575 -575
- package/dist/{esm-AMFssoNp.js → esm-mDQNEFe_.js} +354 -354
- package/dist/{feedback-button-DwXkmewo.js → feedback-button-DL0DJ-LB.js} +21 -21
- package/dist/{glide-data-editor-BlmcP-lw.js → glide-data-editor-n4wnx19S.js} +3 -3
- package/dist/{globals-BdRitZ4p.js → globals-NCsYyjpB.js} +1 -1
- package/dist/{html-to-image-bpiQh7ND.js → html-to-image-BoZthB4P.js} +454 -445
- package/dist/main.js +3587 -3587
- package/dist/{number-overlay-editor-DQG-hFHT.js → number-overlay-editor-rlvo4mo3.js} +1 -1
- package/dist/{process-output-BzloOI7F.js → process-output-DLS4Mqg_.js} +2 -2
- package/dist/{reveal-component-D3r3vSTK.js → reveal-component-BJfmRUzb.js} +3 -3
- package/package.json +1 -1
- package/src/__mocks__/document.tsx +54 -0
- package/src/__mocks__/notebook.ts +2 -1
- package/src/__mocks__/requests.ts +0 -2
- package/src/components/chat/chat-panel.tsx +3 -3
- package/src/components/datasources/__tests__/column-preview.test.tsx +6 -8
- package/src/components/datasources/column-preview.tsx +4 -8
- package/src/components/datasources/datasources.tsx +4 -3
- package/src/components/dependency-graph/minimap-content.tsx +2 -6
- package/src/components/dependency-graph/panels.tsx +2 -1
- package/src/components/editor/__tests__/Output.test.tsx +50 -32
- package/src/components/editor/__tests__/data-attributes.test.tsx +22 -11
- package/src/components/editor/__tests__/output-persistence.test.tsx +6 -1
- package/src/components/editor/actions/__tests__/name-cell-input.test.tsx +69 -0
- package/src/components/editor/actions/name-cell-input.tsx +4 -3
- package/src/components/editor/actions/useCellActionButton.tsx +20 -26
- package/src/components/editor/actions/useNotebookActions.tsx +13 -18
- package/src/components/editor/actions/useSetCodeVisibility.ts +10 -11
- package/src/components/editor/actions/useSetOutputsExpanded.ts +13 -18
- package/src/components/editor/cell/CreateCellButton.tsx +5 -9
- package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +3 -1
- package/src/components/editor/cell/code/cell-editor.tsx +13 -20
- package/src/components/editor/cell/useAddCell.ts +4 -8
- package/src/components/editor/cell/useDeleteCell.tsx +10 -36
- package/src/components/editor/cell/useRunCells.ts +2 -5
- package/src/components/editor/cell/useSplitCell.tsx +2 -1
- package/src/components/editor/chrome/panels/logs-panel.tsx +2 -1
- package/src/components/editor/chrome/panels/snippets-panel.tsx +5 -11
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +3 -1
- package/src/components/editor/columns/sortable-column.tsx +1 -1
- package/src/components/editor/connections/components.tsx +4 -9
- package/src/components/editor/controls/Controls.tsx +1 -1
- package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +9 -3
- package/src/components/editor/documentation.css +34 -11
- package/src/components/editor/errors/auto-fix.tsx +4 -8
- package/src/components/editor/file-tree/file-explorer.tsx +3 -7
- package/src/components/editor/links/__tests__/cell-link.test.tsx +3 -1
- package/src/components/editor/links/cell-link.tsx +2 -1
- package/src/components/editor/navigation/__tests__/clipboard.test.ts +60 -38
- package/src/components/editor/navigation/__tests__/navigation.test.ts +73 -64
- package/src/components/editor/navigation/clipboard.ts +12 -11
- package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +11 -20
- package/src/components/editor/navigation/navigation.ts +20 -28
- package/src/components/editor/notebook-cell.tsx +7 -10
- package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +125 -69
- package/src/components/editor/renderers/cell-array.tsx +10 -17
- package/src/components/markdown/markdown-renderer.tsx +4 -8
- package/src/components/pages/edit-page.tsx +32 -17
- package/src/components/scratchpad/scratchpad.test.tsx +3 -1
- package/src/components/scratchpad/scratchpad.tsx +4 -7
- package/src/components/slides/__tests__/minimap-actions.test.tsx +9 -25
- package/src/components/slides/minimap.tsx +7 -3
- package/src/components/slides/slide-cell-view.tsx +3 -3
- package/src/components/sort/SortableCellsProvider.tsx +2 -1
- package/src/core/ai/__tests__/staged-cells.test.ts +18 -20
- package/src/core/ai/staged-cells.ts +8 -16
- package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +2 -2
- package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +2 -2
- package/src/core/ai/tools/base.ts +2 -2
- package/src/core/ai/tools/edit-notebook-tool.ts +13 -21
- package/src/core/cells/__tests__/actions.test.ts +474 -34
- package/src/core/cells/__tests__/add-missing-import.test.ts +7 -8
- package/src/core/cells/__tests__/cells.test.ts +171 -813
- package/src/core/cells/__tests__/document.test.ts +5 -35
- package/src/core/cells/__tests__/notebook-outline.test.ts +7 -1
- package/src/core/cells/__tests__/outputs.test.tsx +71 -53
- package/src/core/cells/actions.ts +391 -3
- package/src/core/cells/add-missing-import.ts +46 -42
- package/src/core/cells/cells.ts +38 -413
- package/src/core/cells/document.ts +7 -4
- package/src/core/cells/outputs.ts +12 -28
- package/src/core/codemirror/cells/extensions.ts +6 -6
- package/src/core/codemirror/cells/state.ts +1 -1
- package/src/core/codemirror/keymaps/vim.ts +2 -2
- package/src/core/edit-app.tsx +19 -27
- package/src/core/islands/bridge.ts +0 -2
- package/src/core/kernel/handlers.ts +3 -3
- package/src/core/network/__tests__/requests-lazy.test.ts +1 -3
- package/src/core/network/requests-lazy.ts +0 -2
- package/src/core/network/requests-network.ts +0 -16
- package/src/core/network/requests-static.ts +0 -2
- package/src/core/network/requests-toasting.tsx +0 -2
- package/src/core/network/types.ts +0 -7
- package/src/core/notebook/document/__tests__/codemirror.test.ts +5 -0
- package/src/core/notebook/document/__tests__/draft.test.ts +41 -0
- package/src/core/notebook/document/__tests__/state.test.ts +21 -0
- package/src/core/notebook/document/draft.ts +35 -5
- package/src/core/notebook/document/index.ts +1 -0
- package/src/core/notebook/document/state.ts +6 -2
- package/src/core/session/useNotebookSession.tsx +6 -2
- package/src/core/wasm/bridge.ts +0 -16
- package/src/css/globals.css +56 -22
- package/src/stories/runtime-story.tsx +22 -15
|
@@ -4,6 +4,7 @@ import { python } from "@codemirror/lang-python";
|
|
|
4
4
|
import { EditorState } from "@codemirror/state";
|
|
5
5
|
import { EditorView } from "@codemirror/view";
|
|
6
6
|
import { createStore } from "jotai";
|
|
7
|
+
import { createRef } from "react";
|
|
7
8
|
import {
|
|
8
9
|
afterAll,
|
|
9
10
|
beforeAll,
|
|
@@ -17,11 +18,12 @@ import {
|
|
|
17
18
|
import { MockNotebook } from "@/__mocks__/notebook";
|
|
18
19
|
import { cellId } from "@/__tests__/branded";
|
|
19
20
|
import type { CellHandle } from "@/components/editor/notebook-cell";
|
|
20
|
-
import { CellId, SCRATCH_CELL_ID
|
|
21
|
+
import { CellId, SCRATCH_CELL_ID } from "@/core/cells/ids";
|
|
21
22
|
import { foldAllBulk, unfoldAllBulk } from "@/core/codemirror/editing/commands";
|
|
22
23
|
import { adaptiveLanguageConfiguration } from "@/core/codemirror/language/extension";
|
|
23
24
|
import { OverridingHotkeyProvider } from "@/core/hotkeys/hotkeys";
|
|
24
25
|
import type { OutputMessage } from "@/core/kernel/messages";
|
|
26
|
+
import type { CellConfig } from "@/core/network/types";
|
|
25
27
|
import {
|
|
26
28
|
type CollapsibleTree,
|
|
27
29
|
MultiColumn,
|
|
@@ -39,7 +41,12 @@ import {
|
|
|
39
41
|
scrollToBottom,
|
|
40
42
|
scrollToTop,
|
|
41
43
|
} from "../scrollCellIntoView";
|
|
42
|
-
import
|
|
44
|
+
import {
|
|
45
|
+
type CellData,
|
|
46
|
+
createCell,
|
|
47
|
+
createCellConfig,
|
|
48
|
+
createCellRuntimeState,
|
|
49
|
+
} from "../types";
|
|
43
50
|
|
|
44
51
|
vi.mock("@/core/codemirror/editing/commands", () => ({
|
|
45
52
|
foldAllBulk: vi.fn(),
|
|
@@ -120,8 +127,7 @@ describe("cell reducer", () => {
|
|
|
120
127
|
let cells: ReturnType<typeof flattenTopLevelNotebookCells>;
|
|
121
128
|
let firstCellId: CellId;
|
|
122
129
|
|
|
123
|
-
const
|
|
124
|
-
state = reducer(state, action);
|
|
130
|
+
const mountEditors = () => {
|
|
125
131
|
for (const [cellIdString, handle] of Object.entries(state.cellHandles)) {
|
|
126
132
|
// @ts-expect-error - Typescript Object.entries doesn't know that keys are CellId
|
|
127
133
|
const cid: CellId = cellIdString;
|
|
@@ -135,7 +141,76 @@ describe("cell reducer", () => {
|
|
|
135
141
|
}
|
|
136
142
|
}
|
|
137
143
|
cells = flattenTopLevelNotebookCells(state);
|
|
138
|
-
}
|
|
144
|
+
};
|
|
145
|
+
const actions = createActions((action) => {
|
|
146
|
+
state = reducer(state, action);
|
|
147
|
+
mountEditors();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
/** Put a cell into the notebook the way the document would. */
|
|
151
|
+
function seedCell({
|
|
152
|
+
cellId,
|
|
153
|
+
before,
|
|
154
|
+
code = "",
|
|
155
|
+
name,
|
|
156
|
+
config,
|
|
157
|
+
newCellId,
|
|
158
|
+
hideCode,
|
|
159
|
+
autoFocus = true,
|
|
160
|
+
}: {
|
|
161
|
+
cellId: CellId | "__end__" | { type: "__end__"; columnId: CellColumnId };
|
|
162
|
+
before: boolean;
|
|
163
|
+
code?: string;
|
|
164
|
+
name?: string;
|
|
165
|
+
config?: CellConfig;
|
|
166
|
+
newCellId?: CellId;
|
|
167
|
+
hideCode?: boolean;
|
|
168
|
+
autoFocus?: boolean;
|
|
169
|
+
}): CellId {
|
|
170
|
+
let column: CollapsibleTree<CellId>;
|
|
171
|
+
let cellIndex: number;
|
|
172
|
+
if (cellId === "__end__") {
|
|
173
|
+
column = state.cellIds.atOrThrow(0);
|
|
174
|
+
cellIndex = column.length;
|
|
175
|
+
} else if (typeof cellId === "string") {
|
|
176
|
+
column = state.cellIds.findWithId(cellId);
|
|
177
|
+
cellIndex = column.topLevelIds.indexOf(cellId);
|
|
178
|
+
} else {
|
|
179
|
+
column = state.cellIds.get(cellId.columnId) ?? state.cellIds.atOrThrow(0);
|
|
180
|
+
cellIndex = column.length;
|
|
181
|
+
}
|
|
182
|
+
const id = newCellId ?? CellId.create();
|
|
183
|
+
state = {
|
|
184
|
+
...state,
|
|
185
|
+
cellIds: state.cellIds.insertId(
|
|
186
|
+
id,
|
|
187
|
+
column.id,
|
|
188
|
+
before ? cellIndex : cellIndex + 1,
|
|
189
|
+
),
|
|
190
|
+
cellData: {
|
|
191
|
+
...state.cellData,
|
|
192
|
+
[id]: createCell({
|
|
193
|
+
id,
|
|
194
|
+
code,
|
|
195
|
+
name,
|
|
196
|
+
config: createCellConfig({
|
|
197
|
+
...config,
|
|
198
|
+
...(hideCode != null && { hide_code: hideCode }),
|
|
199
|
+
}),
|
|
200
|
+
edited: Boolean(code),
|
|
201
|
+
}),
|
|
202
|
+
},
|
|
203
|
+
cellRuntime: { ...state.cellRuntime, [id]: createCellRuntimeState() },
|
|
204
|
+
cellHandles: { ...state.cellHandles, [id]: createRef() },
|
|
205
|
+
scrollKey: autoFocus ? id : null,
|
|
206
|
+
untouchedNewCells:
|
|
207
|
+
hideCode && autoFocus
|
|
208
|
+
? new Set([...state.untouchedNewCells, id])
|
|
209
|
+
: state.untouchedNewCells,
|
|
210
|
+
};
|
|
211
|
+
mountEditors();
|
|
212
|
+
return id;
|
|
213
|
+
}
|
|
139
214
|
|
|
140
215
|
let i = 0;
|
|
141
216
|
const originalCreate = CellId.create.bind(CellId);
|
|
@@ -151,7 +226,7 @@ describe("cell reducer", () => {
|
|
|
151
226
|
|
|
152
227
|
state = initialNotebookState();
|
|
153
228
|
state.cellIds = MultiColumn.from([]);
|
|
154
|
-
|
|
229
|
+
seedCell({ cellId: "__end__", before: false });
|
|
155
230
|
firstCellId = state.cellIds.inOrderIds[0];
|
|
156
231
|
});
|
|
157
232
|
|
|
@@ -159,181 +234,6 @@ describe("cell reducer", () => {
|
|
|
159
234
|
CellId.create = originalCreate;
|
|
160
235
|
});
|
|
161
236
|
|
|
162
|
-
it("can add a cell after another cell", () => {
|
|
163
|
-
actions.createNewCell({
|
|
164
|
-
cellId: firstCellId,
|
|
165
|
-
before: false,
|
|
166
|
-
});
|
|
167
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
168
|
-
"
|
|
169
|
-
[0] ''
|
|
170
|
-
|
|
171
|
-
[1] ''
|
|
172
|
-
"
|
|
173
|
-
`);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it("can add a cell to the end with code", () => {
|
|
177
|
-
actions.createNewCell({
|
|
178
|
-
cellId: "__end__",
|
|
179
|
-
code: "import numpy as np",
|
|
180
|
-
before: false,
|
|
181
|
-
});
|
|
182
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
183
|
-
"
|
|
184
|
-
[0] ''
|
|
185
|
-
|
|
186
|
-
[1] 'import numpy as np'
|
|
187
|
-
"
|
|
188
|
-
`);
|
|
189
|
-
|
|
190
|
-
// Cell should be added to the end and edited
|
|
191
|
-
expect(cells[1].code).toBe("import numpy as np");
|
|
192
|
-
expect(cells[1].edited).toBe(true);
|
|
193
|
-
expect(cells[1].lastCodeRun).toBe(null);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
it("can add a cell before another cell", () => {
|
|
197
|
-
actions.createNewCell({
|
|
198
|
-
cellId: firstCellId,
|
|
199
|
-
before: true,
|
|
200
|
-
});
|
|
201
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
202
|
-
"
|
|
203
|
-
[1] ''
|
|
204
|
-
|
|
205
|
-
[0] ''
|
|
206
|
-
"
|
|
207
|
-
`);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it("can add a cell with name and config", () => {
|
|
211
|
-
actions.createNewCell({
|
|
212
|
-
cellId: firstCellId,
|
|
213
|
-
before: false,
|
|
214
|
-
code: "x = 1",
|
|
215
|
-
name: "My Cell",
|
|
216
|
-
config: { hide_code: true, disabled: false },
|
|
217
|
-
});
|
|
218
|
-
const newCellId = state.cellIds.inOrderIds[1];
|
|
219
|
-
expect(state.cellData[newCellId].name).toBe("My Cell");
|
|
220
|
-
expect(state.cellData[newCellId].config.hide_code).toBe(true);
|
|
221
|
-
expect(state.cellData[newCellId].config.disabled).toBe(false);
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
it("can delete a Python cell and undo delete", () => {
|
|
225
|
-
actions.createNewCell({
|
|
226
|
-
cellId: firstCellId,
|
|
227
|
-
before: false,
|
|
228
|
-
});
|
|
229
|
-
actions.deleteCell({
|
|
230
|
-
cellId: firstCellId,
|
|
231
|
-
});
|
|
232
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
233
|
-
"
|
|
234
|
-
[1] ''
|
|
235
|
-
"
|
|
236
|
-
`);
|
|
237
|
-
|
|
238
|
-
// undo
|
|
239
|
-
actions.undoDeleteCell();
|
|
240
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
241
|
-
"
|
|
242
|
-
[2] ''
|
|
243
|
-
|
|
244
|
-
[1] ''
|
|
245
|
-
"
|
|
246
|
-
`);
|
|
247
|
-
|
|
248
|
-
// Verify scrollKey is set to the restored cell
|
|
249
|
-
expect(state.scrollKey).toBe("2");
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
it("can delete a SQL cell and undo delete", () => {
|
|
253
|
-
actions.createNewCell({
|
|
254
|
-
cellId: firstCellId,
|
|
255
|
-
before: false,
|
|
256
|
-
code: `df = mo.sql("""SELECT * FROM table""")`,
|
|
257
|
-
});
|
|
258
|
-
const newCellId = state.cellIds.getColumns()[0].atOrThrow(1);
|
|
259
|
-
actions.deleteCell({
|
|
260
|
-
cellId: newCellId,
|
|
261
|
-
});
|
|
262
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
263
|
-
"
|
|
264
|
-
[0] ''
|
|
265
|
-
"
|
|
266
|
-
`);
|
|
267
|
-
|
|
268
|
-
// undo
|
|
269
|
-
actions.undoDeleteCell();
|
|
270
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
271
|
-
"
|
|
272
|
-
[0] ''
|
|
273
|
-
|
|
274
|
-
[2] 'df = mo.sql("""SELECT * FROM table""")'
|
|
275
|
-
"
|
|
276
|
-
`);
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
it("can delete a Markdown cell and undo delete", () => {
|
|
280
|
-
const text = "The quick brown fox jumps over the lazy dog.";
|
|
281
|
-
actions.createNewCell({
|
|
282
|
-
cellId: firstCellId,
|
|
283
|
-
before: false,
|
|
284
|
-
code: `mo.md(r"""${text}""")`,
|
|
285
|
-
});
|
|
286
|
-
const newCellId = state.cellIds.getColumns()[0].atOrThrow(1);
|
|
287
|
-
actions.deleteCell({
|
|
288
|
-
cellId: newCellId,
|
|
289
|
-
});
|
|
290
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
291
|
-
"
|
|
292
|
-
[0] ''
|
|
293
|
-
"
|
|
294
|
-
`);
|
|
295
|
-
|
|
296
|
-
// undo
|
|
297
|
-
actions.undoDeleteCell();
|
|
298
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
299
|
-
"
|
|
300
|
-
[0] ''
|
|
301
|
-
|
|
302
|
-
[2] 'mo.md(r"""The quick brown fox jumps over the lazy dog.""")'
|
|
303
|
-
"
|
|
304
|
-
`);
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it("undo delete restores cell config (hide_code, disabled)", () => {
|
|
308
|
-
actions.createNewCell({
|
|
309
|
-
cellId: firstCellId,
|
|
310
|
-
before: false,
|
|
311
|
-
code: "x = 1",
|
|
312
|
-
});
|
|
313
|
-
const newCellId = state.cellIds.getColumns()[0].atOrThrow(1);
|
|
314
|
-
|
|
315
|
-
// Set config to hidden and disabled
|
|
316
|
-
actions.updateCellConfig({
|
|
317
|
-
cellId: newCellId,
|
|
318
|
-
config: { hide_code: true, disabled: true },
|
|
319
|
-
});
|
|
320
|
-
expect(state.cellData[newCellId].config.hide_code).toBe(true);
|
|
321
|
-
expect(state.cellData[newCellId].config.disabled).toBe(true);
|
|
322
|
-
|
|
323
|
-
// Delete the cell
|
|
324
|
-
actions.deleteCell({ cellId: newCellId });
|
|
325
|
-
expect(state.cellIds.inOrderIds).not.toContain(newCellId);
|
|
326
|
-
|
|
327
|
-
// Undo delete
|
|
328
|
-
actions.undoDeleteCell();
|
|
329
|
-
const restoredCellId =
|
|
330
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
331
|
-
|
|
332
|
-
// Config should be preserved
|
|
333
|
-
expect(state.cellData[restoredCellId].config.hide_code).toBe(true);
|
|
334
|
-
expect(state.cellData[restoredCellId].config.disabled).toBe(true);
|
|
335
|
-
});
|
|
336
|
-
|
|
337
237
|
it("can update a cell", () => {
|
|
338
238
|
actions.updateCellCode({
|
|
339
239
|
cellId: firstCellId,
|
|
@@ -348,7 +248,7 @@ describe("cell reducer", () => {
|
|
|
348
248
|
});
|
|
349
249
|
|
|
350
250
|
it("can move a cell", () => {
|
|
351
|
-
|
|
251
|
+
seedCell({
|
|
352
252
|
cellId: firstCellId,
|
|
353
253
|
before: false,
|
|
354
254
|
});
|
|
@@ -462,11 +362,11 @@ describe("cell reducer", () => {
|
|
|
462
362
|
});
|
|
463
363
|
|
|
464
364
|
it("can drag and drop a cell", () => {
|
|
465
|
-
|
|
365
|
+
seedCell({
|
|
466
366
|
cellId: firstCellId,
|
|
467
367
|
before: false,
|
|
468
368
|
});
|
|
469
|
-
|
|
369
|
+
seedCell({
|
|
470
370
|
cellId: cellId("1"),
|
|
471
371
|
before: false,
|
|
472
372
|
});
|
|
@@ -512,11 +412,11 @@ describe("cell reducer", () => {
|
|
|
512
412
|
});
|
|
513
413
|
|
|
514
414
|
it("can move a cell to an exact index within a column", () => {
|
|
515
|
-
|
|
415
|
+
seedCell({
|
|
516
416
|
cellId: firstCellId,
|
|
517
417
|
before: false,
|
|
518
418
|
});
|
|
519
|
-
|
|
419
|
+
seedCell({
|
|
520
420
|
cellId: cellId("1"),
|
|
521
421
|
before: false,
|
|
522
422
|
});
|
|
@@ -540,11 +440,11 @@ describe("cell reducer", () => {
|
|
|
540
440
|
});
|
|
541
441
|
|
|
542
442
|
it("can move a cell to an exact index across columns", () => {
|
|
543
|
-
|
|
443
|
+
seedCell({
|
|
544
444
|
cellId: firstCellId,
|
|
545
445
|
before: false,
|
|
546
446
|
});
|
|
547
|
-
|
|
447
|
+
seedCell({
|
|
548
448
|
cellId: cellId("1"),
|
|
549
449
|
before: false,
|
|
550
450
|
});
|
|
@@ -573,11 +473,11 @@ describe("cell reducer", () => {
|
|
|
573
473
|
});
|
|
574
474
|
|
|
575
475
|
it("moveCellToIndex is a no-op when moving to the same position", () => {
|
|
576
|
-
|
|
476
|
+
seedCell({
|
|
577
477
|
cellId: firstCellId,
|
|
578
478
|
before: false,
|
|
579
479
|
});
|
|
580
|
-
|
|
480
|
+
seedCell({
|
|
581
481
|
cellId: cellId("1"),
|
|
582
482
|
before: false,
|
|
583
483
|
});
|
|
@@ -595,7 +495,7 @@ describe("cell reducer", () => {
|
|
|
595
495
|
});
|
|
596
496
|
|
|
597
497
|
it("moveCellToIndex is a no-op for an invalid columnId", () => {
|
|
598
|
-
|
|
498
|
+
seedCell({
|
|
599
499
|
cellId: firstCellId,
|
|
600
500
|
before: false,
|
|
601
501
|
});
|
|
@@ -612,11 +512,11 @@ describe("cell reducer", () => {
|
|
|
612
512
|
});
|
|
613
513
|
|
|
614
514
|
it("can move multiple cells relative to target", () => {
|
|
615
|
-
|
|
515
|
+
seedCell({
|
|
616
516
|
cellId: firstCellId,
|
|
617
517
|
before: false,
|
|
618
518
|
});
|
|
619
|
-
|
|
519
|
+
seedCell({
|
|
620
520
|
cellId: cellId("1"),
|
|
621
521
|
before: false,
|
|
622
522
|
});
|
|
@@ -647,143 +547,6 @@ describe("cell reducer", () => {
|
|
|
647
547
|
`);
|
|
648
548
|
});
|
|
649
549
|
|
|
650
|
-
it("can undo cut-paste (move with previousPlacements)", () => {
|
|
651
|
-
actions.createNewCell({
|
|
652
|
-
cellId: firstCellId,
|
|
653
|
-
before: false,
|
|
654
|
-
});
|
|
655
|
-
actions.createNewCell({
|
|
656
|
-
cellId: cellId("1"),
|
|
657
|
-
before: false,
|
|
658
|
-
});
|
|
659
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
660
|
-
"
|
|
661
|
-
[0] ''
|
|
662
|
-
|
|
663
|
-
[1] ''
|
|
664
|
-
|
|
665
|
-
[2] ''
|
|
666
|
-
"
|
|
667
|
-
`);
|
|
668
|
-
|
|
669
|
-
const col = state.cellIds.findWithId(firstCellId);
|
|
670
|
-
const previousPlacements = [
|
|
671
|
-
{
|
|
672
|
-
columnId: col.id,
|
|
673
|
-
index: col.indexOfOrThrow(
|
|
674
|
-
firstCellId,
|
|
675
|
-
) as import("@/utils/id-tree").CellIndex,
|
|
676
|
-
},
|
|
677
|
-
{
|
|
678
|
-
columnId: col.id,
|
|
679
|
-
index: col.indexOfOrThrow(
|
|
680
|
-
cellId("1"),
|
|
681
|
-
) as import("@/utils/id-tree").CellIndex,
|
|
682
|
-
},
|
|
683
|
-
];
|
|
684
|
-
|
|
685
|
-
actions.moveCellsRelativeTo({
|
|
686
|
-
cellIds: [firstCellId, cellId("1")],
|
|
687
|
-
targetCellId: cellId("2"),
|
|
688
|
-
position: "after",
|
|
689
|
-
previousPlacements,
|
|
690
|
-
});
|
|
691
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
692
|
-
"
|
|
693
|
-
[2] ''
|
|
694
|
-
|
|
695
|
-
[0] ''
|
|
696
|
-
|
|
697
|
-
[1] ''
|
|
698
|
-
"
|
|
699
|
-
`);
|
|
700
|
-
|
|
701
|
-
actions.undoDeleteCell();
|
|
702
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
703
|
-
"
|
|
704
|
-
[0] ''
|
|
705
|
-
|
|
706
|
-
[1] ''
|
|
707
|
-
|
|
708
|
-
[2] ''
|
|
709
|
-
"
|
|
710
|
-
`);
|
|
711
|
-
});
|
|
712
|
-
|
|
713
|
-
it("undo order: cut-paste then delete — first undo restores delete, second undo undoes move", () => {
|
|
714
|
-
actions.createNewCell({
|
|
715
|
-
cellId: firstCellId,
|
|
716
|
-
before: false,
|
|
717
|
-
});
|
|
718
|
-
actions.createNewCell({
|
|
719
|
-
cellId: cellId("1"),
|
|
720
|
-
before: false,
|
|
721
|
-
});
|
|
722
|
-
|
|
723
|
-
const col = state.cellIds.findWithId(firstCellId);
|
|
724
|
-
const previousPlacements = [
|
|
725
|
-
{
|
|
726
|
-
columnId: col.id,
|
|
727
|
-
index: col.indexOfOrThrow(
|
|
728
|
-
firstCellId,
|
|
729
|
-
) as import("@/utils/id-tree").CellIndex,
|
|
730
|
-
},
|
|
731
|
-
{
|
|
732
|
-
columnId: col.id,
|
|
733
|
-
index: col.indexOfOrThrow(
|
|
734
|
-
cellId("1"),
|
|
735
|
-
) as import("@/utils/id-tree").CellIndex,
|
|
736
|
-
},
|
|
737
|
-
];
|
|
738
|
-
|
|
739
|
-
actions.moveCellsRelativeTo({
|
|
740
|
-
cellIds: [firstCellId, cellId("1")],
|
|
741
|
-
targetCellId: cellId("2"),
|
|
742
|
-
position: "after",
|
|
743
|
-
previousPlacements,
|
|
744
|
-
});
|
|
745
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
746
|
-
"
|
|
747
|
-
[2] ''
|
|
748
|
-
|
|
749
|
-
[0] ''
|
|
750
|
-
|
|
751
|
-
[1] ''
|
|
752
|
-
"
|
|
753
|
-
`);
|
|
754
|
-
|
|
755
|
-
actions.deleteCell({ cellId: cellId("2") });
|
|
756
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
757
|
-
"
|
|
758
|
-
[0] ''
|
|
759
|
-
|
|
760
|
-
[1] ''
|
|
761
|
-
"
|
|
762
|
-
`);
|
|
763
|
-
|
|
764
|
-
actions.undoDeleteCell();
|
|
765
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
766
|
-
"
|
|
767
|
-
[3] ''
|
|
768
|
-
|
|
769
|
-
[0] ''
|
|
770
|
-
|
|
771
|
-
[1] ''
|
|
772
|
-
"
|
|
773
|
-
`);
|
|
774
|
-
|
|
775
|
-
actions.undoDeleteCell();
|
|
776
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
777
|
-
"
|
|
778
|
-
[0] ''
|
|
779
|
-
|
|
780
|
-
[1] ''
|
|
781
|
-
|
|
782
|
-
[3] ''
|
|
783
|
-
"
|
|
784
|
-
`);
|
|
785
|
-
});
|
|
786
|
-
|
|
787
550
|
it("keeps error evidence after an edit and a new queued run", () => {
|
|
788
551
|
const code = "raise ValueError('old failure')";
|
|
789
552
|
const output: OutputMessage = {
|
|
@@ -1167,7 +930,7 @@ describe("cell reducer", () => {
|
|
|
1167
930
|
formattingChange: false,
|
|
1168
931
|
});
|
|
1169
932
|
// Add cell
|
|
1170
|
-
|
|
933
|
+
seedCell({
|
|
1171
934
|
cellId: firstCellId,
|
|
1172
935
|
before: false,
|
|
1173
936
|
});
|
|
@@ -1272,33 +1035,6 @@ describe("cell reducer", () => {
|
|
|
1272
1035
|
expect(cell.edited).toBe(false);
|
|
1273
1036
|
});
|
|
1274
1037
|
|
|
1275
|
-
it("can update a cells config", () => {
|
|
1276
|
-
const firstCellId = cells[0].id;
|
|
1277
|
-
let cell = cells[0];
|
|
1278
|
-
// Starts empty
|
|
1279
|
-
expect(cell.config).toEqual({
|
|
1280
|
-
disabled: false,
|
|
1281
|
-
hide_code: false,
|
|
1282
|
-
column: null,
|
|
1283
|
-
expand_output: false,
|
|
1284
|
-
});
|
|
1285
|
-
|
|
1286
|
-
actions.updateCellConfig({
|
|
1287
|
-
cellId: firstCellId,
|
|
1288
|
-
config: { disabled: true },
|
|
1289
|
-
});
|
|
1290
|
-
cell = cells[0];
|
|
1291
|
-
expect(cell.config.disabled).toBe(true);
|
|
1292
|
-
|
|
1293
|
-
// Revert
|
|
1294
|
-
actions.updateCellConfig({
|
|
1295
|
-
cellId: firstCellId,
|
|
1296
|
-
config: { disabled: false },
|
|
1297
|
-
});
|
|
1298
|
-
cell = cells[0];
|
|
1299
|
-
expect(cell.config.disabled).toBe(false);
|
|
1300
|
-
});
|
|
1301
|
-
|
|
1302
1038
|
it("can run a stopped cell", () => {
|
|
1303
1039
|
// Update code of first cell
|
|
1304
1040
|
actions.updateCellCode({
|
|
@@ -1704,8 +1440,8 @@ describe("cell reducer", () => {
|
|
|
1704
1440
|
});
|
|
1705
1441
|
|
|
1706
1442
|
it("can send a cell to the top", () => {
|
|
1707
|
-
|
|
1708
|
-
|
|
1443
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1444
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
1709
1445
|
actions.sendToTop({ cellId: cellId("2") });
|
|
1710
1446
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
1711
1447
|
"
|
|
@@ -1719,8 +1455,8 @@ describe("cell reducer", () => {
|
|
|
1719
1455
|
});
|
|
1720
1456
|
|
|
1721
1457
|
it("can send a cell to the bottom", () => {
|
|
1722
|
-
|
|
1723
|
-
|
|
1458
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1459
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
1724
1460
|
actions.sendToBottom({ cellId: firstCellId });
|
|
1725
1461
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
1726
1462
|
"
|
|
@@ -1734,8 +1470,8 @@ describe("cell reducer", () => {
|
|
|
1734
1470
|
});
|
|
1735
1471
|
|
|
1736
1472
|
it("can focus cells", () => {
|
|
1737
|
-
|
|
1738
|
-
|
|
1473
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1474
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
1739
1475
|
|
|
1740
1476
|
actions.focusCell({ cellId: cellId("1"), where: "before" });
|
|
1741
1477
|
expect(focusAndScrollCellIntoView).toHaveBeenCalledWith(
|
|
@@ -1751,11 +1487,6 @@ describe("cell reducer", () => {
|
|
|
1751
1487
|
expect(scrollToBottom).toHaveBeenCalled();
|
|
1752
1488
|
});
|
|
1753
1489
|
|
|
1754
|
-
it("can update cell name", () => {
|
|
1755
|
-
actions.updateCellName({ cellId: firstCellId, name: "Test Cell" });
|
|
1756
|
-
expect(state.cellData[firstCellId].name).toBe("Test Cell");
|
|
1757
|
-
});
|
|
1758
|
-
|
|
1759
1490
|
it("can fold and unfold all cells", () => {
|
|
1760
1491
|
actions.foldAll();
|
|
1761
1492
|
expect(foldAllBulk).toHaveBeenCalled();
|
|
@@ -1784,13 +1515,13 @@ describe("cell reducer", () => {
|
|
|
1784
1515
|
});
|
|
1785
1516
|
|
|
1786
1517
|
it("can collapse and expand cells", () => {
|
|
1787
|
-
|
|
1788
|
-
|
|
1518
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1519
|
+
seedCell({
|
|
1789
1520
|
cellId: cellId("1"),
|
|
1790
1521
|
before: false,
|
|
1791
1522
|
code: "# Header",
|
|
1792
1523
|
});
|
|
1793
|
-
|
|
1524
|
+
seedCell({
|
|
1794
1525
|
cellId: cellId("2"),
|
|
1795
1526
|
before: false,
|
|
1796
1527
|
code: "## Subheader",
|
|
@@ -1812,13 +1543,13 @@ describe("cell reducer", () => {
|
|
|
1812
1543
|
});
|
|
1813
1544
|
|
|
1814
1545
|
it("can collapse and expand all cells in multiple columns", () => {
|
|
1815
|
-
|
|
1816
|
-
|
|
1546
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1547
|
+
seedCell({
|
|
1817
1548
|
cellId: cellId("1"),
|
|
1818
1549
|
before: false,
|
|
1819
1550
|
code: "# First Column Header",
|
|
1820
1551
|
});
|
|
1821
|
-
|
|
1552
|
+
seedCell({
|
|
1822
1553
|
cellId: cellId("2"),
|
|
1823
1554
|
before: false,
|
|
1824
1555
|
code: "## First Column Subheader",
|
|
@@ -1826,12 +1557,12 @@ describe("cell reducer", () => {
|
|
|
1826
1557
|
|
|
1827
1558
|
actions.addColumnBreakpoint({ cellId: cellId("2") });
|
|
1828
1559
|
|
|
1829
|
-
|
|
1560
|
+
seedCell({
|
|
1830
1561
|
cellId: cellId("3"),
|
|
1831
1562
|
before: false,
|
|
1832
1563
|
code: "# Second Column Header",
|
|
1833
1564
|
});
|
|
1834
|
-
|
|
1565
|
+
seedCell({
|
|
1835
1566
|
cellId: cellId("4"),
|
|
1836
1567
|
before: false,
|
|
1837
1568
|
code: "## Second Column Subheader",
|
|
@@ -1879,18 +1610,18 @@ describe("cell reducer", () => {
|
|
|
1879
1610
|
});
|
|
1880
1611
|
|
|
1881
1612
|
it("can collapse and expand nested cells in one call", () => {
|
|
1882
|
-
|
|
1883
|
-
|
|
1613
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1614
|
+
seedCell({
|
|
1884
1615
|
cellId: cellId("1"),
|
|
1885
1616
|
before: false,
|
|
1886
1617
|
code: "# Header",
|
|
1887
1618
|
});
|
|
1888
|
-
|
|
1619
|
+
seedCell({
|
|
1889
1620
|
cellId: cellId("2"),
|
|
1890
1621
|
before: false,
|
|
1891
1622
|
code: "## Subheader",
|
|
1892
1623
|
});
|
|
1893
|
-
|
|
1624
|
+
seedCell({
|
|
1894
1625
|
cellId: cellId("3"),
|
|
1895
1626
|
before: false,
|
|
1896
1627
|
code: "### Subsubheader",
|
|
@@ -1934,18 +1665,18 @@ describe("cell reducer", () => {
|
|
|
1934
1665
|
});
|
|
1935
1666
|
|
|
1936
1667
|
it("can collapse all cells when nested heading ranges end at the same cell", () => {
|
|
1937
|
-
|
|
1938
|
-
|
|
1668
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1669
|
+
seedCell({
|
|
1939
1670
|
cellId: cellId("1"),
|
|
1940
1671
|
before: false,
|
|
1941
1672
|
code: "# Header",
|
|
1942
1673
|
});
|
|
1943
|
-
|
|
1674
|
+
seedCell({
|
|
1944
1675
|
cellId: cellId("2"),
|
|
1945
1676
|
before: false,
|
|
1946
1677
|
code: "## Subheader",
|
|
1947
1678
|
});
|
|
1948
|
-
|
|
1679
|
+
seedCell({
|
|
1949
1680
|
cellId: cellId("3"),
|
|
1950
1681
|
before: false,
|
|
1951
1682
|
code: "### Subsubheader",
|
|
@@ -1999,23 +1730,23 @@ describe("cell reducer", () => {
|
|
|
1999
1730
|
});
|
|
2000
1731
|
|
|
2001
1732
|
it("can collapse all cells when a deep chain is followed by a later section", () => {
|
|
2002
|
-
|
|
2003
|
-
|
|
1733
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1734
|
+
seedCell({
|
|
2004
1735
|
cellId: cellId("1"),
|
|
2005
1736
|
before: false,
|
|
2006
1737
|
code: "# Header",
|
|
2007
1738
|
});
|
|
2008
|
-
|
|
1739
|
+
seedCell({
|
|
2009
1740
|
cellId: cellId("2"),
|
|
2010
1741
|
before: false,
|
|
2011
1742
|
code: "## Section A",
|
|
2012
1743
|
});
|
|
2013
|
-
|
|
1744
|
+
seedCell({
|
|
2014
1745
|
cellId: cellId("3"),
|
|
2015
1746
|
before: false,
|
|
2016
1747
|
code: "### Sub of A",
|
|
2017
1748
|
});
|
|
2018
|
-
|
|
1749
|
+
seedCell({
|
|
2019
1750
|
cellId: cellId("4"),
|
|
2020
1751
|
before: false,
|
|
2021
1752
|
code: "## Section B",
|
|
@@ -2078,8 +1809,8 @@ describe("cell reducer", () => {
|
|
|
2078
1809
|
});
|
|
2079
1810
|
|
|
2080
1811
|
it("can show hidden cells", () => {
|
|
2081
|
-
|
|
2082
|
-
|
|
1812
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1813
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
2083
1814
|
actions.collapseCell({ cellId: firstCellId });
|
|
2084
1815
|
|
|
2085
1816
|
actions.showCellIfHidden({ cellId: cellId("1") });
|
|
@@ -2089,7 +1820,7 @@ describe("cell reducer", () => {
|
|
|
2089
1820
|
});
|
|
2090
1821
|
|
|
2091
1822
|
it("can split and undo split cells", () => {
|
|
2092
|
-
|
|
1823
|
+
seedCell({
|
|
2093
1824
|
cellId: firstCellId,
|
|
2094
1825
|
before: false,
|
|
2095
1826
|
code: "line1\nline2",
|
|
@@ -2156,9 +1887,9 @@ describe("cell reducer", () => {
|
|
|
2156
1887
|
});
|
|
2157
1888
|
|
|
2158
1889
|
it("can add a column breakpoint", () => {
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
1890
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1891
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
1892
|
+
seedCell({ cellId: cellId("2"), before: false });
|
|
2162
1893
|
|
|
2163
1894
|
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2164
1895
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
@@ -2203,16 +1934,16 @@ describe("cell reducer", () => {
|
|
|
2203
1934
|
|
|
2204
1935
|
it("cannot add a column breakpoint before the first cell", () => {
|
|
2205
1936
|
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2206
|
-
|
|
2207
|
-
|
|
1937
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1938
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
2208
1939
|
actions.addColumnBreakpoint({ cellId: firstCellId });
|
|
2209
1940
|
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2210
1941
|
});
|
|
2211
1942
|
|
|
2212
1943
|
it("can delete a column", () => {
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
1944
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1945
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
1946
|
+
seedCell({ cellId: cellId("2"), before: false });
|
|
2216
1947
|
actions.addColumnBreakpoint({ cellId: cellId("2") });
|
|
2217
1948
|
|
|
2218
1949
|
expect(state.cellIds.getColumns().length).toBe(2);
|
|
@@ -2256,8 +1987,8 @@ describe("cell reducer", () => {
|
|
|
2256
1987
|
});
|
|
2257
1988
|
|
|
2258
1989
|
it("deleting the last column does nothing", () => {
|
|
2259
|
-
|
|
2260
|
-
|
|
1990
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1991
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
2261
1992
|
|
|
2262
1993
|
const initialState = { ...state };
|
|
2263
1994
|
|
|
@@ -2268,9 +1999,9 @@ describe("cell reducer", () => {
|
|
|
2268
1999
|
});
|
|
2269
2000
|
|
|
2270
2001
|
it("can drop a cell over another cell", () => {
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2002
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
2003
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
2004
|
+
seedCell({ cellId: cellId("2"), before: false });
|
|
2274
2005
|
|
|
2275
2006
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2276
2007
|
"
|
|
@@ -2303,8 +2034,8 @@ describe("cell reducer", () => {
|
|
|
2303
2034
|
});
|
|
2304
2035
|
|
|
2305
2036
|
it("can drop a cell over a new column", () => {
|
|
2306
|
-
|
|
2307
|
-
|
|
2037
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
2038
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
2308
2039
|
|
|
2309
2040
|
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2310
2041
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
@@ -2341,9 +2072,9 @@ describe("cell reducer", () => {
|
|
|
2341
2072
|
});
|
|
2342
2073
|
|
|
2343
2074
|
it("can drop a column over another column", () => {
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2075
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
2076
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
2077
|
+
seedCell({ cellId: cellId("2"), before: false });
|
|
2347
2078
|
actions.addColumnBreakpoint({ cellId: cellId("2") });
|
|
2348
2079
|
|
|
2349
2080
|
expect(state.cellIds.getColumns().length).toBe(2);
|
|
@@ -2394,8 +2125,8 @@ describe("cell reducer", () => {
|
|
|
2394
2125
|
|
|
2395
2126
|
it("can compact columns", () => {
|
|
2396
2127
|
// Create initial state with 3 columns, including an empty one
|
|
2397
|
-
|
|
2398
|
-
|
|
2128
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
2129
|
+
seedCell({ cellId: cellId("1"), before: false });
|
|
2399
2130
|
actions.addColumnBreakpoint({ cellId: cellId("1") });
|
|
2400
2131
|
actions.addColumnBreakpoint({ cellId: cellId("2") });
|
|
2401
2132
|
actions.dropOverNewColumn({ cellId: cellId("2") });
|
|
@@ -2534,7 +2265,7 @@ describe("cell reducer", () => {
|
|
|
2534
2265
|
|
|
2535
2266
|
it("can clear output of all cells", () => {
|
|
2536
2267
|
// Create multiple cells with output
|
|
2537
|
-
|
|
2268
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
2538
2269
|
const secondCellId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(1);
|
|
2539
2270
|
|
|
2540
2271
|
// Add output to both cells
|
|
@@ -2581,121 +2312,9 @@ describe("cell reducer", () => {
|
|
|
2581
2312
|
expect(state.cellRuntime[secondCellId].consoleOutputs).toEqual([]);
|
|
2582
2313
|
});
|
|
2583
2314
|
|
|
2584
|
-
it("skips creating new cell if code exists and skipIfCodeExists is true", () => {
|
|
2585
|
-
// Add initial cell with code
|
|
2586
|
-
actions.updateCellCode({
|
|
2587
|
-
cellId: firstCellId,
|
|
2588
|
-
code: "import numpy as np",
|
|
2589
|
-
formattingChange: false,
|
|
2590
|
-
});
|
|
2591
|
-
|
|
2592
|
-
// Try to create new cell with same code and skipIfCodeExists
|
|
2593
|
-
actions.createNewCell({
|
|
2594
|
-
cellId: "__end__",
|
|
2595
|
-
code: "import numpy as np",
|
|
2596
|
-
before: false,
|
|
2597
|
-
skipIfCodeExists: true,
|
|
2598
|
-
});
|
|
2599
|
-
|
|
2600
|
-
// Should still only have one cell
|
|
2601
|
-
expect(state.cellIds.inOrderIds.length).toBe(1);
|
|
2602
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2603
|
-
"
|
|
2604
|
-
[0] 'import numpy as np'
|
|
2605
|
-
"
|
|
2606
|
-
`);
|
|
2607
|
-
|
|
2608
|
-
// Verify we can still add cell with different code
|
|
2609
|
-
actions.createNewCell({
|
|
2610
|
-
cellId: "__end__",
|
|
2611
|
-
code: "import pandas as pd",
|
|
2612
|
-
before: false,
|
|
2613
|
-
skipIfCodeExists: true,
|
|
2614
|
-
});
|
|
2615
|
-
|
|
2616
|
-
expect(state.cellIds.inOrderIds.length).toBe(2);
|
|
2617
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2618
|
-
"
|
|
2619
|
-
[0] 'import numpy as np'
|
|
2620
|
-
|
|
2621
|
-
[1] 'import pandas as pd'
|
|
2622
|
-
"
|
|
2623
|
-
`);
|
|
2624
|
-
});
|
|
2625
|
-
|
|
2626
|
-
it("can create and noop-update a setup cell", () => {
|
|
2627
|
-
// Create the setup cell
|
|
2628
|
-
actions.addSetupCellIfDoesntExist({ code: "# Setup code" });
|
|
2629
|
-
|
|
2630
|
-
// Check that setup cell was created
|
|
2631
|
-
expect(state.cellData[SETUP_CELL_ID].id).toBe(SETUP_CELL_ID);
|
|
2632
|
-
expect(state.cellData[SETUP_CELL_ID].name).toBe("setup");
|
|
2633
|
-
expect(state.cellData[SETUP_CELL_ID].code).toBe("# Setup code");
|
|
2634
|
-
expect(state.cellData[SETUP_CELL_ID].edited).toBe(true);
|
|
2635
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
2636
|
-
|
|
2637
|
-
// Update the setup cell
|
|
2638
|
-
actions.addSetupCellIfDoesntExist({ code: "# Updated setup code" });
|
|
2639
|
-
|
|
2640
|
-
// Check that the setup cell did not change, since it already exists
|
|
2641
|
-
expect(state.cellData[SETUP_CELL_ID].code).toBe("# Setup code");
|
|
2642
|
-
expect(state.cellData[SETUP_CELL_ID].edited).toBe(true);
|
|
2643
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
2644
|
-
});
|
|
2645
|
-
|
|
2646
|
-
it("can delete and undelete the setup cell", () => {
|
|
2647
|
-
// Create the setup cell
|
|
2648
|
-
actions.addSetupCellIfDoesntExist({ code: "# Setup code" });
|
|
2649
|
-
|
|
2650
|
-
// Check that setup cell was created
|
|
2651
|
-
expect(state.cellData[SETUP_CELL_ID].id).toBe(SETUP_CELL_ID);
|
|
2652
|
-
expect(state.cellData[SETUP_CELL_ID].name).toBe("setup");
|
|
2653
|
-
expect(state.cellData[SETUP_CELL_ID].code).toBe("# Setup code");
|
|
2654
|
-
expect(state.cellData[SETUP_CELL_ID].edited).toBe(true);
|
|
2655
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
2656
|
-
|
|
2657
|
-
// Delete the setup cell
|
|
2658
|
-
actions.deleteCell({ cellId: SETUP_CELL_ID });
|
|
2659
|
-
|
|
2660
|
-
// Check that setup cell was deleted
|
|
2661
|
-
expect(state.cellData[SETUP_CELL_ID]).toBeDefined(); // we keep old state
|
|
2662
|
-
expect(state.cellIds.inOrderIds).not.toContain(SETUP_CELL_ID);
|
|
2663
|
-
|
|
2664
|
-
// Undo delete the setup cell
|
|
2665
|
-
actions.undoDeleteCell();
|
|
2666
|
-
|
|
2667
|
-
// Check that setup cell was restored
|
|
2668
|
-
expect(state.cellData[SETUP_CELL_ID].id).toBe(SETUP_CELL_ID);
|
|
2669
|
-
expect(state.cellData[SETUP_CELL_ID].name).toBe("setup");
|
|
2670
|
-
expect(state.cellData[SETUP_CELL_ID].code).toBe("# Setup code");
|
|
2671
|
-
expect(state.cellData[SETUP_CELL_ID].edited).toBe(true);
|
|
2672
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
2673
|
-
|
|
2674
|
-
// Verify scrollKey is set to the restored setup cell
|
|
2675
|
-
expect(state.scrollKey).toBe(SETUP_CELL_ID);
|
|
2676
|
-
});
|
|
2677
|
-
|
|
2678
|
-
it("can delete and then create a new setup cell", () => {
|
|
2679
|
-
// Create the setup cell
|
|
2680
|
-
actions.addSetupCellIfDoesntExist({ code: "# Setup code" });
|
|
2681
|
-
|
|
2682
|
-
// Delete the setup cell
|
|
2683
|
-
actions.deleteCell({ cellId: SETUP_CELL_ID });
|
|
2684
|
-
|
|
2685
|
-
// Create a new setup cell
|
|
2686
|
-
actions.addSetupCellIfDoesntExist({ code: "# New code" });
|
|
2687
|
-
|
|
2688
|
-
// Check that the new setup cell was created
|
|
2689
|
-
expect(state.cellData[SETUP_CELL_ID].id).toBe(SETUP_CELL_ID);
|
|
2690
|
-
expect(state.cellData[SETUP_CELL_ID].name).toBe("setup");
|
|
2691
|
-
expect(state.cellData[SETUP_CELL_ID].code).toBe("# New code");
|
|
2692
|
-
expect(state.cellData[SETUP_CELL_ID].edited).toBe(true);
|
|
2693
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
2694
|
-
});
|
|
2695
|
-
|
|
2696
2315
|
it("can clear all outputs", () => {
|
|
2697
2316
|
// Add a cell and give it output
|
|
2698
|
-
|
|
2317
|
+
seedCell({
|
|
2699
2318
|
cellId: firstCellId,
|
|
2700
2319
|
before: false,
|
|
2701
2320
|
});
|
|
@@ -2723,202 +2342,14 @@ describe("cell reducer", () => {
|
|
|
2723
2342
|
expect(state.cellRuntime[cell2Id].output).toBeNull();
|
|
2724
2343
|
});
|
|
2725
2344
|
|
|
2726
|
-
describe("moveToNextCell", () => {
|
|
2727
|
-
let cell1Id: CellId;
|
|
2728
|
-
let cell2Id: CellId;
|
|
2729
|
-
let cell3Id: CellId;
|
|
2730
|
-
|
|
2731
|
-
beforeEach(() => {
|
|
2732
|
-
// Create a few cells to work with
|
|
2733
|
-
actions.createNewCell({ cellId: "__end__", before: false });
|
|
2734
|
-
actions.createNewCell({ cellId: "__end__", before: false });
|
|
2735
|
-
|
|
2736
|
-
cell1Id = state.cellIds.inOrderIds[0];
|
|
2737
|
-
cell2Id = state.cellIds.inOrderIds[1];
|
|
2738
|
-
cell3Id = state.cellIds.inOrderIds[2];
|
|
2739
|
-
});
|
|
2740
|
-
|
|
2741
|
-
it("creates new cell when moving after last cell with noCreate=false", () => {
|
|
2742
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
2743
|
-
|
|
2744
|
-
actions.moveToNextCell({
|
|
2745
|
-
cellId: cell3Id,
|
|
2746
|
-
before: false,
|
|
2747
|
-
noCreate: false,
|
|
2748
|
-
});
|
|
2749
|
-
|
|
2750
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount + 1);
|
|
2751
|
-
});
|
|
2752
|
-
|
|
2753
|
-
it("creates new cell when moving before first cell with noCreate=false", () => {
|
|
2754
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
2755
|
-
|
|
2756
|
-
actions.moveToNextCell({
|
|
2757
|
-
cellId: cell1Id,
|
|
2758
|
-
before: true,
|
|
2759
|
-
noCreate: false,
|
|
2760
|
-
});
|
|
2761
|
-
|
|
2762
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount + 1);
|
|
2763
|
-
});
|
|
2764
|
-
|
|
2765
|
-
it("does not create new cell when moving after last cell with noCreate=true", () => {
|
|
2766
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
2767
|
-
const initialState = { ...state };
|
|
2768
|
-
|
|
2769
|
-
actions.moveToNextCell({
|
|
2770
|
-
cellId: cell3Id,
|
|
2771
|
-
before: false,
|
|
2772
|
-
noCreate: true,
|
|
2773
|
-
});
|
|
2774
|
-
|
|
2775
|
-
// Should not create a new cell
|
|
2776
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount);
|
|
2777
|
-
// Should not crash or throw an error
|
|
2778
|
-
expect(state.cellIds.inOrderIds).toEqual(initialState.cellIds.inOrderIds);
|
|
2779
|
-
});
|
|
2780
|
-
|
|
2781
|
-
it("does not create new cell when moving before first cell with noCreate=true", () => {
|
|
2782
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
2783
|
-
const initialState = { ...state };
|
|
2784
|
-
|
|
2785
|
-
actions.moveToNextCell({ cellId: cell1Id, before: true, noCreate: true });
|
|
2786
|
-
|
|
2787
|
-
// Should not create a new cell
|
|
2788
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount);
|
|
2789
|
-
// Should not crash or throw an error
|
|
2790
|
-
expect(state.cellIds.inOrderIds).toEqual(initialState.cellIds.inOrderIds);
|
|
2791
|
-
});
|
|
2792
|
-
|
|
2793
|
-
it("focuses next cell when moving within bounds", () => {
|
|
2794
|
-
const focusSpy = vi.mocked(focusAndScrollCellIntoView);
|
|
2795
|
-
focusSpy.mockClear();
|
|
2796
|
-
|
|
2797
|
-
actions.moveToNextCell({
|
|
2798
|
-
cellId: cell1Id,
|
|
2799
|
-
before: false,
|
|
2800
|
-
noCreate: true,
|
|
2801
|
-
});
|
|
2802
|
-
|
|
2803
|
-
expect(focusSpy).toHaveBeenCalledWith({
|
|
2804
|
-
cellId: cell2Id,
|
|
2805
|
-
cell: state.cellHandles[cell2Id],
|
|
2806
|
-
isCodeHidden: false,
|
|
2807
|
-
codeFocus: "top",
|
|
2808
|
-
variableName: undefined,
|
|
2809
|
-
});
|
|
2810
|
-
});
|
|
2811
|
-
|
|
2812
|
-
it("focuses previous cell when moving backward within bounds", () => {
|
|
2813
|
-
const focusSpy = vi.mocked(focusAndScrollCellIntoView);
|
|
2814
|
-
focusSpy.mockClear();
|
|
2815
|
-
|
|
2816
|
-
actions.moveToNextCell({ cellId: cell2Id, before: true, noCreate: true });
|
|
2817
|
-
|
|
2818
|
-
expect(focusSpy).toHaveBeenCalledWith({
|
|
2819
|
-
cellId: cell1Id,
|
|
2820
|
-
cell: state.cellHandles[cell1Id],
|
|
2821
|
-
isCodeHidden: false,
|
|
2822
|
-
codeFocus: "bottom",
|
|
2823
|
-
variableName: undefined,
|
|
2824
|
-
});
|
|
2825
|
-
});
|
|
2826
|
-
|
|
2827
|
-
it("does not move focus from scratch cell", () => {
|
|
2828
|
-
const focusSpy = vi.mocked(focusAndScrollCellIntoView);
|
|
2829
|
-
focusSpy.mockClear();
|
|
2830
|
-
const initialState = { ...state };
|
|
2831
|
-
|
|
2832
|
-
actions.moveToNextCell({
|
|
2833
|
-
cellId: SCRATCH_CELL_ID,
|
|
2834
|
-
before: false,
|
|
2835
|
-
noCreate: false,
|
|
2836
|
-
});
|
|
2837
|
-
|
|
2838
|
-
expect(focusSpy).not.toHaveBeenCalled();
|
|
2839
|
-
expect(state.cellIds.inOrderIds).toEqual(initialState.cellIds.inOrderIds);
|
|
2840
|
-
});
|
|
2841
|
-
});
|
|
2842
|
-
|
|
2843
2345
|
describe("untouched cells functionality", () => {
|
|
2844
2346
|
it("starts with empty untouchedNewCells set", () => {
|
|
2845
2347
|
expect(state.untouchedNewCells).toEqual(new Set());
|
|
2846
2348
|
});
|
|
2847
2349
|
|
|
2848
|
-
it("can create a new cell with hideCode option", () => {
|
|
2849
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
2850
|
-
|
|
2851
|
-
actions.createNewCell({
|
|
2852
|
-
cellId: "__end__",
|
|
2853
|
-
before: false,
|
|
2854
|
-
hideCode: true,
|
|
2855
|
-
});
|
|
2856
|
-
|
|
2857
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount + 1);
|
|
2858
|
-
const newCellId =
|
|
2859
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
2860
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
2861
|
-
});
|
|
2862
|
-
|
|
2863
|
-
it("adds interactively-created hidden cell with boilerplate code to untouchedNewCells", () => {
|
|
2864
|
-
// Markdown cells are created with hideCode and non-empty default code
|
|
2865
|
-
// (e.g. `mo.md(r"""\n""")`). They are user-initiated, so their editor
|
|
2866
|
-
// should be shown until first blur.
|
|
2867
|
-
actions.createNewCell({
|
|
2868
|
-
cellId: "__end__",
|
|
2869
|
-
before: false,
|
|
2870
|
-
code: 'mo.md(r"""\n""")',
|
|
2871
|
-
hideCode: true,
|
|
2872
|
-
autoFocus: true,
|
|
2873
|
-
});
|
|
2874
|
-
|
|
2875
|
-
const newCellId =
|
|
2876
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
2877
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
2878
|
-
});
|
|
2879
|
-
|
|
2880
|
-
it("does not add programmatically-created hidden cell with code to untouchedNewCells", () => {
|
|
2881
|
-
// Cells created by the kernel (e.g. via code_mode) carry code and
|
|
2882
|
-
// autoFocus=false; their hide_code must take effect immediately.
|
|
2883
|
-
actions.createNewCell({
|
|
2884
|
-
cellId: "__end__",
|
|
2885
|
-
before: false,
|
|
2886
|
-
code: "x = 1",
|
|
2887
|
-
hideCode: true,
|
|
2888
|
-
autoFocus: false,
|
|
2889
|
-
});
|
|
2890
|
-
|
|
2891
|
-
const newCellId =
|
|
2892
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
2893
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
2894
|
-
});
|
|
2895
|
-
|
|
2896
|
-
it("does not add cell to untouchedNewCells when hideCode is false", () => {
|
|
2897
|
-
actions.createNewCell({
|
|
2898
|
-
cellId: "__end__",
|
|
2899
|
-
before: false,
|
|
2900
|
-
hideCode: false,
|
|
2901
|
-
});
|
|
2902
|
-
|
|
2903
|
-
const newCellId =
|
|
2904
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
2905
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
2906
|
-
});
|
|
2907
|
-
|
|
2908
|
-
it("does not add cell to untouchedNewCells when hideCode is undefined", () => {
|
|
2909
|
-
actions.createNewCell({
|
|
2910
|
-
cellId: "__end__",
|
|
2911
|
-
before: false,
|
|
2912
|
-
});
|
|
2913
|
-
|
|
2914
|
-
const newCellId =
|
|
2915
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
2916
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
2917
|
-
});
|
|
2918
|
-
|
|
2919
2350
|
it("can mark a cell as touched", () => {
|
|
2920
2351
|
// Create a cell with hideCode
|
|
2921
|
-
|
|
2352
|
+
seedCell({
|
|
2922
2353
|
cellId: "__end__",
|
|
2923
2354
|
before: false,
|
|
2924
2355
|
hideCode: true,
|
|
@@ -2936,7 +2367,7 @@ describe("cell reducer", () => {
|
|
|
2936
2367
|
|
|
2937
2368
|
it("markTouched is idempotent", () => {
|
|
2938
2369
|
// Create a cell with hideCode
|
|
2939
|
-
|
|
2370
|
+
seedCell({
|
|
2940
2371
|
cellId: "__end__",
|
|
2941
2372
|
before: false,
|
|
2942
2373
|
hideCode: true,
|
|
@@ -2966,17 +2397,17 @@ describe("cell reducer", () => {
|
|
|
2966
2397
|
|
|
2967
2398
|
it("can handle multiple untouched cells", () => {
|
|
2968
2399
|
// Create multiple cells with hideCode
|
|
2969
|
-
|
|
2400
|
+
seedCell({
|
|
2970
2401
|
cellId: "__end__",
|
|
2971
2402
|
before: false,
|
|
2972
2403
|
hideCode: true,
|
|
2973
2404
|
});
|
|
2974
|
-
|
|
2405
|
+
seedCell({
|
|
2975
2406
|
cellId: "__end__",
|
|
2976
2407
|
before: false,
|
|
2977
2408
|
hideCode: true,
|
|
2978
2409
|
});
|
|
2979
|
-
|
|
2410
|
+
seedCell({
|
|
2980
2411
|
cellId: "__end__",
|
|
2981
2412
|
before: false,
|
|
2982
2413
|
hideCode: false,
|
|
@@ -3001,12 +2432,12 @@ describe("cell reducer", () => {
|
|
|
3001
2432
|
|
|
3002
2433
|
it("preserves untouched state when cells are moved", () => {
|
|
3003
2434
|
// Create cells with hideCode
|
|
3004
|
-
|
|
2435
|
+
seedCell({
|
|
3005
2436
|
cellId: "__end__",
|
|
3006
2437
|
before: false,
|
|
3007
2438
|
hideCode: true,
|
|
3008
2439
|
});
|
|
3009
|
-
|
|
2440
|
+
seedCell({
|
|
3010
2441
|
cellId: "__end__",
|
|
3011
2442
|
before: false,
|
|
3012
2443
|
hideCode: true,
|
|
@@ -3030,58 +2461,9 @@ describe("cell reducer", () => {
|
|
|
3030
2461
|
expect(state.untouchedNewCells.has(cell2Id)).toBe(true);
|
|
3031
2462
|
});
|
|
3032
2463
|
|
|
3033
|
-
it("does not remove untouched state when cell is deleted", () => {
|
|
3034
|
-
// We could implement this, but it doesn't actually affect downstream behavior.
|
|
3035
|
-
// It is easier to leave it, so `undo` works as expected.
|
|
3036
|
-
|
|
3037
|
-
// Create a cell with hideCode
|
|
3038
|
-
actions.createNewCell({
|
|
3039
|
-
cellId: "__end__",
|
|
3040
|
-
before: false,
|
|
3041
|
-
hideCode: true,
|
|
3042
|
-
});
|
|
3043
|
-
|
|
3044
|
-
const newCellId =
|
|
3045
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3046
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3047
|
-
|
|
3048
|
-
// Delete the cell
|
|
3049
|
-
actions.deleteCell({ cellId: newCellId });
|
|
3050
|
-
|
|
3051
|
-
// Does not actually remove untouched state
|
|
3052
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3053
|
-
});
|
|
3054
|
-
|
|
3055
|
-
it("restores untouched state when cell deletion is undone", () => {
|
|
3056
|
-
// Create a cell with hideCode
|
|
3057
|
-
actions.createNewCell({
|
|
3058
|
-
cellId: "__end__",
|
|
3059
|
-
before: false,
|
|
3060
|
-
hideCode: true,
|
|
3061
|
-
});
|
|
3062
|
-
|
|
3063
|
-
const newCellId =
|
|
3064
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3065
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3066
|
-
|
|
3067
|
-
// Delete the cell
|
|
3068
|
-
actions.deleteCell({ cellId: newCellId });
|
|
3069
|
-
// Still exists in untouchedNewCells
|
|
3070
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3071
|
-
|
|
3072
|
-
// Undo the deletion
|
|
3073
|
-
actions.undoDeleteCell();
|
|
3074
|
-
|
|
3075
|
-
// The cell should be restored but no longer untouched
|
|
3076
|
-
// (this is expected behavior - undoing doesn't restore untouched state)
|
|
3077
|
-
const restoredCellId =
|
|
3078
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3079
|
-
expect(state.untouchedNewCells.has(restoredCellId)).toBe(false);
|
|
3080
|
-
});
|
|
3081
|
-
|
|
3082
2464
|
it("untouched cell behavior with hide_code config", () => {
|
|
3083
2465
|
// Create a cell with hideCode and hide_code config
|
|
3084
|
-
|
|
2466
|
+
seedCell({
|
|
3085
2467
|
cellId: "__end__",
|
|
3086
2468
|
before: false,
|
|
3087
2469
|
hideCode: true,
|
|
@@ -3090,11 +2472,11 @@ describe("cell reducer", () => {
|
|
|
3090
2472
|
const newCellId =
|
|
3091
2473
|
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3092
2474
|
|
|
3093
|
-
//
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
config: { hide_code: true },
|
|
3097
|
-
}
|
|
2475
|
+
// The document hides the cell's code
|
|
2476
|
+
state.cellData[newCellId] = {
|
|
2477
|
+
...state.cellData[newCellId],
|
|
2478
|
+
config: { ...state.cellData[newCellId].config, hide_code: true },
|
|
2479
|
+
};
|
|
3098
2480
|
|
|
3099
2481
|
// Cell should be untouched and have hide_code config
|
|
3100
2482
|
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
@@ -3113,7 +2495,7 @@ describe("cell reducer", () => {
|
|
|
3113
2495
|
|
|
3114
2496
|
it("can mark an existing cell as untouched", () => {
|
|
3115
2497
|
// Create a cell without hideCode (not in untouchedNewCells)
|
|
3116
|
-
|
|
2498
|
+
seedCell({
|
|
3117
2499
|
cellId: "__end__",
|
|
3118
2500
|
before: false,
|
|
3119
2501
|
hideCode: false,
|
|
@@ -3131,7 +2513,7 @@ describe("cell reducer", () => {
|
|
|
3131
2513
|
|
|
3132
2514
|
it("markUntouched is idempotent", () => {
|
|
3133
2515
|
// Create a cell without hideCode
|
|
3134
|
-
|
|
2516
|
+
seedCell({
|
|
3135
2517
|
cellId: "__end__",
|
|
3136
2518
|
before: false,
|
|
3137
2519
|
hideCode: false,
|
|
@@ -3151,7 +2533,7 @@ describe("cell reducer", () => {
|
|
|
3151
2533
|
|
|
3152
2534
|
it("markUntouched does not affect already untouched cells", () => {
|
|
3153
2535
|
// Create a cell with hideCode (already in untouchedNewCells)
|
|
3154
|
-
|
|
2536
|
+
seedCell({
|
|
3155
2537
|
cellId: "__end__",
|
|
3156
2538
|
before: false,
|
|
3157
2539
|
hideCode: true,
|
|
@@ -3169,7 +2551,7 @@ describe("cell reducer", () => {
|
|
|
3169
2551
|
|
|
3170
2552
|
it("markTouched and markUntouched can toggle cell state", () => {
|
|
3171
2553
|
// Create a cell without hideCode
|
|
3172
|
-
|
|
2554
|
+
seedCell({
|
|
3173
2555
|
cellId: "__end__",
|
|
3174
2556
|
before: false,
|
|
3175
2557
|
hideCode: false,
|
|
@@ -3197,7 +2579,7 @@ describe("cell reducer", () => {
|
|
|
3197
2579
|
it("markUntouched works for markdown cell conversion scenario", () => {
|
|
3198
2580
|
// Simulates converting a Python cell to Markdown
|
|
3199
2581
|
// 1. Create a regular cell (no hideCode)
|
|
3200
|
-
|
|
2582
|
+
seedCell({
|
|
3201
2583
|
cellId: "__end__",
|
|
3202
2584
|
before: false,
|
|
3203
2585
|
hideCode: false,
|
|
@@ -3211,11 +2593,12 @@ describe("cell reducer", () => {
|
|
|
3211
2593
|
expect(state.untouchedNewCells.has(cellId)).toBe(false);
|
|
3212
2594
|
expect(exportedForTesting.isCellCodeHidden(state, cellId)).toBe(false);
|
|
3213
2595
|
|
|
3214
|
-
// 2. Convert to markdown:
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
2596
|
+
// 2. Convert to markdown: the document hides the code, and the cell
|
|
2597
|
+
// is marked untouched
|
|
2598
|
+
state.cellData[cellId] = {
|
|
2599
|
+
...state.cellData[cellId],
|
|
2600
|
+
config: { ...state.cellData[cellId].config, hide_code: true },
|
|
2601
|
+
};
|
|
3219
2602
|
actions.markUntouched({ cellId });
|
|
3220
2603
|
|
|
3221
2604
|
// Code should NOT be hidden because cell is untouched (user can edit)
|
|
@@ -3237,7 +2620,7 @@ describe("cell reducer", () => {
|
|
|
3237
2620
|
const { cellDataAtom, cellRuntimeAtom, cellHandleAtom } =
|
|
3238
2621
|
exportedForTesting;
|
|
3239
2622
|
|
|
3240
|
-
|
|
2623
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
3241
2624
|
const newCellId = state.cellIds.inOrderIds[1];
|
|
3242
2625
|
|
|
3243
2626
|
const dataAtom1 = cellDataAtom(newCellId);
|
|
@@ -3253,31 +2636,6 @@ describe("cell reducer", () => {
|
|
|
3253
2636
|
expect(runtimeAtom2).toBe(runtimeAtom1);
|
|
3254
2637
|
expect(handleAtom2).toBe(handleAtom1);
|
|
3255
2638
|
});
|
|
3256
|
-
|
|
3257
|
-
it("cleans up atom family cache when cells are deleted", () => {
|
|
3258
|
-
const { cellDataAtom, cellRuntimeAtom, cellHandleAtom } =
|
|
3259
|
-
exportedForTesting;
|
|
3260
|
-
|
|
3261
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
3262
|
-
const newCellId = state.cellIds.inOrderIds[1];
|
|
3263
|
-
|
|
3264
|
-
// Access to create cache entries
|
|
3265
|
-
const dataAtom1 = cellDataAtom(newCellId);
|
|
3266
|
-
const runtimeAtom1 = cellRuntimeAtom(newCellId);
|
|
3267
|
-
const handleAtom1 = cellHandleAtom(newCellId);
|
|
3268
|
-
|
|
3269
|
-
// Triggers purge
|
|
3270
|
-
actions.deleteCell({ cellId: newCellId });
|
|
3271
|
-
|
|
3272
|
-
// Access again (should be new instances after cleanup)
|
|
3273
|
-
const dataAtom2 = cellDataAtom(newCellId);
|
|
3274
|
-
const runtimeAtom2 = cellRuntimeAtom(newCellId);
|
|
3275
|
-
const handleAtom2 = cellHandleAtom(newCellId);
|
|
3276
|
-
|
|
3277
|
-
expect(dataAtom2).not.toBe(dataAtom1);
|
|
3278
|
-
expect(runtimeAtom2).not.toBe(runtimeAtom1);
|
|
3279
|
-
expect(handleAtom2).not.toBe(handleAtom1);
|
|
3280
|
-
});
|
|
3281
2639
|
});
|
|
3282
2640
|
});
|
|
3283
2641
|
|