@marimo-team/islands 0.25.3-dev275 → 0.25.3-dev279
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-BuIXiuc5.js → ErrorBoundary-DmTMuDPR.js} +1 -1
- package/dist/{chat-ui-SZ6lSH52.js → chat-ui-v1Fdh0NA.js} +270 -270
- package/dist/{code-visibility-BEAPMrC-.js → code-visibility-Dw4-TXN0.js} +2 -2
- package/dist/{common-CEmzaoJ8.js → common-BXMFi4lr.js} +4947 -4943
- package/dist/{data-grid-overlay-editor-CUo25_W8.js → data-grid-overlay-editor-hZzwX7Ia.js} +1 -1
- package/dist/{error-entries-B-1yUdcH.js → error-entries-C1S-Rmyt.js} +545 -535
- package/dist/{feedback-button-BqiR7zMO.js → feedback-button-6Ui2TDLR.js} +5 -5
- package/dist/{glide-data-editor-B7dguvqk.js → glide-data-editor-PZNlrSDI.js} +3 -3
- package/dist/{globals-CYykXfGI.js → globals-DX6FPZYq.js} +1 -1
- package/dist/{html-to-image-DC_pmZLs.js → html-to-image-CqGUd58T.js} +14452 -14452
- package/dist/main.js +6031 -6036
- package/dist/{number-overlay-editor-C4u7SJAJ.js → number-overlay-editor-D0CsL3_R.js} +1 -1
- package/dist/{process-output-DYu84VfZ.js → process-output-DskX9jLa.js} +2 -2
- package/dist/{reveal-component-DGi-irHV.js → reveal-component-D7xeI1QR.js} +906 -906
- package/package.json +1 -1
- package/src/__mocks__/executions.ts +4 -2
- package/src/__mocks__/notebook.ts +0 -2
- package/src/__tests__/CellStatus.test.tsx +6 -6
- package/src/components/editor/__tests__/data-attributes.test.tsx +0 -2
- package/src/components/editor/__tests__/output-persistence.test.tsx +20 -5
- package/src/components/editor/cell/CellStatus.tsx +6 -5
- package/src/components/editor/cell/__tests__/useRunCells.test.tsx +169 -0
- package/src/components/editor/cell/collapse.tsx +3 -4
- package/src/components/editor/cell/useRunCells.ts +32 -3
- package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +2 -3
- package/src/components/editor/notebook-cell.tsx +23 -37
- package/src/components/editor/renderers/grid-layout/grid-layout.tsx +4 -10
- package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -2
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +8 -5
- package/src/components/slides/minimap.tsx +3 -2
- package/src/components/slides/reveal-component.tsx +3 -2
- package/src/components/slides/slide-cell-view.tsx +8 -8
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +0 -101
- package/src/core/cells/__tests__/actions.test.ts +0 -1
- package/src/core/cells/__tests__/cell.test.ts +81 -17
- package/src/core/cells/__tests__/cells.test.ts +0 -100
- package/src/core/cells/__tests__/document.test.ts +2 -8
- package/src/core/cells/__tests__/utils.test.ts +93 -24
- package/src/core/cells/actions.ts +0 -1
- package/src/core/cells/cell.ts +37 -14
- package/src/core/cells/cells.ts +10 -99
- package/src/core/cells/document.ts +2 -13
- package/src/core/cells/types.ts +0 -23
- package/src/core/cells/utils.ts +44 -17
- package/src/core/codemirror/cells/extensions.ts +0 -14
- package/src/core/errors/__tests__/error-entries.test.ts +40 -1
- package/src/core/errors/error-entries.ts +2 -3
- package/src/core/executions/__tests__/freshness.test.ts +420 -0
- package/src/core/executions/__tests__/hooks.test.tsx +106 -0
- package/src/core/executions/atoms.ts +22 -0
- package/src/core/executions/freshness.ts +164 -0
- package/src/core/executions/hooks.ts +17 -1
- package/src/core/executions/index.ts +3 -1
- package/src/core/islands/bootstrap.ts +0 -1
- package/src/core/kernel/handlers.ts +0 -4
- package/src/core/session/useNotebookSession.tsx +2 -7
- package/src/stories/cell-status.stories.tsx +12 -14
- package/src/stories/cell.stories.tsx +44 -10
- package/src/stories/layout/vertical/one-column.stories.tsx +0 -10
- package/src/components/editor/cell/__tests__/useRunCells.test.ts +0 -45
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
createCell,
|
|
28
28
|
createCellConfig,
|
|
29
29
|
createCellRuntimeState,
|
|
30
|
-
isEdited,
|
|
31
30
|
} from "./types";
|
|
32
31
|
|
|
33
32
|
// Following the document ----------------------------------------------------
|
|
@@ -49,13 +48,7 @@ function followCell(current: CellData, cell: EditableCell): CellData {
|
|
|
49
48
|
if (code === current.code) {
|
|
50
49
|
return { ...current, name: cell.name, config };
|
|
51
50
|
}
|
|
52
|
-
return {
|
|
53
|
-
...current,
|
|
54
|
-
code,
|
|
55
|
-
name: cell.name,
|
|
56
|
-
config,
|
|
57
|
-
edited: isEdited(current.lastCodeRun, code),
|
|
58
|
-
};
|
|
51
|
+
return { ...current, code, name: cell.name, config };
|
|
59
52
|
}
|
|
60
53
|
|
|
61
54
|
/**
|
|
@@ -83,17 +76,13 @@ export function applyDocument(
|
|
|
83
76
|
continue;
|
|
84
77
|
}
|
|
85
78
|
if (current === undefined) {
|
|
86
|
-
// A new cell with code is stale until it runs. The kernel's last run
|
|
87
|
-
// settles it on kernel-ready.
|
|
88
|
-
const code = cell.code ?? "";
|
|
89
79
|
cellData = {
|
|
90
80
|
...cellData,
|
|
91
81
|
[id]: createCell({
|
|
92
82
|
id,
|
|
93
|
-
code,
|
|
83
|
+
code: cell.code ?? "",
|
|
94
84
|
name: cell.name,
|
|
95
85
|
config: createCellConfig(cell.config),
|
|
96
|
-
edited: isEdited(null, code),
|
|
97
86
|
}),
|
|
98
87
|
};
|
|
99
88
|
cellRuntime = {
|
package/src/core/cells/types.ts
CHANGED
|
@@ -6,18 +6,6 @@ import type { CellId } from "./ids";
|
|
|
6
6
|
import { DEFAULT_CELL_NAME } from "./names";
|
|
7
7
|
import type { Outline } from "./outline";
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Whether a cell's code has changed since it last ran. A cell that never ran
|
|
11
|
-
* is edited once it has code. Whitespace at the ends does not count.
|
|
12
|
-
*
|
|
13
|
-
* TODO(MO-8403): Delete with `lastCodeRun`.
|
|
14
|
-
*/
|
|
15
|
-
export function isEdited(lastCodeRun: string | null, code: string): boolean {
|
|
16
|
-
return lastCodeRun === null
|
|
17
|
-
? code.trim().length > 0
|
|
18
|
-
: lastCodeRun.trim() !== code.trim();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
9
|
/**
|
|
22
10
|
* Create a new cell with default state.
|
|
23
11
|
*/
|
|
@@ -25,8 +13,6 @@ export function createCell({
|
|
|
25
13
|
id,
|
|
26
14
|
name = DEFAULT_CELL_NAME,
|
|
27
15
|
code = "",
|
|
28
|
-
lastCodeRun = null,
|
|
29
|
-
edited = false,
|
|
30
16
|
config,
|
|
31
17
|
}: Partial<CellData> & { id: CellId }): CellData {
|
|
32
18
|
return {
|
|
@@ -39,8 +25,6 @@ export function createCell({
|
|
|
39
25
|
},
|
|
40
26
|
name: name,
|
|
41
27
|
code: code,
|
|
42
|
-
edited: edited,
|
|
43
|
-
lastCodeRun: lastCodeRun,
|
|
44
28
|
};
|
|
45
29
|
}
|
|
46
30
|
|
|
@@ -61,7 +45,6 @@ export function createCellRuntimeState(
|
|
|
61
45
|
outline: null,
|
|
62
46
|
output: null,
|
|
63
47
|
consoleOutputs: [],
|
|
64
|
-
staleInputs: false,
|
|
65
48
|
debuggerActive: false,
|
|
66
49
|
...state,
|
|
67
50
|
};
|
|
@@ -76,10 +59,6 @@ export interface CellData {
|
|
|
76
59
|
name: string;
|
|
77
60
|
/** current contents of the editor */
|
|
78
61
|
code: string;
|
|
79
|
-
/** whether this cell has been modified since its last run */
|
|
80
|
-
edited: boolean;
|
|
81
|
-
/** snapshot of code that was last run */
|
|
82
|
-
lastCodeRun: string | null;
|
|
83
62
|
/** cell configuration */
|
|
84
63
|
config: CellConfig;
|
|
85
64
|
}
|
|
@@ -97,8 +76,6 @@ export interface CellRuntimeState {
|
|
|
97
76
|
outline: Outline | null;
|
|
98
77
|
/** messages encoding the cell's console outputs. TODO(MO-8405) */
|
|
99
78
|
consoleOutputs: ConsoleOutputMessage[];
|
|
100
|
-
/** whether the cell has stale inputs. TODO(MO-8403) */
|
|
101
|
-
staleInputs: boolean;
|
|
102
79
|
/** debugger active */
|
|
103
80
|
debuggerActive: boolean;
|
|
104
81
|
/** serialization message. TODO(MO-8414) */
|
package/src/core/cells/utils.ts
CHANGED
|
@@ -4,8 +4,11 @@ import type { EditorView } from "@codemirror/view";
|
|
|
4
4
|
import {
|
|
5
5
|
type CellExecutionInputs,
|
|
6
6
|
type CellExecutionView,
|
|
7
|
+
type CellFreshness,
|
|
8
|
+
type CellFreshnessLookup,
|
|
7
9
|
cellExecutionView,
|
|
8
10
|
} from "@/core/executions";
|
|
11
|
+
import type { Executions } from "@/core/notebook/replica";
|
|
9
12
|
import { Objects } from "@/utils/objects";
|
|
10
13
|
import type { MarimoError, OutputMessage } from "../kernel/messages";
|
|
11
14
|
import { isErrorMime } from "../mime";
|
|
@@ -15,8 +18,9 @@ import type { CellId } from "./ids";
|
|
|
15
18
|
export function notebookNeedsRun(
|
|
16
19
|
state: NotebookState,
|
|
17
20
|
executions: CellExecutionInputs,
|
|
21
|
+
freshness: CellFreshnessLookup,
|
|
18
22
|
) {
|
|
19
|
-
return staleCellIds(state, executions).length > 0;
|
|
23
|
+
return staleCellIds(state, executions, freshness).length > 0;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
export function notebookCells(state: NotebookState) {
|
|
@@ -78,13 +82,13 @@ export function getUndoLabel(state: NotebookState): string {
|
|
|
78
82
|
* errored, or running.
|
|
79
83
|
*/
|
|
80
84
|
export function getDescendantsStatus(
|
|
81
|
-
state: NotebookState,
|
|
82
85
|
executions: CellExecutionInputs,
|
|
86
|
+
freshness: CellFreshnessLookup,
|
|
83
87
|
descendants: readonly CellId[],
|
|
84
88
|
) {
|
|
85
89
|
const views = descendants.map((id) => cellExecutionView(executions, id));
|
|
86
90
|
const stale = descendants.some(
|
|
87
|
-
(id) =>
|
|
91
|
+
(id) => freshness(id).sourceChanged || freshness(id).inputsChanged,
|
|
88
92
|
);
|
|
89
93
|
const errored = views.some((view) => view.outcome === "error");
|
|
90
94
|
const runningOrQueued = views.some(
|
|
@@ -104,21 +108,41 @@ export function getDescendantsStatus(
|
|
|
104
108
|
export function staleCellIds(
|
|
105
109
|
state: NotebookState,
|
|
106
110
|
executions: CellExecutionInputs,
|
|
111
|
+
freshness: CellFreshnessLookup,
|
|
107
112
|
) {
|
|
108
|
-
const { cellIds, cellData
|
|
113
|
+
const { cellIds, cellData } = state;
|
|
109
114
|
return cellIds.filter((cellId) => {
|
|
110
115
|
const execution = cellExecutionView(executions, cellId);
|
|
116
|
+
if (execution.status !== "idle") {
|
|
117
|
+
// A run in progress covers the source it was asked for. Only an edit
|
|
118
|
+
// since then, visible once the host has planned the run, needs another.
|
|
119
|
+
return (
|
|
120
|
+
inFlight(executions.executions, cellId) &&
|
|
121
|
+
freshness(cellId).sourceChanged
|
|
122
|
+
);
|
|
123
|
+
}
|
|
111
124
|
return (
|
|
112
125
|
isUninstantiated(execution) ||
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
cellNeedsRun({
|
|
127
|
+
freshness: freshness(cellId),
|
|
128
|
+
interrupted: execution.outcome === "interrupted",
|
|
129
|
+
disabled: cellData[cellId].config.disabled,
|
|
130
|
+
blocked: execution.blocked,
|
|
131
|
+
})
|
|
118
132
|
);
|
|
119
133
|
});
|
|
120
134
|
}
|
|
121
135
|
|
|
136
|
+
/** Whether the host holds a planned or started execution of the cell that has not completed. */
|
|
137
|
+
function inFlight(executions: Executions, cellId: CellId): boolean {
|
|
138
|
+
const latest = executions.latest.get(cellId);
|
|
139
|
+
const record =
|
|
140
|
+
latest === undefined
|
|
141
|
+
? undefined
|
|
142
|
+
: executions.executions.get(latest)?.record;
|
|
143
|
+
return record !== undefined && record.status !== "completed";
|
|
144
|
+
}
|
|
145
|
+
|
|
122
146
|
/** Whether a cell has never run: no result to show and nothing in flight. */
|
|
123
147
|
export function isUninstantiated({
|
|
124
148
|
status,
|
|
@@ -128,24 +152,27 @@ export function isUninstantiated({
|
|
|
128
152
|
}
|
|
129
153
|
|
|
130
154
|
/**
|
|
131
|
-
* Whether a cell needs to be run
|
|
132
|
-
*
|
|
133
|
-
*
|
|
155
|
+
* Whether a cell needs to be run: its source changed, its last run was
|
|
156
|
+
* interrupted, or an input changed and the cell can run. A disabled cell,
|
|
157
|
+
* or one blocked by a disabled ancestor, is not flagged for changed inputs
|
|
158
|
+
* until it can run again.
|
|
134
159
|
*/
|
|
135
160
|
export function cellNeedsRun({
|
|
136
|
-
|
|
161
|
+
freshness,
|
|
137
162
|
interrupted,
|
|
138
|
-
staleInputs,
|
|
139
163
|
disabled,
|
|
140
164
|
blocked,
|
|
141
165
|
}: {
|
|
142
|
-
|
|
166
|
+
freshness: CellFreshness;
|
|
143
167
|
interrupted: boolean;
|
|
144
|
-
staleInputs: boolean;
|
|
145
168
|
disabled: boolean | undefined;
|
|
146
169
|
blocked: boolean;
|
|
147
170
|
}): boolean {
|
|
148
|
-
return
|
|
171
|
+
return (
|
|
172
|
+
freshness.sourceChanged ||
|
|
173
|
+
interrupted ||
|
|
174
|
+
(freshness.inputsChanged && !(disabled || blocked))
|
|
175
|
+
);
|
|
149
176
|
}
|
|
150
177
|
|
|
151
178
|
export function cellStatusClasses({
|
|
@@ -23,7 +23,6 @@ import { createObservable } from "@/core/state/observable";
|
|
|
23
23
|
import { formatKeymapExtension } from "../extensions";
|
|
24
24
|
import { formattingChangeEffect } from "../format";
|
|
25
25
|
import { goToDefinitionAtCursorPosition } from "../go-to-definition/utils";
|
|
26
|
-
import { getCellCode } from "../language/cell-code";
|
|
27
26
|
import { isAtEndOfEditor, isAtStartOfEditor } from "../utils";
|
|
28
27
|
import {
|
|
29
28
|
breakpointGutter,
|
|
@@ -327,19 +326,6 @@ function cellCodeEditing(hotkeys: HotkeyProvider): Extension[] {
|
|
|
327
326
|
return;
|
|
328
327
|
}
|
|
329
328
|
const cellId = update.view.state.facet(cellIdState);
|
|
330
|
-
// The code itself reaches the document through the editor's binding.
|
|
331
|
-
// Formatting, including a language switch, rewrites the code without
|
|
332
|
-
// editing it, so the cell stays as run or as edited as it was.
|
|
333
|
-
const formatted = update.transactions.some((tr) =>
|
|
334
|
-
tr.effects.some((effect) => effect.is(formattingChangeEffect)),
|
|
335
|
-
);
|
|
336
|
-
if (formatted) {
|
|
337
|
-
update.view.state.facet(cellActionsState).codeFormatted({
|
|
338
|
-
cellId,
|
|
339
|
-
before: getCellCode(update.startState),
|
|
340
|
-
after: getCellCode(update.state),
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
329
|
|
|
344
330
|
// Clear pending cut state if this cell was marked for cut
|
|
345
331
|
const pendingCutCellIds = store.get(pendingCutCellIdsAtom);
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
+
import { createStore } from "jotai";
|
|
3
4
|
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { MockNotebook } from "@/__mocks__/notebook";
|
|
4
6
|
import { cellId } from "@/__tests__/branded";
|
|
5
|
-
import {
|
|
7
|
+
import { notebookAtom } from "@/core/cells/cells";
|
|
8
|
+
import {
|
|
9
|
+
type CellErrorEntry,
|
|
10
|
+
formatCellError,
|
|
11
|
+
getCellErrorEntries,
|
|
12
|
+
} from "../error-entries";
|
|
6
13
|
|
|
7
14
|
describe("formatCellError", () => {
|
|
8
15
|
it("formats current tracebacks without notebook source", () => {
|
|
@@ -23,3 +30,35 @@ describe("formatCellError", () => {
|
|
|
23
30
|
expect(text).not.toContain("<span");
|
|
24
31
|
});
|
|
25
32
|
});
|
|
33
|
+
|
|
34
|
+
describe("getCellErrorEntries", () => {
|
|
35
|
+
it("pairs an error with the source that raised it, not a later edit", () => {
|
|
36
|
+
const id = cellId("c1");
|
|
37
|
+
const store = createStore();
|
|
38
|
+
store.set(
|
|
39
|
+
notebookAtom,
|
|
40
|
+
MockNotebook.notebookState({
|
|
41
|
+
cellData: { [id]: { code: "print('fixed')" } },
|
|
42
|
+
cellRuntime: {
|
|
43
|
+
[id]: {
|
|
44
|
+
output: {
|
|
45
|
+
channel: "marimo-error",
|
|
46
|
+
mimetype: "application/vnd.marimo+error",
|
|
47
|
+
data: [
|
|
48
|
+
{
|
|
49
|
+
type: "exception",
|
|
50
|
+
exception_type: "ZeroDivisionError",
|
|
51
|
+
msg: "division by zero",
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
timestamp: 0,
|
|
55
|
+
code: "1 / 0",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
expect(getCellErrorEntries(store)[0]?.cellCode).toBe("1 / 0");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -93,9 +93,8 @@ export function getCellErrorEntries(store: JotaiStore): CellErrorEntry[] {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
const cellName = displayCellName(cellData[cellId].name, cellIndex);
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
const cellCode = cellData[cellId].lastCodeRun ?? cellData[cellId].code;
|
|
96
|
+
// The source that raised, since the cell may have been edited since.
|
|
97
|
+
const cellCode = output.code ?? cellData[cellId].code;
|
|
99
98
|
|
|
100
99
|
entries.push({
|
|
101
100
|
cellId,
|