@marimo-team/islands 0.24.3-dev79 → 0.24.3-dev81
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-DIWA1QGH.js → ErrorBoundary-CCi-VkF7.js} +1 -1
- package/dist/{cells-BLjghRgH.js → cells-BIfOnGBK.js} +9 -4
- package/dist/{chat-ui-ZVLuVQRR.js → chat-ui-LWkjhObe.js} +4 -4
- package/dist/{code-visibility-DtL0wZlt.js → code-visibility-Bsfqbe2z.js} +2 -2
- package/dist/{common-MDKJTGbt.js → common-BnKC1tWB.js} +3 -3
- package/dist/{data-grid-overlay-editor-fY7oIkDy.js → data-grid-overlay-editor-CJnlWykO.js} +1 -1
- package/dist/{error-entries-CJR74llu.js → error-entries-CR0oClSL.js} +1 -1
- package/dist/{feedback-button-DUQsmSVO.js → feedback-button-MWISfIIf.js} +4 -4
- package/dist/{glide-data-editor-0lPCT8aT.js → glide-data-editor-dcmP8mKS.js} +3 -3
- package/dist/{globals-BZ84V5JW.js → globals-fCMBgbAD.js} +1 -1
- package/dist/{html-to-image-DYuNuZZd.js → html-to-image-_i03yR4q.js} +586 -567
- package/dist/main.js +10 -10
- package/dist/{number-overlay-editor-CqbV6XrR.js → number-overlay-editor-DhNE6pBe.js} +1 -1
- package/dist/{process-output-BurYfV57.js → process-output-D3zQyTAS.js} +2 -2
- package/dist/{reveal-component-Dn-E-TUl.js → reveal-component-Cdcgngkc.js} +3 -3
- package/package.json +1 -1
- package/src/__mocks__/notebook.ts +1 -0
- package/src/components/editor/navigation/clipboard.ts +1 -0
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +37 -0
- package/src/core/cells/__tests__/apply-transaction.test.ts +34 -0
- package/src/core/cells/__tests__/cells.test.ts +1 -0
- package/src/core/cells/__tests__/document-changes.test.ts +39 -1
- package/src/core/cells/__tests__/outputs.test.tsx +117 -0
- package/src/core/cells/__tests__/session.test.ts +7 -0
- package/src/core/cells/cells.ts +6 -1
- package/src/core/cells/document-changes.ts +11 -1
- package/src/core/cells/outputs.ts +66 -9
- package/src/core/cells/session.ts +2 -0
- package/src/core/cells/types.ts +2 -0
|
@@ -153,6 +153,7 @@ describe("toDocumentChanges", () => {
|
|
|
153
153
|
"config": {
|
|
154
154
|
"column": null,
|
|
155
155
|
"disabled": false,
|
|
156
|
+
"expand_output": false,
|
|
156
157
|
"hide_code": false,
|
|
157
158
|
},
|
|
158
159
|
"name": "_",
|
|
@@ -183,6 +184,7 @@ describe("toDocumentChanges", () => {
|
|
|
183
184
|
"config": {
|
|
184
185
|
"column": null,
|
|
185
186
|
"disabled": false,
|
|
187
|
+
"expand_output": false,
|
|
186
188
|
"hide_code": false,
|
|
187
189
|
},
|
|
188
190
|
"name": "_",
|
|
@@ -229,6 +231,7 @@ describe("toDocumentChanges", () => {
|
|
|
229
231
|
"cellId": "0",
|
|
230
232
|
"column": null,
|
|
231
233
|
"disabled": false,
|
|
234
|
+
"expandOutput": false,
|
|
232
235
|
"hideCode": true,
|
|
233
236
|
"type": "set-config",
|
|
234
237
|
},
|
|
@@ -236,6 +239,29 @@ describe("toDocumentChanges", () => {
|
|
|
236
239
|
`);
|
|
237
240
|
});
|
|
238
241
|
|
|
242
|
+
it("maps expand_output to expandOutput in set-config", () => {
|
|
243
|
+
setup("a");
|
|
244
|
+
const [a] = state.cellIds.inOrderIds;
|
|
245
|
+
|
|
246
|
+
const { changes } = resolve(state, {
|
|
247
|
+
type: "updateCellConfig",
|
|
248
|
+
payload: { cellId: a, config: { expand_output: true } },
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
expect(changes).toMatchInlineSnapshot(`
|
|
252
|
+
[
|
|
253
|
+
{
|
|
254
|
+
"cellId": "0",
|
|
255
|
+
"column": null,
|
|
256
|
+
"disabled": false,
|
|
257
|
+
"expandOutput": true,
|
|
258
|
+
"hideCode": false,
|
|
259
|
+
"type": "set-config",
|
|
260
|
+
},
|
|
261
|
+
]
|
|
262
|
+
`);
|
|
263
|
+
});
|
|
264
|
+
|
|
239
265
|
it("includes full CellConfig in create-cell", () => {
|
|
240
266
|
setup("a");
|
|
241
267
|
|
|
@@ -246,13 +272,14 @@ describe("toDocumentChanges", () => {
|
|
|
246
272
|
before: false,
|
|
247
273
|
code: "hidden",
|
|
248
274
|
newCellId: CellId.create(),
|
|
275
|
+
config: { expand_output: true },
|
|
249
276
|
hideCode: true,
|
|
250
277
|
},
|
|
251
278
|
});
|
|
252
279
|
|
|
253
280
|
expect(changes[0]).toMatchObject({
|
|
254
281
|
type: "create-cell",
|
|
255
|
-
config: { hide_code: true },
|
|
282
|
+
config: { hide_code: true, expand_output: true },
|
|
256
283
|
});
|
|
257
284
|
});
|
|
258
285
|
});
|
|
@@ -273,6 +300,7 @@ describe("toDocumentChanges", () => {
|
|
|
273
300
|
"cellId": "1",
|
|
274
301
|
"column": 1,
|
|
275
302
|
"disabled": false,
|
|
303
|
+
"expandOutput": false,
|
|
276
304
|
"hideCode": false,
|
|
277
305
|
"type": "set-config",
|
|
278
306
|
},
|
|
@@ -302,6 +330,7 @@ describe("toDocumentChanges", () => {
|
|
|
302
330
|
"cellId": "1",
|
|
303
331
|
"column": 1,
|
|
304
332
|
"disabled": false,
|
|
333
|
+
"expandOutput": false,
|
|
305
334
|
"hideCode": false,
|
|
306
335
|
"type": "set-config",
|
|
307
336
|
},
|
|
@@ -309,6 +338,7 @@ describe("toDocumentChanges", () => {
|
|
|
309
338
|
"cellId": "2",
|
|
310
339
|
"column": 1,
|
|
311
340
|
"disabled": false,
|
|
341
|
+
"expandOutput": false,
|
|
312
342
|
"hideCode": false,
|
|
313
343
|
"type": "set-config",
|
|
314
344
|
},
|
|
@@ -343,6 +373,7 @@ describe("toDocumentChanges", () => {
|
|
|
343
373
|
"cellId": "1",
|
|
344
374
|
"column": 0,
|
|
345
375
|
"disabled": false,
|
|
376
|
+
"expandOutput": false,
|
|
346
377
|
"hideCode": false,
|
|
347
378
|
"type": "set-config",
|
|
348
379
|
},
|
|
@@ -350,6 +381,7 @@ describe("toDocumentChanges", () => {
|
|
|
350
381
|
"cellId": "2",
|
|
351
382
|
"column": 0,
|
|
352
383
|
"disabled": false,
|
|
384
|
+
"expandOutput": false,
|
|
353
385
|
"hideCode": false,
|
|
354
386
|
"type": "set-config",
|
|
355
387
|
},
|
|
@@ -386,6 +418,7 @@ describe("toDocumentChanges", () => {
|
|
|
386
418
|
"config": {
|
|
387
419
|
"column": null,
|
|
388
420
|
"disabled": false,
|
|
421
|
+
"expand_output": false,
|
|
389
422
|
"hide_code": false,
|
|
390
423
|
},
|
|
391
424
|
"name": "_",
|
|
@@ -395,6 +428,7 @@ describe("toDocumentChanges", () => {
|
|
|
395
428
|
"cellId": "1",
|
|
396
429
|
"column": 1,
|
|
397
430
|
"disabled": false,
|
|
431
|
+
"expandOutput": false,
|
|
398
432
|
"hideCode": false,
|
|
399
433
|
"type": "set-config",
|
|
400
434
|
},
|
|
@@ -458,6 +492,7 @@ describe("toDocumentChanges", () => {
|
|
|
458
492
|
"config": {
|
|
459
493
|
"column": null,
|
|
460
494
|
"disabled": false,
|
|
495
|
+
"expand_output": false,
|
|
461
496
|
"hide_code": false,
|
|
462
497
|
},
|
|
463
498
|
"name": "_",
|
|
@@ -521,6 +556,7 @@ describe("toDocumentChanges", () => {
|
|
|
521
556
|
"config": {
|
|
522
557
|
"column": null,
|
|
523
558
|
"disabled": false,
|
|
559
|
+
"expand_output": false,
|
|
524
560
|
"hide_code": false,
|
|
525
561
|
},
|
|
526
562
|
"name": "_",
|
|
@@ -559,6 +595,7 @@ describe("toDocumentChanges", () => {
|
|
|
559
595
|
"config": {
|
|
560
596
|
"column": null,
|
|
561
597
|
"disabled": false,
|
|
598
|
+
"expand_output": false,
|
|
562
599
|
"hide_code": false,
|
|
563
600
|
},
|
|
564
601
|
"name": "setup",
|
|
@@ -648,6 +685,7 @@ describe("coalesceChanges", () => {
|
|
|
648
685
|
column: null,
|
|
649
686
|
disabled: true,
|
|
650
687
|
hideCode: false,
|
|
688
|
+
expandOutput: false,
|
|
651
689
|
},
|
|
652
690
|
{ type: "move-cell", cellId: X, after: A },
|
|
653
691
|
{ type: "delete-cell", cellId: X },
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { act, renderHook } from "@testing-library/react";
|
|
4
|
+
import { createStore, Provider } from "jotai";
|
|
5
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { MockNotebook } from "@/__mocks__/notebook";
|
|
7
|
+
import { notebookAtom } from "@/core/cells/cells";
|
|
8
|
+
import { CellId } from "@/core/cells/ids";
|
|
9
|
+
import { type AppMode, viewStateAtom } from "@/core/mode";
|
|
10
|
+
import { useExpandedConsoleOutput, useExpandedOutput } from "../outputs";
|
|
11
|
+
|
|
12
|
+
const saveCellConfig = vi.fn().mockResolvedValue(null);
|
|
13
|
+
|
|
14
|
+
vi.mock("@/core/network/requests", () => ({
|
|
15
|
+
getRequestClient: () => ({ saveCellConfig }),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
function setup(opts: { mode: AppMode; expandOutput?: boolean }) {
|
|
19
|
+
const cellId = CellId.create();
|
|
20
|
+
const store = createStore();
|
|
21
|
+
store.set(
|
|
22
|
+
notebookAtom,
|
|
23
|
+
MockNotebook.notebookState({
|
|
24
|
+
cellData: {
|
|
25
|
+
[cellId]: { config: { expand_output: opts.expandOutput ?? false } },
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
29
|
+
store.set(viewStateAtom, { mode: opts.mode, cellAnchor: null });
|
|
30
|
+
|
|
31
|
+
const { result } = renderHook(() => useExpandedOutput(cellId), {
|
|
32
|
+
wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return { cellId, store, result };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const configOf = (store: ReturnType<typeof createStore>, cellId: CellId) =>
|
|
39
|
+
store.get(notebookAtom).cellData[cellId].config;
|
|
40
|
+
|
|
41
|
+
describe("useExpandedOutput", () => {
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
vi.clearAllMocks();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("reads the initial state from the cell's expand_output config", () => {
|
|
47
|
+
expect(setup({ mode: "edit" }).result.current[0]).toBe(false);
|
|
48
|
+
expect(setup({ mode: "edit", expandOutput: true }).result.current[0]).toBe(
|
|
49
|
+
true,
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("persists the toggle to the cell's config in edit mode", () => {
|
|
54
|
+
const { cellId, store, result } = setup({ mode: "edit" });
|
|
55
|
+
|
|
56
|
+
act(() => result.current[1](true));
|
|
57
|
+
|
|
58
|
+
expect(result.current[0]).toBe(true);
|
|
59
|
+
expect(configOf(store, cellId).expand_output).toBe(true);
|
|
60
|
+
expect(saveCellConfig).toHaveBeenCalledWith({
|
|
61
|
+
configs: { [cellId]: { expand_output: true } },
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("collapses by clearing the config", () => {
|
|
66
|
+
const { cellId, store, result } = setup({
|
|
67
|
+
mode: "edit",
|
|
68
|
+
expandOutput: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
act(() => result.current[1](false));
|
|
72
|
+
|
|
73
|
+
expect(result.current[0]).toBe(false);
|
|
74
|
+
expect(configOf(store, cellId).expand_output).toBe(false);
|
|
75
|
+
expect(saveCellConfig).toHaveBeenCalledWith({
|
|
76
|
+
configs: { [cellId]: { expand_output: false } },
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("keeps the toggle in memory outside of edit mode", () => {
|
|
81
|
+
const { cellId, store, result } = setup({ mode: "read" });
|
|
82
|
+
|
|
83
|
+
act(() => result.current[1](true));
|
|
84
|
+
|
|
85
|
+
expect(result.current[0]).toBe(true);
|
|
86
|
+
// Cell configs are read-only outside of edit mode.
|
|
87
|
+
expect(configOf(store, cellId).expand_output).toBe(false);
|
|
88
|
+
expect(saveCellConfig).not.toHaveBeenCalled();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("still honors expand_output outside of edit mode", () => {
|
|
92
|
+
const { result } = setup({ mode: "read", expandOutput: true });
|
|
93
|
+
expect(result.current[0]).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// `expand_output` covers the cell's output area only. Console output is
|
|
97
|
+
// clamped independently and stays an in-memory, per-session toggle.
|
|
98
|
+
it("does not touch the config when console output is expanded", () => {
|
|
99
|
+
const cellId = CellId.create();
|
|
100
|
+
const store = createStore();
|
|
101
|
+
store.set(
|
|
102
|
+
notebookAtom,
|
|
103
|
+
MockNotebook.notebookState({ cellData: { [cellId]: {} } }),
|
|
104
|
+
);
|
|
105
|
+
store.set(viewStateAtom, { mode: "edit", cellAnchor: null });
|
|
106
|
+
|
|
107
|
+
const { result } = renderHook(() => useExpandedConsoleOutput(cellId), {
|
|
108
|
+
wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
act(() => result.current[1](true));
|
|
112
|
+
|
|
113
|
+
expect(result.current[0]).toBe(true);
|
|
114
|
+
expect(configOf(store, cellId).expand_output).toBe(false);
|
|
115
|
+
expect(saveCellConfig).not.toHaveBeenCalled();
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -59,6 +59,7 @@ describe("notebookStateFromSession", () => {
|
|
|
59
59
|
column: config?.column ?? null,
|
|
60
60
|
disabled: config?.disabled ?? null,
|
|
61
61
|
hide_code: config?.hide_code ?? null,
|
|
62
|
+
expand_output: config?.expand_output ?? null,
|
|
62
63
|
},
|
|
63
64
|
});
|
|
64
65
|
|
|
@@ -298,6 +299,7 @@ describe("notebookStateFromSession", () => {
|
|
|
298
299
|
hide_code: false,
|
|
299
300
|
disabled: false,
|
|
300
301
|
column: null,
|
|
302
|
+
expand_output: false,
|
|
301
303
|
},
|
|
302
304
|
serializedEditorState: null,
|
|
303
305
|
});
|
|
@@ -309,6 +311,7 @@ describe("notebookStateFromSession", () => {
|
|
|
309
311
|
hide_code: true,
|
|
310
312
|
disabled: true,
|
|
311
313
|
column: 1,
|
|
314
|
+
expand_output: true,
|
|
312
315
|
}),
|
|
313
316
|
]);
|
|
314
317
|
const result = notebookStateFromSession(null, notebook);
|
|
@@ -319,6 +322,7 @@ describe("notebookStateFromSession", () => {
|
|
|
319
322
|
hide_code: true,
|
|
320
323
|
disabled: true,
|
|
321
324
|
column: 1,
|
|
325
|
+
expand_output: true,
|
|
322
326
|
});
|
|
323
327
|
});
|
|
324
328
|
|
|
@@ -350,6 +354,7 @@ describe("notebookStateFromSession", () => {
|
|
|
350
354
|
hide_code: false,
|
|
351
355
|
disabled: false,
|
|
352
356
|
column: null,
|
|
357
|
+
expand_output: false,
|
|
353
358
|
},
|
|
354
359
|
serializedEditorState: null,
|
|
355
360
|
});
|
|
@@ -386,6 +391,7 @@ describe("notebookStateFromSession", () => {
|
|
|
386
391
|
hide_code: false,
|
|
387
392
|
disabled: false,
|
|
388
393
|
column: null,
|
|
394
|
+
expand_output: false,
|
|
389
395
|
},
|
|
390
396
|
serializedEditorState: null,
|
|
391
397
|
});
|
|
@@ -426,6 +432,7 @@ describe("notebookStateFromSession", () => {
|
|
|
426
432
|
hide_code: false,
|
|
427
433
|
disabled: false,
|
|
428
434
|
column: null,
|
|
435
|
+
expand_output: false,
|
|
429
436
|
},
|
|
430
437
|
serializedEditorState: null,
|
|
431
438
|
});
|
package/src/core/cells/cells.ts
CHANGED
|
@@ -125,7 +125,12 @@ export interface NotebookState {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
function withScratchCell(notebookState: NotebookState): NotebookState {
|
|
128
|
-
const config = {
|
|
128
|
+
const config = {
|
|
129
|
+
column: 0,
|
|
130
|
+
hide_code: false,
|
|
131
|
+
disabled: false,
|
|
132
|
+
expand_output: false,
|
|
133
|
+
};
|
|
129
134
|
return {
|
|
130
135
|
...notebookState,
|
|
131
136
|
cellData: {
|
|
@@ -164,6 +164,7 @@ function columnChanges(
|
|
|
164
164
|
column: newCol,
|
|
165
165
|
disabled: cell?.config.disabled ?? false,
|
|
166
166
|
hideCode: cell?.config.hide_code ?? false,
|
|
167
|
+
expandOutput: cell?.config.expand_output ?? false,
|
|
167
168
|
});
|
|
168
169
|
}
|
|
169
170
|
}
|
|
@@ -277,6 +278,7 @@ export function toDocumentChanges(
|
|
|
277
278
|
column: cell.config.column ?? null,
|
|
278
279
|
disabled: cell.config.disabled ?? false,
|
|
279
280
|
hideCode: cell.config.hide_code ?? false,
|
|
281
|
+
expandOutput: cell.config.expand_output ?? false,
|
|
280
282
|
},
|
|
281
283
|
];
|
|
282
284
|
}
|
|
@@ -452,7 +454,11 @@ export function fromDocumentChanges(
|
|
|
452
454
|
payload: { cellId: change.cellId, name: change.name },
|
|
453
455
|
});
|
|
454
456
|
}
|
|
455
|
-
if (
|
|
457
|
+
if (
|
|
458
|
+
change.config?.disabled != null ||
|
|
459
|
+
change.config?.column != null ||
|
|
460
|
+
change.config?.expand_output != null
|
|
461
|
+
) {
|
|
456
462
|
actions.push({
|
|
457
463
|
type: "updateCellConfig",
|
|
458
464
|
payload: {
|
|
@@ -464,6 +470,9 @@ export function fromDocumentChanges(
|
|
|
464
470
|
...(change.config.column != null && {
|
|
465
471
|
column: change.config.column,
|
|
466
472
|
}),
|
|
473
|
+
...(change.config.expand_output != null && {
|
|
474
|
+
expand_output: change.config.expand_output,
|
|
475
|
+
}),
|
|
467
476
|
},
|
|
468
477
|
},
|
|
469
478
|
});
|
|
@@ -560,6 +569,7 @@ export function fromDocumentChanges(
|
|
|
560
569
|
column: change.column,
|
|
561
570
|
disabled: change.disabled,
|
|
562
571
|
hide_code: change.hideCode,
|
|
572
|
+
expand_output: change.expandOutput,
|
|
563
573
|
},
|
|
564
574
|
},
|
|
565
575
|
});
|
|
@@ -1,34 +1,91 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useAtomValue } from "jotai";
|
|
4
|
+
import { selectAtom } from "jotai/utils";
|
|
5
|
+
import { useEffect, useMemo, useState } from "react";
|
|
6
|
+
import { useEvent } from "@/hooks/useEvent";
|
|
7
|
+
import { Logger } from "@/utils/Logger";
|
|
4
8
|
import type { OutputMessage } from "../kernel/messages";
|
|
9
|
+
import { viewStateAtom } from "../mode";
|
|
10
|
+
import { getRequestClient } from "../network/requests";
|
|
11
|
+
import { cellDataAtom, useCellActions } from "./cells";
|
|
5
12
|
import type { CellId } from "./ids";
|
|
6
13
|
|
|
7
14
|
// This does not need to be overcomplicated. We can just store the expanded
|
|
8
15
|
// state in a global map instead of Jotai since state is not shared between cells.
|
|
16
|
+
// The output area only falls back to its map where the `expand_output` config
|
|
17
|
+
// cannot be edited; see `useExpandedOutput`.
|
|
9
18
|
const expandedOutputs: Record<CellId, boolean> = {};
|
|
10
19
|
const expandedConsoleOutputs: Record<CellId, boolean> = {};
|
|
11
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Whether a cell's output is shown in full, instead of clamped to a fixed
|
|
23
|
+
* height. Covers the cell's output area only; console output is clamped
|
|
24
|
+
* independently, via `useExpandedConsoleOutput`.
|
|
25
|
+
*
|
|
26
|
+
* In edit mode, we toggle the cell's `expand_output` config, so the choice is persisted.
|
|
27
|
+
*/
|
|
12
28
|
export function useExpandedOutput(cellId: CellId) {
|
|
13
|
-
const
|
|
29
|
+
const { mode } = useAtomValue(viewStateAtom);
|
|
30
|
+
const { updateCellConfig } = useCellActions();
|
|
31
|
+
// Select just the flag: every output would otherwise re-render on each
|
|
32
|
+
// keystroke in its cell.
|
|
33
|
+
const isConfigExpanded = useAtomValue(
|
|
34
|
+
useMemo(
|
|
35
|
+
() =>
|
|
36
|
+
selectAtom(
|
|
37
|
+
cellDataAtom(cellId),
|
|
38
|
+
(data) => data?.config.expand_output ?? false,
|
|
39
|
+
Object.is,
|
|
40
|
+
),
|
|
41
|
+
[cellId],
|
|
42
|
+
),
|
|
43
|
+
);
|
|
44
|
+
const [isSessionExpanded, setIsSessionExpanded] = useState(
|
|
45
|
+
() => expandedOutputs[cellId] ?? isConfigExpanded,
|
|
46
|
+
);
|
|
14
47
|
|
|
15
48
|
// Sync state to external storage
|
|
16
49
|
useEffect(() => {
|
|
17
|
-
expandedOutputs[cellId] =
|
|
18
|
-
}, [cellId,
|
|
50
|
+
expandedOutputs[cellId] = isSessionExpanded;
|
|
51
|
+
}, [cellId, isSessionExpanded]);
|
|
19
52
|
|
|
20
|
-
|
|
53
|
+
const isEditable = mode === "edit";
|
|
54
|
+
const isExpanded = isEditable ? isConfigExpanded : isSessionExpanded;
|
|
55
|
+
|
|
56
|
+
const setIsExpanded = useEvent((expanded: boolean) => {
|
|
57
|
+
setIsSessionExpanded(expanded);
|
|
58
|
+
if (!isEditable) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const config = { expand_output: expanded };
|
|
62
|
+
updateCellConfig({ cellId, config });
|
|
63
|
+
getRequestClient()
|
|
64
|
+
.saveCellConfig({ configs: { [cellId]: config } })
|
|
65
|
+
.catch((error) => {
|
|
66
|
+
Logger.error("Failed to save expand_output config", error);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return [isExpanded, setIsExpanded] as const;
|
|
21
71
|
}
|
|
22
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Whether a cell's console output is shown in full. Deliberately not backed by
|
|
75
|
+
* `expand_output`: that config covers the cell's output area only, so console
|
|
76
|
+
* output stays a per-session, in-memory toggle.
|
|
77
|
+
*/
|
|
23
78
|
export function useExpandedConsoleOutput(cellId: CellId) {
|
|
24
|
-
const [
|
|
79
|
+
const [isExpanded, setIsExpanded] = useState(
|
|
80
|
+
expandedConsoleOutputs[cellId] ?? false,
|
|
81
|
+
);
|
|
25
82
|
|
|
26
83
|
// Sync state to external storage
|
|
27
84
|
useEffect(() => {
|
|
28
|
-
expandedConsoleOutputs[cellId] =
|
|
29
|
-
}, [cellId,
|
|
85
|
+
expandedConsoleOutputs[cellId] = isExpanded;
|
|
86
|
+
}, [cellId, isExpanded]);
|
|
30
87
|
|
|
31
|
-
return [
|
|
88
|
+
return [isExpanded, setIsExpanded] as const;
|
|
32
89
|
}
|
|
33
90
|
|
|
34
91
|
export function isOutputEmpty(
|
|
@@ -149,6 +149,7 @@ function createEmptyNotebookCell(): NotebookCell {
|
|
|
149
149
|
column: null,
|
|
150
150
|
disabled: false,
|
|
151
151
|
hide_code: false,
|
|
152
|
+
expand_output: false,
|
|
152
153
|
},
|
|
153
154
|
};
|
|
154
155
|
}
|
|
@@ -177,6 +178,7 @@ function createCellDataFromNotebook(
|
|
|
177
178
|
column: notebookCell.config?.column ?? null,
|
|
178
179
|
disabled: notebookCell.config?.disabled ?? false,
|
|
179
180
|
hide_code: notebookCell.config?.hide_code ?? false,
|
|
181
|
+
expand_output: notebookCell.config?.expand_output ?? false,
|
|
180
182
|
},
|
|
181
183
|
serializedEditorState: null,
|
|
182
184
|
};
|
package/src/core/cells/types.ts
CHANGED
|
@@ -27,6 +27,7 @@ export function createCell({
|
|
|
27
27
|
hide_code: false,
|
|
28
28
|
disabled: false,
|
|
29
29
|
column: null,
|
|
30
|
+
expand_output: false,
|
|
30
31
|
},
|
|
31
32
|
name: name,
|
|
32
33
|
code: code,
|
|
@@ -42,6 +43,7 @@ export function createCellConfig(config?: Partial<CellConfig>): CellConfig {
|
|
|
42
43
|
hide_code: false,
|
|
43
44
|
disabled: false,
|
|
44
45
|
column: null,
|
|
46
|
+
expand_output: false,
|
|
45
47
|
...config,
|
|
46
48
|
};
|
|
47
49
|
}
|