@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
|
@@ -37,8 +37,10 @@ import { Label } from "@/components/ui/label";
|
|
|
37
37
|
import { toast } from "@/components/ui/use-toast";
|
|
38
38
|
import { aiCompletionCellAtom } from "@/core/ai/state";
|
|
39
39
|
import { maybeAddMarimoImport } from "@/core/cells/add-missing-import";
|
|
40
|
-
import { hasOnlyOneCellAtom
|
|
40
|
+
import { hasOnlyOneCellAtom } from "@/core/cells/cells";
|
|
41
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
41
42
|
import { type CellId, SETUP_CELL_ID } from "@/core/cells/ids";
|
|
43
|
+
import { useNotebookDocumentEdit } from "@/core/notebook/document";
|
|
42
44
|
import type { CellData } from "@/core/cells/types";
|
|
43
45
|
import { formatEditorViews } from "@/core/codemirror/format";
|
|
44
46
|
import {
|
|
@@ -53,7 +55,6 @@ import {
|
|
|
53
55
|
autoInstantiateAtom,
|
|
54
56
|
} from "@/core/config/config";
|
|
55
57
|
import { kioskModeAtom } from "@/core/mode";
|
|
56
|
-
import { useRequestClient } from "@/core/network/requests";
|
|
57
58
|
import type { CellConfig, RuntimeState } from "@/core/network/types";
|
|
58
59
|
import { canLinkToCell, createCellLink } from "@/utils/cell-urls";
|
|
59
60
|
import { copyToClipboard } from "@/utils/copy";
|
|
@@ -83,16 +84,15 @@ interface Props {
|
|
|
83
84
|
|
|
84
85
|
export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
85
86
|
const {
|
|
86
|
-
createNewCell: createCell,
|
|
87
|
-
updateCellConfig,
|
|
88
|
-
updateCellName,
|
|
89
87
|
moveCell,
|
|
90
88
|
sendToTop,
|
|
91
89
|
sendToBottom,
|
|
92
90
|
addColumnBreakpoint,
|
|
93
91
|
clearCellOutput,
|
|
94
92
|
markUntouched,
|
|
93
|
+
createCell,
|
|
95
94
|
} = useCellActions();
|
|
95
|
+
const edit = useNotebookDocumentEdit();
|
|
96
96
|
const splitCell = useSplitCellCallback();
|
|
97
97
|
const runCell = useRunCell(cell?.cellId);
|
|
98
98
|
const hasOnlyOneCell = useAtomValue(hasOnlyOneCellAtom);
|
|
@@ -104,7 +104,6 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
104
104
|
const autoInstantiate = useAtomValue(autoInstantiateAtom);
|
|
105
105
|
const kioskMode = useAtomValue(kioskModeAtom);
|
|
106
106
|
const appWidth = useAtomValue(appWidthAtom);
|
|
107
|
-
const { saveCellConfig } = useRequestClient();
|
|
108
107
|
|
|
109
108
|
if (!cell || kioskMode) {
|
|
110
109
|
return [];
|
|
@@ -120,16 +119,13 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
120
119
|
status,
|
|
121
120
|
} = cell;
|
|
122
121
|
|
|
123
|
-
const toggleDisabled =
|
|
124
|
-
|
|
125
|
-
await saveCellConfig({ configs: { [cellId]: newConfig } });
|
|
126
|
-
updateCellConfig({ cellId, config: newConfig });
|
|
122
|
+
const toggleDisabled = () => {
|
|
123
|
+
edit((tx) => tx.updateConfig(cellId, { disabled: !config.disabled }));
|
|
127
124
|
};
|
|
128
125
|
|
|
129
|
-
const toggleHideCode =
|
|
126
|
+
const toggleHideCode = () => {
|
|
130
127
|
const newConfig: Partial<CellConfig> = { hide_code: !config.hide_code };
|
|
131
|
-
|
|
132
|
-
updateCellConfig({ cellId, config: newConfig });
|
|
128
|
+
edit((tx) => tx.updateConfig(cellId, newConfig));
|
|
133
129
|
const editorView = getEditorView();
|
|
134
130
|
// If we're hiding the code, we should blur the editor
|
|
135
131
|
// otherwise, we should focus it
|
|
@@ -221,20 +217,18 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
221
217
|
if (!editorView) {
|
|
222
218
|
return;
|
|
223
219
|
}
|
|
224
|
-
maybeAddMarimoImport({ autoInstantiate,
|
|
220
|
+
maybeAddMarimoImport({ autoInstantiate, createCell });
|
|
225
221
|
switchLanguage(editorView, {
|
|
226
222
|
language: "markdown",
|
|
227
223
|
keepCodeAsIs: false,
|
|
228
224
|
});
|
|
229
225
|
// Code stays visible until the user blurs the cell
|
|
230
226
|
if (!config.hide_code && MARKDOWN_INITIAL_HIDE_CODE) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
config: { hide_code: MARKDOWN_INITIAL_HIDE_CODE },
|
|
237
|
-
});
|
|
227
|
+
edit((tx) =>
|
|
228
|
+
tx.updateConfig(cellId, {
|
|
229
|
+
hide_code: MARKDOWN_INITIAL_HIDE_CODE,
|
|
230
|
+
}),
|
|
231
|
+
);
|
|
238
232
|
markUntouched({ cellId });
|
|
239
233
|
}
|
|
240
234
|
},
|
|
@@ -266,7 +260,7 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
266
260
|
}
|
|
267
261
|
maybeAddMarimoImport({
|
|
268
262
|
autoInstantiate,
|
|
269
|
-
|
|
263
|
+
createCell,
|
|
270
264
|
});
|
|
271
265
|
switchLanguage(editorView, {
|
|
272
266
|
language: "sql",
|
|
@@ -288,7 +282,7 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
288
282
|
),
|
|
289
283
|
label: "Create cell above",
|
|
290
284
|
hotkey: "cell.createAbove",
|
|
291
|
-
handle: () => createCell({
|
|
285
|
+
handle: () => createCell({ before: cellId }),
|
|
292
286
|
hidden: isSetupCell,
|
|
293
287
|
redundant: true,
|
|
294
288
|
},
|
|
@@ -301,7 +295,7 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
301
295
|
),
|
|
302
296
|
label: "Create cell below",
|
|
303
297
|
hotkey: "cell.createBelow",
|
|
304
|
-
handle: () => createCell({
|
|
298
|
+
handle: () => createCell({ after: cellId }),
|
|
305
299
|
redundant: true,
|
|
306
300
|
},
|
|
307
301
|
{
|
|
@@ -406,7 +400,7 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
406
400
|
}
|
|
407
401
|
}}
|
|
408
402
|
onChange={(newName) =>
|
|
409
|
-
|
|
403
|
+
edit((tx) => tx.setName(cellId, newName))
|
|
410
404
|
}
|
|
411
405
|
/>
|
|
412
406
|
</div>
|
|
@@ -417,7 +411,7 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
417
411
|
<NameCellInput
|
|
418
412
|
placeholder={"cell name"}
|
|
419
413
|
value={name}
|
|
420
|
-
onChange={(newName) =>
|
|
414
|
+
onChange={(newName) => edit((tx) => tx.setName(cellId, newName))}
|
|
421
415
|
onEnterKey={() => closePopover?.()}
|
|
422
416
|
/>
|
|
423
417
|
),
|
|
@@ -62,8 +62,9 @@ import {
|
|
|
62
62
|
getNotebook,
|
|
63
63
|
hasDisabledCellsAtom,
|
|
64
64
|
undoLabelAtom,
|
|
65
|
-
useCellActions,
|
|
66
65
|
} from "@/core/cells/cells";
|
|
66
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
67
|
+
import { useNotebookDocumentEdit } from "@/core/notebook/document";
|
|
67
68
|
import { disabledCellIds } from "@/core/cells/utils";
|
|
68
69
|
import { capabilitiesAtom } from "@/core/config/capabilities";
|
|
69
70
|
import { aiEnabledAtom, useResolvedMarimoConfig } from "@/core/config/config";
|
|
@@ -77,7 +78,6 @@ import { createShareableLink } from "@/core/wasm/share";
|
|
|
77
78
|
import { isWasm } from "@/core/wasm/utils";
|
|
78
79
|
import { useDetectedDataSources } from "@/hooks/useDataSourceDiscovery";
|
|
79
80
|
import { copyToClipboard } from "@/utils/copy";
|
|
80
|
-
import { Objects } from "@/utils/objects";
|
|
81
81
|
import { Strings } from "@/utils/strings";
|
|
82
82
|
import { newNotebookURL } from "@/utils/urls";
|
|
83
83
|
import { useRunAllCells } from "../cell/useRunCells";
|
|
@@ -127,12 +127,11 @@ export function useNotebookActions({
|
|
|
127
127
|
const aiEnabled = useAtomValue(aiEnabledAtom);
|
|
128
128
|
|
|
129
129
|
const {
|
|
130
|
-
updateCellConfig,
|
|
131
130
|
undoDeleteCell,
|
|
132
131
|
clearAllCellOutputs,
|
|
133
|
-
addSetupCellIfDoesntExist,
|
|
134
132
|
collapseAllCells,
|
|
135
133
|
expandAllCells,
|
|
134
|
+
addSetupCell,
|
|
136
135
|
} = useCellActions();
|
|
137
136
|
const restartKernel = useRestartKernel();
|
|
138
137
|
const runAllCells = useRunAllCells();
|
|
@@ -142,7 +141,8 @@ export function useNotebookActions({
|
|
|
142
141
|
const { handleClick: openSettings } = useOpenSettingsToTab();
|
|
143
142
|
const setKeyboardShortcutsOpen = useSetAtom(keyboardShortcutsAtom);
|
|
144
143
|
const setExportOptions = useSetAtom(exportOptionsAtom);
|
|
145
|
-
const { readCode
|
|
144
|
+
const { readCode } = useRequestClient();
|
|
145
|
+
const edit = useNotebookDocumentEdit();
|
|
146
146
|
const detectedDatabaseSources = useDetectedDataSources("database");
|
|
147
147
|
const detectedStorageSources = useDetectedDataSources("storage");
|
|
148
148
|
const addDetectedDataSource = useAddDetectedDataSource();
|
|
@@ -449,18 +449,13 @@ export function useNotebookActions({
|
|
|
449
449
|
icon: <ZapIcon size={14} strokeWidth={1.5} />,
|
|
450
450
|
label: "Enable all cells",
|
|
451
451
|
hidden: !hasDisabledCells || kioskMode,
|
|
452
|
-
handle:
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
await saveCellConfig({ configs: newConfigs });
|
|
460
|
-
// update on FE
|
|
461
|
-
for (const cellId of ids) {
|
|
462
|
-
updateCellConfig({ cellId, config: { disabled: false } });
|
|
463
|
-
}
|
|
452
|
+
handle: () => {
|
|
453
|
+
const ids = disabledCellIds(getNotebook());
|
|
454
|
+
edit((tx) => {
|
|
455
|
+
for (const cellId of ids) {
|
|
456
|
+
tx.updateConfig(cellId, { disabled: false });
|
|
457
|
+
}
|
|
458
|
+
});
|
|
464
459
|
},
|
|
465
460
|
},
|
|
466
461
|
|
|
@@ -469,7 +464,7 @@ export function useNotebookActions({
|
|
|
469
464
|
icon: <DiamondPlusIcon size={14} strokeWidth={1.5} />,
|
|
470
465
|
label: "Add setup cell",
|
|
471
466
|
handle: () => {
|
|
472
|
-
|
|
467
|
+
addSetupCell();
|
|
473
468
|
},
|
|
474
469
|
},
|
|
475
470
|
{
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { useCallback } from "react";
|
|
4
|
-
import { getNotebook
|
|
4
|
+
import { getNotebook } from "@/core/cells/cells";
|
|
5
5
|
import type { CellId } from "@/core/cells/ids";
|
|
6
6
|
import { MarkdownLanguageAdapter } from "@/core/codemirror/language/languages/markdown";
|
|
7
|
-
import {
|
|
7
|
+
import { useNotebookDocumentEdit } from "@/core/notebook/document";
|
|
8
8
|
import type { CellConfig } from "@/core/network/types";
|
|
9
9
|
import { Objects } from "@/utils/objects";
|
|
10
10
|
|
|
@@ -21,11 +21,10 @@ const cellCodeKind = (code: string): CellCodeKind =>
|
|
|
21
21
|
* cell of the given kind.
|
|
22
22
|
*/
|
|
23
23
|
export const useSetCodeVisibility = () => {
|
|
24
|
-
const
|
|
25
|
-
const { saveCellConfig } = useRequestClient();
|
|
24
|
+
const edit = useNotebookDocumentEdit();
|
|
26
25
|
|
|
27
26
|
return useCallback(
|
|
28
|
-
|
|
27
|
+
(hidden: boolean, kind: CellCodeKind) => {
|
|
29
28
|
const notebook = getNotebook();
|
|
30
29
|
|
|
31
30
|
const newConfigs: Record<CellId, Partial<CellConfig>> = {};
|
|
@@ -46,12 +45,12 @@ export const useSetCodeVisibility = () => {
|
|
|
46
45
|
return;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
48
|
+
edit((tx) => {
|
|
49
|
+
for (const [cellId, config] of entries) {
|
|
50
|
+
tx.updateConfig(cellId, config);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
54
53
|
},
|
|
55
|
-
[
|
|
54
|
+
[edit],
|
|
56
55
|
);
|
|
57
56
|
};
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { useCallback } from "react";
|
|
4
|
-
import {
|
|
5
|
-
getNotebook,
|
|
6
|
-
type NotebookState,
|
|
7
|
-
useCellActions,
|
|
8
|
-
} from "@/core/cells/cells";
|
|
4
|
+
import { getNotebook, type NotebookState } from "@/core/cells/cells";
|
|
9
5
|
import type { CellId } from "@/core/cells/ids";
|
|
10
6
|
import { isOutputEmpty } from "@/core/cells/outputs";
|
|
11
|
-
import {
|
|
7
|
+
import { useNotebookDocumentEdit } from "@/core/notebook/document";
|
|
12
8
|
import type { CellConfig } from "@/core/network/types";
|
|
13
9
|
import { Objects } from "@/utils/objects";
|
|
14
10
|
|
|
@@ -44,24 +40,23 @@ export function outputExpansionConfigs(
|
|
|
44
40
|
* every output to a fixed height, by setting each cell's `expand_output` config.
|
|
45
41
|
*/
|
|
46
42
|
export const useSetOutputsExpanded = () => {
|
|
47
|
-
const
|
|
48
|
-
const { saveCellConfig } = useRequestClient();
|
|
43
|
+
const edit = useNotebookDocumentEdit();
|
|
49
44
|
|
|
50
45
|
return useCallback(
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
(expanded: boolean) => {
|
|
47
|
+
const entries = Objects.entries(
|
|
48
|
+
outputExpansionConfigs(getNotebook(), expanded),
|
|
49
|
+
);
|
|
55
50
|
if (entries.length === 0) {
|
|
56
51
|
return;
|
|
57
52
|
}
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
54
|
+
edit((tx) => {
|
|
55
|
+
for (const [cellId, config] of entries) {
|
|
56
|
+
tx.updateConfig(cellId, config);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
64
59
|
},
|
|
65
|
-
[
|
|
60
|
+
[edit],
|
|
66
61
|
);
|
|
67
62
|
};
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
DropdownMenuTrigger,
|
|
11
11
|
} from "@/components/ui/dropdown-menu";
|
|
12
12
|
import { maybeAddMarimoImport } from "@/core/cells/add-missing-import";
|
|
13
|
-
import { useCellActions } from "@/core/cells/
|
|
13
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
14
14
|
import { LanguageAdapters } from "@/core/codemirror/language/LanguageAdapters";
|
|
15
15
|
import { MARKDOWN_INITIAL_HIDE_CODE } from "@/core/codemirror/language/languages/markdown";
|
|
16
16
|
import {
|
|
@@ -33,7 +33,7 @@ export const CreateCellButton = ({
|
|
|
33
33
|
onClick: ((opts: { code: string; hideCode?: boolean }) => void) | undefined;
|
|
34
34
|
oneClickShortcut: "shift" | "mod";
|
|
35
35
|
}) => {
|
|
36
|
-
const {
|
|
36
|
+
const { createCell, addSetupCell } = useCellActions();
|
|
37
37
|
const shortcut = `${oneClickShortcut}-Click`;
|
|
38
38
|
const [open, setOpen] = useState(false);
|
|
39
39
|
// Time the dropdown last opened, to ignore the click that opened it
|
|
@@ -62,7 +62,7 @@ export const CreateCellButton = ({
|
|
|
62
62
|
// enabled; the user experience is confusing otherwise (how does the user
|
|
63
63
|
// know they need to run import marimo as mo. first?).
|
|
64
64
|
const addMarkdownCell = () => {
|
|
65
|
-
maybeAddMarimoImport({ autoInstantiate: true,
|
|
65
|
+
maybeAddMarimoImport({ autoInstantiate: true, createCell });
|
|
66
66
|
onClick?.({
|
|
67
67
|
code: LanguageAdapters.markdown.defaultCode,
|
|
68
68
|
hideCode: MARKDOWN_INITIAL_HIDE_CODE,
|
|
@@ -70,14 +70,10 @@ export const CreateCellButton = ({
|
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
const addSQLCell = () => {
|
|
73
|
-
maybeAddMarimoImport({ autoInstantiate: true,
|
|
73
|
+
maybeAddMarimoImport({ autoInstantiate: true, createCell });
|
|
74
74
|
onClick?.({ code: LanguageAdapters.sql.defaultCode });
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
const addSetupCell = () => {
|
|
78
|
-
addSetupCellIfDoesntExist({});
|
|
79
|
-
};
|
|
80
|
-
|
|
81
77
|
const renderIcon = (icon: React.ReactNode) => {
|
|
82
78
|
return <div className="mr-3 text-muted-foreground">{icon}</div>;
|
|
83
79
|
};
|
|
@@ -170,7 +166,7 @@ export const CreateCellButton = ({
|
|
|
170
166
|
{renderIcon(<DatabaseIcon size={13} strokeWidth={1.5} />)}
|
|
171
167
|
SQL cell
|
|
172
168
|
</DropdownMenuItem>
|
|
173
|
-
<DropdownMenuItem onClick={addSetupCell}>
|
|
169
|
+
<DropdownMenuItem onClick={() => addSetupCell()}>
|
|
174
170
|
{renderIcon(<DiamondPlusIcon size={13} strokeWidth={1.5} />)}
|
|
175
171
|
Setup cell
|
|
176
172
|
</DropdownMenuItem>
|
|
@@ -14,8 +14,10 @@ vi.mock("@/components/editor/cell/useDeleteCell", () => ({
|
|
|
14
14
|
|
|
15
15
|
vi.mock("@/core/cells/cells", () => ({
|
|
16
16
|
getCellEditorView: vi.fn(),
|
|
17
|
+
}));
|
|
18
|
+
vi.mock("@/core/cells/actions", () => ({
|
|
17
19
|
useCellActions: () => ({
|
|
18
|
-
|
|
20
|
+
createCell: vi.fn(),
|
|
19
21
|
updateCellCode: vi.fn(),
|
|
20
22
|
}),
|
|
21
23
|
}));
|
|
@@ -10,7 +10,9 @@ import { Button } from "@/components/ui/button";
|
|
|
10
10
|
import { DelayMount } from "@/components/utils/delay-mount";
|
|
11
11
|
import { aiCompletionCellAtom } from "@/core/ai/state";
|
|
12
12
|
import { maybeAddMarimoImport } from "@/core/cells/add-missing-import";
|
|
13
|
-
import { getNotebook
|
|
13
|
+
import { getNotebook } from "@/core/cells/cells";
|
|
14
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
15
|
+
import { useNotebookDocumentEdit } from "@/core/notebook/document";
|
|
14
16
|
import { SETUP_CELL_ID } from "@/core/cells/ids";
|
|
15
17
|
import { usePendingDeleteService } from "@/core/cells/pending-delete-service";
|
|
16
18
|
import type { CellData, CellRuntimeState } from "@/core/cells/types";
|
|
@@ -36,7 +38,6 @@ import { autoInstantiateAtom, isAiFeatureEnabled } from "@/core/config/config";
|
|
|
36
38
|
import type { UserConfig } from "@/core/config/config-schema";
|
|
37
39
|
import { OverridingHotkeyProvider } from "@/core/hotkeys/hotkeys";
|
|
38
40
|
import { connectionAtom } from "@/core/network/connection";
|
|
39
|
-
import { useRequestClient } from "@/core/network/requests";
|
|
40
41
|
import { canUseRtc, isRtcEnabled } from "@/core/rtc/state";
|
|
41
42
|
import { useSaveNotebook } from "@/core/saving/save-component";
|
|
42
43
|
import { isAppConnecting } from "@/core/session/connection-utils";
|
|
@@ -135,7 +136,7 @@ const CellEditorInternal = ({
|
|
|
135
136
|
const deleteCell = useDeleteCellCallback();
|
|
136
137
|
const { saveOrNameNotebook } = useSaveNotebook();
|
|
137
138
|
const pendingDeleteService = usePendingDeleteService();
|
|
138
|
-
const
|
|
139
|
+
const edit = useNotebookDocumentEdit();
|
|
139
140
|
|
|
140
141
|
const loading = status === "running" || status === "queued";
|
|
141
142
|
const cellActions = useCellActions();
|
|
@@ -175,9 +176,7 @@ const CellEditorInternal = ({
|
|
|
175
176
|
const toggleHideCode = useEvent(() => {
|
|
176
177
|
// Use cellConfig.hide_code instead of hidden, since it may be temporarily shown
|
|
177
178
|
const nextHidden = !cellConfig.hide_code;
|
|
178
|
-
|
|
179
|
-
void saveCellConfig({ configs: { [cellId]: { hide_code: nextHidden } } });
|
|
180
|
-
cellActions.updateCellConfig({ cellId, config: { hide_code: nextHidden } });
|
|
179
|
+
edit((tx) => tx.updateConfig(cellId, { hide_code: nextHidden }));
|
|
181
180
|
return nextHidden;
|
|
182
181
|
});
|
|
183
182
|
|
|
@@ -186,17 +185,13 @@ const CellEditorInternal = ({
|
|
|
186
185
|
const afterToggleMarkdown = useEvent(() => {
|
|
187
186
|
maybeAddMarimoImport({
|
|
188
187
|
autoInstantiate,
|
|
189
|
-
|
|
188
|
+
createCell: cellActions.createCell,
|
|
190
189
|
});
|
|
191
190
|
// Code stays visible until the user blurs the cell
|
|
192
191
|
if (!cellConfig.hide_code && MARKDOWN_INITIAL_HIDE_CODE) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
cellActions.updateCellConfig({
|
|
197
|
-
cellId,
|
|
198
|
-
config: { hide_code: MARKDOWN_INITIAL_HIDE_CODE },
|
|
199
|
-
});
|
|
192
|
+
edit((tx) =>
|
|
193
|
+
tx.updateConfig(cellId, { hide_code: MARKDOWN_INITIAL_HIDE_CODE }),
|
|
194
|
+
);
|
|
200
195
|
cellActions.markUntouched({ cellId });
|
|
201
196
|
}
|
|
202
197
|
});
|
|
@@ -204,7 +199,7 @@ const CellEditorInternal = ({
|
|
|
204
199
|
const afterToggleSQL = useEvent(() => {
|
|
205
200
|
maybeAddMarimoImport({
|
|
206
201
|
autoInstantiate,
|
|
207
|
-
|
|
202
|
+
createCell: cellActions.createCell,
|
|
208
203
|
});
|
|
209
204
|
});
|
|
210
205
|
|
|
@@ -224,11 +219,9 @@ const CellEditorInternal = ({
|
|
|
224
219
|
saveNotebook: saveOrNameNotebook,
|
|
225
220
|
createManyBelow: (cells) => {
|
|
226
221
|
for (const code of cells.toReversed()) {
|
|
227
|
-
cellActions.
|
|
222
|
+
cellActions.createCell({
|
|
223
|
+
after: cellId,
|
|
228
224
|
code,
|
|
229
|
-
before: false,
|
|
230
|
-
cellId: cellId,
|
|
231
|
-
// If the code already exists, skip creation
|
|
232
225
|
skipIfCodeExists: true,
|
|
233
226
|
});
|
|
234
227
|
}
|
|
@@ -237,7 +230,7 @@ const CellEditorInternal = ({
|
|
|
237
230
|
const notebook = getNotebook();
|
|
238
231
|
// No setup cell yet: create one with this code at the top.
|
|
239
232
|
if (!notebook.cellIds.setupCellExists()) {
|
|
240
|
-
cellActions.
|
|
233
|
+
cellActions.addSetupCell({ code });
|
|
241
234
|
return;
|
|
242
235
|
}
|
|
243
236
|
// Setup cell exists: append the pasted code to it. Prefer updating
|
|
@@ -2,28 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
import { useAtomValue } from "jotai";
|
|
4
4
|
import { maybeAddAltairImport } from "@/core/cells/add-missing-import";
|
|
5
|
-
import { useCellActions } from "@/core/cells/
|
|
5
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
6
6
|
import { useLastFocusedCellId } from "@/core/cells/focus";
|
|
7
7
|
import { autoInstantiateAtom } from "@/core/config/config";
|
|
8
8
|
|
|
9
9
|
export function useAddCodeToNewCell(): (code: string) => void {
|
|
10
10
|
const autoInstantiate = useAtomValue(autoInstantiateAtom);
|
|
11
11
|
const lastFocusedCellId = useLastFocusedCellId();
|
|
12
|
-
const {
|
|
12
|
+
const { createCell } = useCellActions();
|
|
13
13
|
|
|
14
14
|
return (code: string) => {
|
|
15
15
|
if (code.includes("alt")) {
|
|
16
16
|
maybeAddAltairImport({
|
|
17
17
|
autoInstantiate,
|
|
18
|
-
|
|
18
|
+
createCell,
|
|
19
19
|
fromCellId: lastFocusedCellId,
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
code: code,
|
|
25
|
-
before: false,
|
|
26
|
-
cellId: lastFocusedCellId ?? "__end__",
|
|
27
|
-
});
|
|
23
|
+
createCell({ after: lastFocusedCellId, code });
|
|
28
24
|
};
|
|
29
25
|
}
|
|
@@ -3,35 +3,22 @@
|
|
|
3
3
|
import useEvent from "react-use-event-hook";
|
|
4
4
|
import { UndoButton } from "@/components/buttons/undo-button";
|
|
5
5
|
import { toast } from "@/components/ui/use-toast";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
notebookAtom,
|
|
9
|
-
useCellActions,
|
|
10
|
-
} from "@/core/cells/cells";
|
|
6
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
7
|
+
import { notebookAtom } from "@/core/cells/cells";
|
|
11
8
|
import type { CellId } from "@/core/cells/ids";
|
|
12
|
-
import { useRequestClient } from "@/core/network/requests";
|
|
13
9
|
import { store } from "@/core/state/jotai";
|
|
14
10
|
|
|
15
11
|
export function useDeleteCellCallback() {
|
|
16
|
-
const {
|
|
17
|
-
const { sendDeleteCell } = useRequestClient();
|
|
12
|
+
const { deleteCells, undoDeleteCell } = useCellActions();
|
|
18
13
|
|
|
19
14
|
return useEvent((opts: { cellId: CellId }) => {
|
|
20
|
-
// Can't delete the last cell
|
|
21
|
-
if (store.get(hasOnlyOneCellAtom)) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
15
|
const { cellId } = opts;
|
|
26
16
|
const notebook = store.get(notebookAtom);
|
|
27
17
|
const isEmptyCell = (notebook.cellData[cellId]?.code ?? "").trim() === "";
|
|
28
18
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// Fall back on failure
|
|
33
|
-
undoDeleteCell();
|
|
34
|
-
});
|
|
19
|
+
if (!deleteCells({ cellIds: [cellId] })) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
35
22
|
|
|
36
23
|
if (!isEmptyCell) {
|
|
37
24
|
const { dismiss } = toast({
|
|
@@ -53,33 +40,20 @@ export function useDeleteCellCallback() {
|
|
|
53
40
|
}
|
|
54
41
|
|
|
55
42
|
export function useDeleteManyCellsCallback() {
|
|
56
|
-
const {
|
|
57
|
-
const { sendDeleteCell } = useRequestClient();
|
|
43
|
+
const { deleteCells, undoDeleteCell } = useCellActions();
|
|
58
44
|
|
|
59
|
-
return useEvent(
|
|
60
|
-
|
|
61
|
-
if (store.get(hasOnlyOneCellAtom)) {
|
|
45
|
+
return useEvent((opts: { cellIds: CellId[] }) => {
|
|
46
|
+
if (!deleteCells({ cellIds: opts.cellIds })) {
|
|
62
47
|
return;
|
|
63
48
|
}
|
|
64
49
|
|
|
65
|
-
const { cellIds } = opts;
|
|
66
|
-
for (const cellId of cellIds) {
|
|
67
|
-
await sendDeleteCell({ cellId }).then(() => {
|
|
68
|
-
deleteCell({ cellId });
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
50
|
const { dismiss } = toast({
|
|
73
51
|
title: "Cells deleted",
|
|
74
52
|
action: (
|
|
75
53
|
<UndoButton
|
|
76
54
|
data-testid="undo-delete-button"
|
|
77
55
|
onClick={() => {
|
|
78
|
-
|
|
79
|
-
// This function does not take a cellId,
|
|
80
|
-
// so we just undo the number of cells that were deleted
|
|
81
|
-
undoDeleteCell();
|
|
82
|
-
}
|
|
56
|
+
undoDeleteCell();
|
|
83
57
|
dismiss();
|
|
84
58
|
}}
|
|
85
59
|
/>
|
|
@@ -3,11 +3,8 @@
|
|
|
3
3
|
import { closeCompletion } from "@codemirror/autocomplete";
|
|
4
4
|
import { atom, useSetAtom } from "jotai";
|
|
5
5
|
import useEvent from "react-use-event-hook";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
type NotebookState,
|
|
9
|
-
useCellActions,
|
|
10
|
-
} from "@/core/cells/cells";
|
|
6
|
+
import { getNotebook, type NotebookState } from "@/core/cells/cells";
|
|
7
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
11
8
|
import type { CellId } from "@/core/cells/ids";
|
|
12
9
|
import { enabledCellIds, staleCellIds } from "@/core/cells/utils";
|
|
13
10
|
import { getCurrentLanguageAdapter } from "@/core/codemirror/language/commands";
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import useEvent from "react-use-event-hook";
|
|
4
4
|
import { UndoButton } from "@/components/buttons/undo-button";
|
|
5
5
|
import { toast } from "@/components/ui/use-toast";
|
|
6
|
-
import { getCellEditorView
|
|
6
|
+
import { getCellEditorView } from "@/core/cells/cells";
|
|
7
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
7
8
|
import type { CellId } from "@/core/cells/ids";
|
|
8
9
|
import { getEditorCodeAsPython } from "@/core/codemirror/language/utils";
|
|
9
10
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import { FileTextIcon } from "lucide-react";
|
|
4
4
|
import React from "react";
|
|
5
5
|
import { ClearButton } from "@/components/buttons/clear-button";
|
|
6
|
-
import {
|
|
6
|
+
import { useCellLogs } from "@/core/cells/cells";
|
|
7
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
7
8
|
import {
|
|
8
9
|
type CellLog,
|
|
9
10
|
formatLogTimestamp,
|
|
@@ -22,7 +22,7 @@ import { Suspense } from "react";
|
|
|
22
22
|
import { Spinner } from "@/components/icons/spinner";
|
|
23
23
|
import { Button } from "@/components/ui/button";
|
|
24
24
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
25
|
-
import { useCellActions } from "@/core/cells/
|
|
25
|
+
import { useCellActions } from "@/core/cells/actions";
|
|
26
26
|
import { useLastFocusedCellId } from "@/core/cells/focus";
|
|
27
27
|
import { useRequestClient } from "@/core/network/requests";
|
|
28
28
|
import { LazyAnyLanguageCodeMirror } from "@/plugins/impl/code/LazyAnyLanguageCodeMirror";
|
|
@@ -125,18 +125,16 @@ const SnippetViewer: React.FC<{ snippet: Snippet; onClose: () => void }> = ({
|
|
|
125
125
|
onClose,
|
|
126
126
|
}) => {
|
|
127
127
|
const { theme } = useTheme();
|
|
128
|
-
const {
|
|
128
|
+
const { createCell } = useCellActions();
|
|
129
129
|
const lastFocusedCellId = useLastFocusedCellId();
|
|
130
130
|
|
|
131
131
|
const handleInsertSnippet = () => {
|
|
132
132
|
// Add below last focused cell in reverse order
|
|
133
133
|
for (const section of snippet.sections.toReversed()) {
|
|
134
134
|
if (section.code) {
|
|
135
|
-
|
|
135
|
+
createCell({
|
|
136
|
+
after: lastFocusedCellId,
|
|
136
137
|
code: section.code,
|
|
137
|
-
before: false,
|
|
138
|
-
cellId: lastFocusedCellId ?? "__end__",
|
|
139
|
-
// If the code already exists, skip creation
|
|
140
138
|
skipIfCodeExists: true,
|
|
141
139
|
});
|
|
142
140
|
}
|
|
@@ -144,11 +142,7 @@ const SnippetViewer: React.FC<{ snippet: Snippet; onClose: () => void }> = ({
|
|
|
144
142
|
};
|
|
145
143
|
|
|
146
144
|
const handleInsertCode = (code: string) => {
|
|
147
|
-
|
|
148
|
-
code,
|
|
149
|
-
before: false,
|
|
150
|
-
cellId: lastFocusedCellId ?? "__end__",
|
|
151
|
-
});
|
|
145
|
+
createCell({ after: lastFocusedCellId, code });
|
|
152
146
|
};
|
|
153
147
|
|
|
154
148
|
return (
|