@marimo-team/frontend 0.19.3-dev3 → 0.19.3-dev30
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/assets/{CellStatus-CJVmn-JU.js → CellStatus-CGsC_xni.js} +1 -1
- package/dist/assets/{ConnectedDataExplorerComponent-KlUs_Sz3.js → ConnectedDataExplorerComponent-Cr6-n9Em.js} +1 -1
- package/dist/assets/{ErrorBoundary-Drf1manw.js → ErrorBoundary-C7JBxSzd.js} +1 -1
- package/dist/assets/{ImperativeModal-q6QlC2aZ.js → ImperativeModal-DVhvP4lH.js} +1 -1
- package/dist/assets/{JsonOutput-BLd1jTNA.js → JsonOutput-CCSLhScI.js} +1 -1
- package/dist/assets/{LazyAnyLanguageCodeMirror-jpEDlD0M.js → LazyAnyLanguageCodeMirror-Cp2punaU.js} +2 -2
- package/dist/assets/{MarimoErrorOutput-Orp0blpZ.js → MarimoErrorOutput-CDtUiLzW.js} +1 -1
- package/dist/assets/{RenderHTML-BzGWfPTJ.js → RenderHTML-B1PnGgGU.js} +1 -1
- package/dist/assets/VisuallyHidden-B9t3FhTP.js +1 -0
- package/dist/assets/{add-cell-with-ai-Dx5UA23s.js → add-cell-with-ai-DG5ez5tQ.js} +1 -1
- package/dist/assets/{add-database-form-MNQmbAaT.js → add-database-form-BDC4sw5d.js} +1 -1
- package/dist/assets/{agent-panel-BS2q53WX.js → agent-panel-DvdoiTMc.js} +15 -15
- package/dist/assets/{ai-model-dropdown-DZ7evAGU.js → ai-model-dropdown-DSzuccWn.js} +1 -1
- package/dist/assets/{alert-dialog-k5KxevGr.js → alert-dialog-jcHA5geR.js} +1 -1
- package/dist/assets/{any-language-editor-DQu1Tt2N.js → any-language-editor-Cm83E7D_.js} +1 -1
- package/dist/assets/{app-config-button-CsABtw-A.js → app-config-button-DrOOXwCm.js} +1 -1
- package/dist/assets/button-B8cGZzP5.js +1 -0
- package/dist/assets/{cache-panel-C1So4Zu3.js → cache-panel-1FqnpB9y.js} +1 -1
- package/dist/assets/{cell-editor-D4tKLHiP.js → cell-editor-Bowbis7w.js} +13 -13
- package/dist/assets/{cell-link-BoUpLV2S.js → cell-link-DXYH8FLx.js} +1 -1
- package/dist/assets/{cells-D_SkyFDn.js → cells-4S-e0VcC.js} +46 -46
- package/dist/assets/{chat-components-6dWNbFjV.js → chat-components-Bs4IxADW.js} +1 -1
- package/dist/assets/{chat-display-Cfg38gMM.js → chat-display-CPq1j1yR.js} +1 -1
- package/dist/assets/{chat-panel-CofEklYU.js → chat-panel-dvZilXEF.js} +1 -1
- package/dist/assets/{client-BUus2uot.js → client-DdSTQs8P.js} +1 -1
- package/dist/assets/{column-preview-9nPwQyJZ.js → column-preview-DtHgotrc.js} +1 -1
- package/dist/assets/{command-Qt3ng7cb.js → command-NXYtUgbp.js} +1 -1
- package/dist/assets/{command-palette-ptrGtoIl.js → command-palette-85dl4RPg.js} +1 -1
- package/dist/assets/{common-DE3UmpZO.js → common-DTmoX7TD.js} +1 -1
- package/dist/assets/config-Ba3eeYri.js +1 -0
- package/dist/assets/context-DHfVoQfl.js +1 -0
- package/dist/assets/{copy-icon-B69c-352.js → copy-icon-jWsqdLn1.js} +1 -1
- package/dist/assets/{datasource-CR_zEq5o.js → datasource-CPVUAqzI.js} +1 -1
- package/dist/assets/{dependency-graph-panel-DQnoPpen.js → dependency-graph-panel-VYsYCQNm.js} +1 -1
- package/dist/assets/{dialog-DUEuLcT2.js → dialog-CF5DtF1E.js} +1 -1
- package/dist/assets/{dist-DOFFh6Ii.js → dist-Dg7UO_Vw.js} +1 -1
- package/dist/assets/{documentation-panel-C0769uWv.js → documentation-panel-CwAtyJSz.js} +1 -1
- package/dist/assets/{download-CITws1-y.js → download-BcXr1SQk.js} +1 -1
- package/dist/assets/edit-page-CCa1yDjZ.js +12 -0
- package/dist/assets/{error-banner-DU5Qb8a8.js → error-banner-DvT0IGDZ.js} +1 -1
- package/dist/assets/{error-panel-B-EvbVVc.js → error-panel-BbbZ1gDy.js} +1 -1
- package/dist/assets/{es-CEEVxHsX.js → es-B3NV9-gC.js} +1 -1
- package/dist/assets/{field-DDKGFzpC.js → field-Clr_fqUr.js} +1 -1
- package/dist/assets/{file-explorer-panel-BqkMxs-d.js → file-explorer-panel-JB9Lb6XZ.js} +1 -1
- package/dist/assets/{floating-outline-p0aHdM2W.js → floating-outline-BDIr9Bbt.js} +1 -1
- package/dist/assets/{focus-D18AHojc.js → focus-DAgLzXHM.js} +1 -1
- package/dist/assets/{form-DEraWoX5.js → form-DVkjQxq_.js} +1 -1
- package/dist/assets/{glide-data-editor-D_bRnWfy.js → glide-data-editor-Dv8ZW9dk.js} +1 -1
- package/dist/assets/{globals-D3SeIm1j.js → globals-BJD8iIVw.js} +1 -1
- package/dist/assets/{home-page-9rDRaLCP.js → home-page-5ew0gT8b.js} +1 -1
- package/dist/assets/house-CncUa_LL.js +1 -0
- package/dist/assets/index-D2zgBMLw.js +43 -0
- package/dist/assets/index-__6MNWbe.css +2 -0
- package/dist/assets/input-B80Yt1uu.js +1 -0
- package/dist/assets/{kiosk-mode-DL9UBacr.js → kiosk-mode-Cev1VOAm.js} +1 -1
- package/dist/assets/{label-qwandMoh.js → label-CNZLffHW.js} +1 -1
- package/dist/assets/{layout-Bd6wzfjT.js → layout-CurIookF.js} +4 -4
- package/dist/assets/links-Bpd4gqTj.js +1 -0
- package/dist/assets/{logs-panel-C7VsvCHz.js → logs-panel-CLsE2AN1.js} +1 -1
- package/dist/assets/{markdown-renderer-C_xfLXiO.js → markdown-renderer-Cc0PiY-K.js} +1 -1
- package/dist/assets/{mode-BFwdGSZ7.js → mode-B3tNMXH2.js} +1 -1
- package/dist/assets/{multi-map-fjX9ImVF.js → multi-map-CQd4MZr5.js} +1 -1
- package/dist/assets/name-cell-input-lkGsSC32.js +1 -0
- package/dist/assets/{outline-panel-BlhMaZpZ.js → outline-panel-CR_3Njth.js} +1 -1
- package/dist/assets/{packages-panel-YNB3ay32.js → packages-panel-D2JfrhoE.js} +1 -1
- package/dist/assets/panels-CpuHPy5a.js +1 -0
- package/dist/assets/{process-output-4w8xDO0j.js → process-output-rKnBuRRW.js} +1 -1
- package/dist/assets/{readonly-python-code-DjP4vjBQ.js → readonly-python-code-D7ixCdRP.js} +1 -1
- package/dist/assets/{run-page-DRgXZvWr.js → run-page-UbtG3woR.js} +1 -1
- package/dist/assets/{scratchpad-panel-BYCWZWFJ.js → scratchpad-panel-Bvg9Sbf8.js} +1 -1
- package/dist/assets/{secrets-panel-CDWmmmBS.js → secrets-panel-BMY6PPth.js} +1 -1
- package/dist/assets/{select-D0g5GnIs.js → select-D9lTzMzP.js} +1 -1
- package/dist/assets/{session-panel-C0b1PCJc.js → session-panel-CE7qRaFP.js} +1 -1
- package/dist/assets/{slides-component-MkPkpql1.js → slides-component-Dp0Yv5b0.js} +1 -1
- package/dist/assets/{snippets-panel-CpjS6w9M.js → snippets-panel-CiNTJKw4.js} +1 -1
- package/dist/assets/state-CZqgb3sC.js +1 -0
- package/dist/assets/{state-kFdt1US2.js → state-lX2Tur1r.js} +1 -1
- package/dist/assets/{switch-C9iBa4rX.js → switch-utDdERLs.js} +1 -1
- package/dist/assets/{terminal-BvgBa6Ri.js → terminal-BWM0fOMh.js} +1 -1
- package/dist/assets/{textarea-D2hGxqGj.js → textarea-CuGxnSJT.js} +1 -1
- package/dist/assets/{tracing-CKdq5KMT.js → tracing-CfhQiEJB.js} +1 -1
- package/dist/assets/{tracing-panel-DXjACxb_.js → tracing-panel-BES8ykC_.js} +2 -2
- package/dist/assets/{types-VzFAm7Cv.js → types-BqIUl7zM.js} +1 -1
- package/dist/assets/{useAddCell-CVfRv5mq.js → useAddCell-B5Yugh3r.js} +1 -1
- package/dist/assets/useBoolean-DI-eW-xX.js +1 -0
- package/dist/assets/{useCellActionButton-Woqd9LSB.js → useCellActionButton-BNKqQ1-h.js} +1 -1
- package/dist/assets/{useDateFormatter-CV0QXb5P.js → useDateFormatter-DsANziQR.js} +1 -1
- package/dist/assets/{useDeleteCell-GHwc6J4l.js → useDeleteCell-ChzEFH8j.js} +1 -1
- package/dist/assets/{useDependencyPanelTab-B0ZsFCYF.js → useDependencyPanelTab-MCxvkAot.js} +1 -1
- package/dist/assets/useNotebookActions-BRPD06EX.js +1 -0
- package/dist/assets/{useNumberFormatter-D8ks3oPN.js → useNumberFormatter-FoXhpyAb.js} +1 -1
- package/dist/assets/usePress-DTwIUo40.js +7 -0
- package/dist/assets/{useRunCells-BZ_OFvV4.js → useRunCells-Dgv3VAFX.js} +1 -1
- package/dist/assets/{useSplitCell-BnJiHHep.js → useSplitCell-_rfoF197.js} +1 -1
- package/dist/assets/utilities.esm-C0AZu44u.js +3 -0
- package/dist/assets/{vega-component-DpAAiTdH.js → vega-component-BoLFf7jF.js} +1 -1
- package/dist/assets/{write-secret-modal-CLm48gMe.js → write-secret-modal-hOetwavI.js} +1 -1
- package/dist/index.html +54 -54
- package/package.json +5 -5
- package/src/components/app-config/__tests__/get-dirty-values.test.ts +1 -1
- package/src/components/app-config/user-config-form.tsx +1 -1
- package/src/components/chat/acp/agent-panel.tsx +56 -43
- package/src/components/editor/KernelStartupErrorModal.tsx +101 -0
- package/src/components/editor/actions/name-cell-input.tsx +10 -4
- package/src/components/editor/chrome/types.ts +2 -4
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +55 -58
- package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +150 -96
- package/src/components/editor/notebook-cell.tsx +13 -13
- package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +27 -0
- package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +6 -0
- package/src/components/utils/lazy-mount.tsx +29 -8
- package/src/core/MarimoApp.tsx +2 -0
- package/src/core/cells/cells.ts +1 -4
- package/src/core/cells/scrollCellIntoView.ts +3 -2
- package/src/core/codemirror/cm.ts +2 -0
- package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +123 -0
- package/src/core/codemirror/lsp/notebook-lsp.ts +44 -4
- package/src/core/codemirror/misc/__tests__/string-braces.test.ts +200 -0
- package/src/core/codemirror/misc/string-braces.ts +37 -0
- package/src/core/errors/state.ts +7 -1
- package/src/core/islands/main.ts +2 -0
- package/src/core/kernel/__tests__/handlers.test.ts +2 -2
- package/src/core/kernel/state.ts +1 -0
- package/src/core/network/__tests__/requests-lazy.test.ts +1 -1
- package/src/core/network/requests-lazy.ts +2 -2
- package/src/core/websocket/types.ts +1 -0
- package/src/core/websocket/useMarimoKernelConnection.tsx +18 -1
- package/src/css/app/Cell.css +6 -0
- package/src/css/globals.css +2 -0
- package/src/plugins/impl/chat/chat-ui.tsx +16 -4
- package/src/utils/events.ts +1 -0
- package/dist/assets/VisuallyHidden-BodIky8L.js +0 -1
- package/dist/assets/button-DuYGqRtX.js +0 -1
- package/dist/assets/config-babG4OBR.js +0 -1
- package/dist/assets/context-BAYdLMF_.js +0 -1
- package/dist/assets/edit-page-pktOsK3x.js +0 -12
- package/dist/assets/globe-CY9im410.js +0 -1
- package/dist/assets/index-CGjwCay2.js +0 -43
- package/dist/assets/index-nL7dJutx.css +0 -2
- package/dist/assets/input-CaEtLL8p.js +0 -1
- package/dist/assets/links-ENMiP32L.js +0 -1
- package/dist/assets/name-cell-input-CsDYsdH3.js +0 -1
- package/dist/assets/panels-DfOJ05Sp.js +0 -1
- package/dist/assets/state-BTRRCWOH.js +0 -1
- package/dist/assets/useBoolean-5kuXz69O.js +0 -1
- package/dist/assets/useNotebookActions-DQW0wwU6.js +0 -1
- package/dist/assets/usePress-C2LPFxyv.js +0 -7
- package/dist/assets/utilities.esm-FYD46c3d.js +0 -3
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ChevronDownIcon,
|
|
5
|
+
ExternalLinkIcon,
|
|
6
|
+
InfoIcon,
|
|
5
7
|
PowerOffIcon,
|
|
6
8
|
ZapIcon,
|
|
7
9
|
ZapOffIcon,
|
|
@@ -15,7 +17,9 @@ import {
|
|
|
15
17
|
DropdownMenuSeparator,
|
|
16
18
|
DropdownMenuTrigger,
|
|
17
19
|
} from "@/components/ui/dropdown-menu";
|
|
20
|
+
import { ExternalLink } from "@/components/ui/links";
|
|
18
21
|
import { Switch } from "@/components/ui/switch";
|
|
22
|
+
import { Tooltip, TooltipProvider } from "@/components/ui/tooltip";
|
|
19
23
|
import { useResolvedMarimoConfig } from "@/core/config/config";
|
|
20
24
|
import { useRequestClient } from "@/core/network/requests";
|
|
21
25
|
import { isWasm } from "@/core/wasm/utils";
|
|
@@ -99,117 +103,167 @@ export const RuntimeSettings: React.FC<RuntimeSettingsProps> = ({
|
|
|
99
103
|
</FooterItem>
|
|
100
104
|
</DropdownMenuTrigger>
|
|
101
105
|
<DropdownMenuContent align="start" className="w-64">
|
|
102
|
-
<DropdownMenuLabel>
|
|
106
|
+
<DropdownMenuLabel>
|
|
107
|
+
<div className="flex items-center justify-between w-full">
|
|
108
|
+
<span>Runtime reactivity</span>
|
|
109
|
+
<ExternalLink href="https://links.marimo.app/runtime-configuration">
|
|
110
|
+
<span className="text-xs font-normal flex items-center gap-1">
|
|
111
|
+
Docs
|
|
112
|
+
<ExternalLinkIcon className="w-3 h-3" />
|
|
113
|
+
</span>
|
|
114
|
+
</ExternalLink>
|
|
115
|
+
</div>
|
|
116
|
+
</DropdownMenuLabel>
|
|
103
117
|
<DropdownMenuSeparator />
|
|
104
118
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
<
|
|
108
|
-
<div className="flex items-center
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<div
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
<TooltipProvider>
|
|
120
|
+
{/* On startup toggle */}
|
|
121
|
+
<DisableIfOverridden name="runtime.auto_instantiate">
|
|
122
|
+
<div className="flex items-center justify-between px-2 py-2">
|
|
123
|
+
<div className="flex items-center space-x-2">
|
|
124
|
+
{config.runtime.auto_instantiate ? (
|
|
125
|
+
<ZapIcon size={14} className="text-amber-500" />
|
|
126
|
+
) : (
|
|
127
|
+
<ZapOffIcon size={14} className="text-muted-foreground" />
|
|
128
|
+
)}
|
|
129
|
+
<div>
|
|
130
|
+
<div className="text-sm font-medium flex items-center gap-1">
|
|
131
|
+
On startup
|
|
132
|
+
<Tooltip
|
|
133
|
+
content={
|
|
134
|
+
<div className="max-w-[200px]">
|
|
135
|
+
Whether to automatically run the notebook on startup
|
|
136
|
+
</div>
|
|
137
|
+
}
|
|
138
|
+
>
|
|
139
|
+
<InfoIcon className="w-3 h-3" />
|
|
140
|
+
</Tooltip>
|
|
141
|
+
</div>
|
|
142
|
+
<div className="text-xs text-muted-foreground">
|
|
143
|
+
{config.runtime.auto_instantiate ? "autorun" : "lazy"}
|
|
144
|
+
</div>
|
|
118
145
|
</div>
|
|
119
146
|
</div>
|
|
147
|
+
<Switch
|
|
148
|
+
checked={config.runtime.auto_instantiate}
|
|
149
|
+
onCheckedChange={handleStartupToggle}
|
|
150
|
+
size="sm"
|
|
151
|
+
/>
|
|
120
152
|
</div>
|
|
121
|
-
|
|
122
|
-
checked={config.runtime.auto_instantiate}
|
|
123
|
-
onCheckedChange={handleStartupToggle}
|
|
124
|
-
size="sm"
|
|
125
|
-
/>
|
|
126
|
-
</div>
|
|
127
|
-
</DisableIfOverridden>
|
|
153
|
+
</DisableIfOverridden>
|
|
128
154
|
|
|
129
|
-
|
|
155
|
+
<DropdownMenuSeparator />
|
|
130
156
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
157
|
+
{/* On cell change toggle */}
|
|
158
|
+
<DisableIfOverridden name="runtime.on_cell_change">
|
|
159
|
+
<div className="flex items-center justify-between px-2 py-2">
|
|
160
|
+
<div className="flex items-center space-x-2">
|
|
161
|
+
{config.runtime.on_cell_change === "autorun" ? (
|
|
162
|
+
<ZapIcon size={14} className="text-amber-500" />
|
|
163
|
+
) : (
|
|
164
|
+
<ZapOffIcon size={14} className="text-muted-foreground" />
|
|
165
|
+
)}
|
|
166
|
+
<div>
|
|
167
|
+
<div className="text-sm font-medium flex items-center gap-1">
|
|
168
|
+
On cell change
|
|
169
|
+
<Tooltip
|
|
170
|
+
content={
|
|
171
|
+
<div className="max-w-[300px]">
|
|
172
|
+
Whether to automatically run dependent cells after
|
|
173
|
+
running a cell
|
|
174
|
+
</div>
|
|
175
|
+
}
|
|
176
|
+
>
|
|
177
|
+
<InfoIcon className="w-3 h-3" />
|
|
178
|
+
</Tooltip>
|
|
179
|
+
</div>
|
|
180
|
+
<div className="text-xs text-muted-foreground">
|
|
181
|
+
{config.runtime.on_cell_change}
|
|
182
|
+
</div>
|
|
144
183
|
</div>
|
|
145
184
|
</div>
|
|
185
|
+
<Switch
|
|
186
|
+
checked={config.runtime.on_cell_change === "autorun"}
|
|
187
|
+
onCheckedChange={handleCellChangeToggle}
|
|
188
|
+
size="sm"
|
|
189
|
+
/>
|
|
146
190
|
</div>
|
|
147
|
-
|
|
148
|
-
checked={config.runtime.on_cell_change === "autorun"}
|
|
149
|
-
onCheckedChange={handleCellChangeToggle}
|
|
150
|
-
size="sm"
|
|
151
|
-
/>
|
|
152
|
-
</div>
|
|
153
|
-
</DisableIfOverridden>
|
|
191
|
+
</DisableIfOverridden>
|
|
154
192
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
193
|
+
{!isWasm() && (
|
|
194
|
+
<>
|
|
195
|
+
<DropdownMenuSeparator />
|
|
158
196
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
197
|
+
{/* On module change dropdown */}
|
|
198
|
+
<DisableIfOverridden name="runtime.auto_reload">
|
|
199
|
+
<div className="px-2 py-1">
|
|
200
|
+
<div className="flex items-center space-x-2 mb-2">
|
|
201
|
+
{config.runtime.auto_reload === "off" && (
|
|
202
|
+
<PowerOffIcon
|
|
203
|
+
size={14}
|
|
204
|
+
className="text-muted-foreground"
|
|
205
|
+
/>
|
|
206
|
+
)}
|
|
207
|
+
{config.runtime.auto_reload === "lazy" && (
|
|
208
|
+
<ZapOffIcon size={14} className="text-muted-foreground" />
|
|
209
|
+
)}
|
|
210
|
+
{config.runtime.auto_reload === "autorun" && (
|
|
211
|
+
<ZapIcon size={14} className="text-amber-500" />
|
|
212
|
+
)}
|
|
213
|
+
<div>
|
|
214
|
+
<div className="text-sm font-medium flex items-center gap-1">
|
|
215
|
+
On module change
|
|
216
|
+
<Tooltip
|
|
217
|
+
content={
|
|
218
|
+
<div className="max-w-[300px]">
|
|
219
|
+
Whether to run affected cells, mark them as stale,
|
|
220
|
+
or do nothing when an external module is updated
|
|
221
|
+
</div>
|
|
222
|
+
}
|
|
223
|
+
>
|
|
224
|
+
<InfoIcon className="w-3 h-3" />
|
|
225
|
+
</Tooltip>
|
|
226
|
+
</div>
|
|
227
|
+
<div className="text-xs text-muted-foreground">
|
|
228
|
+
{config.runtime.auto_reload}
|
|
229
|
+
</div>
|
|
176
230
|
</div>
|
|
177
231
|
</div>
|
|
232
|
+
<div className="space-y-1">
|
|
233
|
+
{["off", "lazy", "autorun"].map((option) => (
|
|
234
|
+
<button
|
|
235
|
+
key={option}
|
|
236
|
+
onClick={() =>
|
|
237
|
+
handleModuleReloadChange(
|
|
238
|
+
option as "off" | "lazy" | "autorun",
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
className={cn(
|
|
242
|
+
"w-full flex items-center px-2 py-1 text-sm rounded hover:bg-accent",
|
|
243
|
+
option === config.runtime.auto_reload && "bg-accent",
|
|
244
|
+
)}
|
|
245
|
+
>
|
|
246
|
+
{option === "off" && (
|
|
247
|
+
<PowerOffIcon size={12} className="mr-2" />
|
|
248
|
+
)}
|
|
249
|
+
{option === "lazy" && (
|
|
250
|
+
<ZapOffIcon size={12} className="mr-2" />
|
|
251
|
+
)}
|
|
252
|
+
{option === "autorun" && (
|
|
253
|
+
<ZapIcon size={12} className="mr-2" />
|
|
254
|
+
)}
|
|
255
|
+
<span className="capitalize">{option}</span>
|
|
256
|
+
{option === config.runtime.auto_reload && (
|
|
257
|
+
<span className="ml-auto">✓</span>
|
|
258
|
+
)}
|
|
259
|
+
</button>
|
|
260
|
+
))}
|
|
261
|
+
</div>
|
|
178
262
|
</div>
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
onClick={() =>
|
|
184
|
-
handleModuleReloadChange(
|
|
185
|
-
option as "off" | "lazy" | "autorun",
|
|
186
|
-
)
|
|
187
|
-
}
|
|
188
|
-
className={cn(
|
|
189
|
-
"w-full flex items-center px-2 py-1 text-sm rounded hover:bg-accent",
|
|
190
|
-
option === config.runtime.auto_reload && "bg-accent",
|
|
191
|
-
)}
|
|
192
|
-
>
|
|
193
|
-
{option === "off" && (
|
|
194
|
-
<PowerOffIcon size={12} className="mr-2" />
|
|
195
|
-
)}
|
|
196
|
-
{option === "lazy" && (
|
|
197
|
-
<ZapOffIcon size={12} className="mr-2" />
|
|
198
|
-
)}
|
|
199
|
-
{option === "autorun" && (
|
|
200
|
-
<ZapIcon size={12} className="mr-2" />
|
|
201
|
-
)}
|
|
202
|
-
<span className="capitalize">{option}</span>
|
|
203
|
-
{option === config.runtime.auto_reload && (
|
|
204
|
-
<span className="ml-auto">✓</span>
|
|
205
|
-
)}
|
|
206
|
-
</button>
|
|
207
|
-
))}
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
</DisableIfOverridden>
|
|
211
|
-
</>
|
|
212
|
-
)}
|
|
263
|
+
</DisableIfOverridden>
|
|
264
|
+
</>
|
|
265
|
+
)}
|
|
266
|
+
</TooltipProvider>
|
|
213
267
|
</DropdownMenuContent>
|
|
214
268
|
</DropdownMenu>
|
|
215
269
|
);
|
|
@@ -585,7 +585,7 @@ const EditableCellComponent = ({
|
|
|
585
585
|
className={cn(
|
|
586
586
|
className,
|
|
587
587
|
navigationProps.className,
|
|
588
|
-
"focus:ring-1 focus:ring-(--slate-
|
|
588
|
+
"focus:ring-1 focus:ring-(--slate-8) focus:ring-offset-2",
|
|
589
589
|
)}
|
|
590
590
|
ref={cellContainerRef}
|
|
591
591
|
{...cellDomProps(cellId, cellData.name)}
|
|
@@ -1032,16 +1032,12 @@ const SetupCellComponent = ({
|
|
|
1032
1032
|
const hasConsoleOutput = cellRuntime.consoleOutputs.length > 0;
|
|
1033
1033
|
const isErrorOutput = isErrorMime(cellRuntime.output?.mimetype);
|
|
1034
1034
|
|
|
1035
|
-
const className = clsx(
|
|
1036
|
-
|
|
1037
|
-
"
|
|
1038
|
-
"
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
"has-error": cellRuntime.errored,
|
|
1042
|
-
stopped: cellRuntime.stopped,
|
|
1043
|
-
},
|
|
1044
|
-
);
|
|
1035
|
+
const className = clsx("marimo-cell", "hover-actions-parent z-10", {
|
|
1036
|
+
interactive: true,
|
|
1037
|
+
"needs-run": needsRun,
|
|
1038
|
+
"has-error": cellRuntime.errored,
|
|
1039
|
+
stopped: cellRuntime.stopped,
|
|
1040
|
+
});
|
|
1045
1041
|
|
|
1046
1042
|
const handleRefactorWithAI: OnRefactorWithAI = useEvent(
|
|
1047
1043
|
(opts: { prompt: string; triggerImmediately: boolean }) => {
|
|
@@ -1076,7 +1072,7 @@ const SetupCellComponent = ({
|
|
|
1076
1072
|
{...mergeProps(navigationProps, {
|
|
1077
1073
|
className: cn(
|
|
1078
1074
|
className,
|
|
1079
|
-
"focus:ring-1 focus:ring-(--
|
|
1075
|
+
"focus:ring-1 focus:ring-(--slate-8) focus:ring-offset-2",
|
|
1080
1076
|
),
|
|
1081
1077
|
onBlur: closeCompletionHandler,
|
|
1082
1078
|
onKeyDown: resumeCompletionHandler,
|
|
@@ -1086,7 +1082,11 @@ const SetupCellComponent = ({
|
|
|
1086
1082
|
tabIndex={-1}
|
|
1087
1083
|
data-setup-cell={true}
|
|
1088
1084
|
>
|
|
1089
|
-
<div
|
|
1085
|
+
<div
|
|
1086
|
+
className={cn("tray")}
|
|
1087
|
+
data-has-output-above={false}
|
|
1088
|
+
data-hidden={!isCellCodeShown}
|
|
1089
|
+
>
|
|
1090
1090
|
<StagedAICellBackground
|
|
1091
1091
|
cellId={cellId}
|
|
1092
1092
|
className="mo-ai-setup-cell"
|
package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts
CHANGED
|
@@ -12,6 +12,8 @@ describe("useFocusFirstEditor", () => {
|
|
|
12
12
|
cb(0);
|
|
13
13
|
return 0;
|
|
14
14
|
});
|
|
15
|
+
// Mock document.hasFocus() to return true so focus logic runs
|
|
16
|
+
vi.spyOn(document, "hasFocus").mockReturnValue(true);
|
|
15
17
|
});
|
|
16
18
|
|
|
17
19
|
afterEach(() => {
|
|
@@ -120,4 +122,29 @@ describe("useFocusFirstEditor", () => {
|
|
|
120
122
|
writable: true,
|
|
121
123
|
});
|
|
122
124
|
});
|
|
125
|
+
|
|
126
|
+
it("should not focus when document does not have focus", () => {
|
|
127
|
+
// Mock document.hasFocus() to return false (e.g., when embedded in iframe)
|
|
128
|
+
vi.spyOn(document, "hasFocus").mockReturnValue(false);
|
|
129
|
+
|
|
130
|
+
const mockEditor = { focus: vi.fn() };
|
|
131
|
+
vi.spyOn(cellsModule, "getNotebook").mockReturnValue({
|
|
132
|
+
cellIds: { iterateTopLevelIds: ["cell-1"] },
|
|
133
|
+
cellData: {
|
|
134
|
+
"cell-1": { config: { hide_code: false } },
|
|
135
|
+
},
|
|
136
|
+
cellHandles: {
|
|
137
|
+
"cell-1": { current: { editorView: mockEditor } },
|
|
138
|
+
},
|
|
139
|
+
} as unknown as cellsModule.NotebookState);
|
|
140
|
+
|
|
141
|
+
renderHook(() => useFocusFirstEditor());
|
|
142
|
+
|
|
143
|
+
act(() => {
|
|
144
|
+
vi.advanceTimersByTime(100);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Focus should NOT be called when document doesn't have focus
|
|
148
|
+
expect(mockEditor.focus).not.toHaveBeenCalled();
|
|
149
|
+
});
|
|
123
150
|
});
|
|
@@ -19,6 +19,12 @@ export function useFocusFirstEditor() {
|
|
|
19
19
|
const timeout = setTimeout(() => {
|
|
20
20
|
// Let the DOM render
|
|
21
21
|
requestAnimationFrame(() => {
|
|
22
|
+
// Skip auto-focus if the document doesn't have focus to avoid
|
|
23
|
+
// stealing focus from outside (e.g., when embedded in an iframe)
|
|
24
|
+
if (!document.hasFocus()) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
// Check if the URL contains a scrollTo parameter
|
|
23
29
|
const hash = window.location.hash;
|
|
24
30
|
const cellName = extractCellNameFromHash(hash);
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
import React, {
|
|
2
|
+
import React, {
|
|
3
|
+
Activity,
|
|
4
|
+
type ActivityProps,
|
|
5
|
+
type PropsWithChildren,
|
|
6
|
+
} from "react";
|
|
3
7
|
|
|
4
8
|
interface Props {
|
|
5
9
|
isOpen: boolean;
|
|
@@ -12,13 +16,30 @@ export const LazyMount: React.FC<PropsWithChildren<Props>> = ({
|
|
|
12
16
|
isOpen,
|
|
13
17
|
children,
|
|
14
18
|
}) => {
|
|
15
|
-
const [
|
|
19
|
+
const [hasMountedBefore, setHasMountedBefore] = React.useState(false);
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
}, [isOpen, isMounted]);
|
|
21
|
+
if (isOpen && !hasMountedBefore) {
|
|
22
|
+
setHasMountedBefore(true);
|
|
23
|
+
}
|
|
22
24
|
|
|
23
|
-
return
|
|
25
|
+
return hasMountedBefore || isOpen ? children : null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Wraps a component in an Activity component. It is not mounted until it is open for the first time.
|
|
30
|
+
*/
|
|
31
|
+
export const LazyActivity: React.FC<PropsWithChildren<ActivityProps>> = (
|
|
32
|
+
props,
|
|
33
|
+
) => {
|
|
34
|
+
const [hasMountedBefore, setHasMountedBefore] = React.useState(false);
|
|
35
|
+
|
|
36
|
+
if (props.mode === "visible" && !hasMountedBefore) {
|
|
37
|
+
setHasMountedBefore(true);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (hasMountedBefore) {
|
|
41
|
+
return <Activity {...props} />;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return null;
|
|
24
45
|
};
|
package/src/core/MarimoApp.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import { getInitialAppMode } from "@/core/mode";
|
|
|
12
12
|
import { CssVariables } from "@/theme/ThemeProvider";
|
|
13
13
|
import { reactLazyWithPreload } from "@/utils/lazy";
|
|
14
14
|
import { ErrorBoundary } from "../components/editor/boundary/ErrorBoundary";
|
|
15
|
+
import { KernelStartupErrorModal } from "../components/editor/KernelStartupErrorModal";
|
|
15
16
|
import { ModalProvider } from "../components/modal/ImperativeModal";
|
|
16
17
|
import { Toaster } from "../components/ui/toaster";
|
|
17
18
|
import { TooltipProvider } from "../components/ui/tooltip";
|
|
@@ -91,6 +92,7 @@ const Providers = memo(({ children }: PropsWithChildren) => {
|
|
|
91
92
|
{children}
|
|
92
93
|
<Toaster />
|
|
93
94
|
<TailwindIndicator />
|
|
95
|
+
<KernelStartupErrorModal />
|
|
94
96
|
</ModalProvider>
|
|
95
97
|
</LocaleProvider>
|
|
96
98
|
</SlotzProvider>
|
package/src/core/cells/cells.ts
CHANGED
|
@@ -1325,10 +1325,7 @@ const {
|
|
|
1325
1325
|
};
|
|
1326
1326
|
},
|
|
1327
1327
|
addSetupCellIfDoesntExist: (state, action: { code?: string }) => {
|
|
1328
|
-
|
|
1329
|
-
if (code == null) {
|
|
1330
|
-
code = "# Initialization code that runs before all other cells";
|
|
1331
|
-
}
|
|
1328
|
+
const { code } = action;
|
|
1332
1329
|
|
|
1333
1330
|
if (state.cellIds.setupCellExists()) {
|
|
1334
1331
|
// Just focus on the existing setup cell
|
|
@@ -53,8 +53,9 @@ export function focusAndScrollCellIntoView({
|
|
|
53
53
|
Logger.warn("scrollCellIntoView: editor not found", cellId);
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
-
//
|
|
57
|
-
|
|
56
|
+
// Skip auto-focus if already focused, or if the document doesn't have
|
|
57
|
+
// focus to avoid stealing focus from outside (e.g., when embedded in an iframe)
|
|
58
|
+
if (editor.hasFocus || !document.hasFocus()) {
|
|
58
59
|
return;
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -64,6 +64,7 @@ import { getCurrentLanguageAdapter } from "./language/commands";
|
|
|
64
64
|
import { adaptiveLanguageConfiguration } from "./language/extension";
|
|
65
65
|
import { dndBundle } from "./misc/dnd";
|
|
66
66
|
import { pasteBundle } from "./misc/paste";
|
|
67
|
+
import { stringsAutoCloseBraces } from "./misc/string-braces";
|
|
67
68
|
import { reactiveReferencesBundle } from "./reactive-references/extension";
|
|
68
69
|
import { darkTheme } from "./theme/dark";
|
|
69
70
|
import { lightTheme } from "./theme/light";
|
|
@@ -203,6 +204,7 @@ export const basicBundle = (opts: CodeMirrorSetupOpts): Extension[] => {
|
|
|
203
204
|
hintTooltip(lspConfig),
|
|
204
205
|
copilotBundle(completionConfig),
|
|
205
206
|
foldGutter(),
|
|
207
|
+
stringsAutoCloseBraces(),
|
|
206
208
|
closeBrackets(),
|
|
207
209
|
completionKeymap(),
|
|
208
210
|
// to avoid clash with charDeleteBackward keymap
|
|
@@ -756,6 +756,129 @@ describe("NotebookLanguageServerClient", () => {
|
|
|
756
756
|
// Verify that the import cell was not changed
|
|
757
757
|
expect(mockView1.state.doc.toString()).toBe("import marimo as mo");
|
|
758
758
|
});
|
|
759
|
+
|
|
760
|
+
it("should only rename private variables in the current cell (issue #7810)", async () => {
|
|
761
|
+
const props = {
|
|
762
|
+
workspaceFolders: null,
|
|
763
|
+
capabilities: {
|
|
764
|
+
textDocument: {
|
|
765
|
+
rename: {
|
|
766
|
+
prepareSupport: true,
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
},
|
|
770
|
+
languageId: "python",
|
|
771
|
+
transport: {
|
|
772
|
+
sendData: vi.fn(),
|
|
773
|
+
subscribe: vi.fn(),
|
|
774
|
+
connect: vi.fn(),
|
|
775
|
+
transportRequestManager: {
|
|
776
|
+
send: vi.fn(),
|
|
777
|
+
},
|
|
778
|
+
} as any,
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
// Setup editor views - both cells have a private variable _x
|
|
782
|
+
const cell1Code = "_x = 1\nprint(_x)";
|
|
783
|
+
const cell2Code = "_x = 2\nprint(_x)";
|
|
784
|
+
|
|
785
|
+
const mockView1 = new EditorView({
|
|
786
|
+
doc: cell1Code,
|
|
787
|
+
extensions: [
|
|
788
|
+
languageAdapterState.init(() => new PythonLanguageAdapter()),
|
|
789
|
+
languageMetadataField.init(() => ({})),
|
|
790
|
+
languageServerWithClient({
|
|
791
|
+
client: mockClient as unknown as LanguageServerClient,
|
|
792
|
+
documentUri: CellDocumentUri.of(Cells.cell1),
|
|
793
|
+
...props,
|
|
794
|
+
}),
|
|
795
|
+
],
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
const mockView2 = new EditorView({
|
|
799
|
+
doc: cell2Code,
|
|
800
|
+
extensions: [
|
|
801
|
+
languageAdapterState.init(() => new PythonLanguageAdapter()),
|
|
802
|
+
languageMetadataField.init(() => ({})),
|
|
803
|
+
languageServerWithClient({
|
|
804
|
+
client: mockClient as unknown as LanguageServerClient,
|
|
805
|
+
documentUri: CellDocumentUri.of(Cells.cell2),
|
|
806
|
+
...props,
|
|
807
|
+
}),
|
|
808
|
+
],
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
(notebookClient as any).getNotebookEditors = () => ({
|
|
812
|
+
[Cells.cell1]: mockView1,
|
|
813
|
+
[Cells.cell2]: mockView2,
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
// Update the mock to return the correct codes
|
|
817
|
+
vi.spyOn(store, "get").mockImplementation((atom) => {
|
|
818
|
+
if (atom === topologicalCodesAtom) {
|
|
819
|
+
return {
|
|
820
|
+
cellIds: [Cells.cell1, Cells.cell2],
|
|
821
|
+
codes: {
|
|
822
|
+
[Cells.cell1]: cell1Code,
|
|
823
|
+
[Cells.cell2]: cell2Code,
|
|
824
|
+
},
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
return undefined;
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
// Setup rename params - renaming _x in cell1
|
|
831
|
+
const renameParams: LSP.RenameParams = {
|
|
832
|
+
textDocument: { uri: CellDocumentUri.of(Cells.cell1) },
|
|
833
|
+
position: { line: 0, character: 0 }, // position of '_x'
|
|
834
|
+
newName: "_y",
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// Open a document first to set up the lens
|
|
838
|
+
await notebookClient.textDocumentDidOpen({
|
|
839
|
+
textDocument: {
|
|
840
|
+
uri: CellDocumentUri.of(Cells.cell1),
|
|
841
|
+
languageId: "python",
|
|
842
|
+
version: 1,
|
|
843
|
+
text: cell1Code,
|
|
844
|
+
},
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// Mock the response from the language server
|
|
848
|
+
// The LSP server would rename _x in BOTH cells (since it sees the merged doc)
|
|
849
|
+
const mockRenameResponse: LSP.WorkspaceEdit = {
|
|
850
|
+
documentChanges: [
|
|
851
|
+
{
|
|
852
|
+
textDocument: {
|
|
853
|
+
uri: "file:///__marimo_notebook__.py",
|
|
854
|
+
version: 1,
|
|
855
|
+
},
|
|
856
|
+
edits: [
|
|
857
|
+
{
|
|
858
|
+
range: {
|
|
859
|
+
start: { line: 0, character: 0 },
|
|
860
|
+
end: { line: 3, character: 10 },
|
|
861
|
+
},
|
|
862
|
+
// LSP renames _x to _y in both cells
|
|
863
|
+
newText: "_y = 1\nprint(_y)\n_y = 2\nprint(_y)",
|
|
864
|
+
},
|
|
865
|
+
],
|
|
866
|
+
},
|
|
867
|
+
],
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
mockClient.textDocumentRename = vi
|
|
871
|
+
.fn()
|
|
872
|
+
.mockResolvedValue(mockRenameResponse);
|
|
873
|
+
|
|
874
|
+
// Call rename
|
|
875
|
+
await notebookClient.textDocumentRename(renameParams);
|
|
876
|
+
|
|
877
|
+
// The fix: only cell1 should be renamed, cell2 should remain unchanged
|
|
878
|
+
// because private variables are cell-local in marimo
|
|
879
|
+
expect(mockView1.state.doc.toString()).toBe("_y = 1\nprint(_y)");
|
|
880
|
+
expect(mockView2.state.doc.toString()).toBe("_x = 2\nprint(_x)");
|
|
881
|
+
});
|
|
759
882
|
});
|
|
760
883
|
|
|
761
884
|
describe("diagnostics handling", () => {
|