@marimo-team/islands 0.19.3-dev7 → 0.19.3
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/{Combination-33P1MEPK.js → Combination-BOmAhdTT.js} +1 -1
- package/dist/{ConnectedDataExplorerComponent-BIfUtj_S.js → ConnectedDataExplorerComponent-D5KcOOzu.js} +7 -7
- package/dist/{any-language-editor-Bda9cY1_.js → any-language-editor-vYraVrwE.js} +3 -3
- package/dist/assets/__vite-browser-external-CgHmDpAZ.js +1 -0
- package/dist/assets/{worker-njnjDMwL.js → worker-BR7KVExK.js} +2 -2
- package/dist/{button-BlF-78eJ.js → button-D6ZIdUA3.js} +1 -1
- package/dist/{check-DDykH_Yi.js → check-S8ldILuD.js} +1 -1
- package/dist/{copy-B5nooU3m.js → copy-ACOJ1BXr.js} +1 -1
- package/dist/{error-banner-UH0Nxilf.js → error-banner-BhqH4mGj.js} +2 -2
- package/dist/{esm-D197NGQX.js → esm-DOBJQbuy.js} +4 -4
- package/dist/{glide-data-editor-Bv8bVIJ9.js → glide-data-editor-DsVDCmV2.js} +6 -6
- package/dist/{label-oKuiQuiM.js → label-BaX2bLJa.js} +4 -4
- package/dist/main.js +455 -459
- package/dist/{mermaid-JA6veDHv.js → mermaid-DZjjc-kI.js} +2 -2
- package/dist/{slides-component-CJJp5XN4.js → slides-component-BHWhzwDN.js} +1 -1
- package/dist/{spec-hsYzGr6F.js → spec-B1PGDiGh.js} +4 -4
- package/dist/style.css +1 -1
- package/dist/{types-DEmfj_i8.js → types-CbQF8CBX.js} +294 -255
- package/dist/{useAsyncData-BGpae_uu.js → useAsyncData-TLXJC7yx.js} +1 -1
- package/dist/{useDeepCompareMemoize-1wVjsLov.js → useDeepCompareMemoize-DVnEG7jx.js} +3 -3
- package/dist/{useTheme-DdLjooMf.js → useTheme-BllQjRdW.js} +1 -0
- package/dist/{vega-component-BGTsperM.js → vega-component-B2QrGnW8.js} +6 -6
- package/package.json +5 -5
- package/src/__mocks__/requests.ts +1 -0
- package/src/__tests__/mount.test.ts +128 -0
- package/src/components/app-config/__tests__/get-dirty-values.test.ts +1 -1
- package/src/components/app-config/ai-config.tsx +328 -28
- package/src/components/app-config/user-config-form.tsx +10 -3
- package/src/components/chat/acp/agent-panel.tsx +56 -43
- package/src/components/chat/chat-utils.ts +0 -19
- package/src/components/data-table/column-header.tsx +1 -1
- package/src/components/editor/KernelStartupErrorModal.tsx +101 -0
- package/src/components/editor/actions/name-cell-input.tsx +10 -4
- package/src/components/editor/ai/completion-handlers.tsx +1 -1
- package/src/components/editor/alerts/connecting-alert.tsx +33 -6
- 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/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/ai/ids/ids.ts +12 -4
- package/src/core/cells/cells.ts +2 -0
- 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/config/__tests__/config-schema.test.ts +36 -0
- package/src/core/config/config-schema.ts +1 -0
- package/src/core/errors/state.ts +7 -1
- package/src/core/export/__tests__/hooks.test.ts +504 -0
- package/src/core/export/hooks.ts +93 -4
- package/src/core/islands/bridge.ts +1 -0
- 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/__tests__/requests-network.test.ts +0 -18
- package/src/core/network/requests-lazy.ts +3 -2
- package/src/core/network/requests-network.ts +10 -7
- package/src/core/network/requests-static.ts +1 -0
- package/src/core/network/requests-toasting.tsx +1 -0
- package/src/core/network/types.ts +2 -0
- package/src/core/wasm/bridge.ts +1 -0
- package/src/core/websocket/types.ts +1 -0
- package/src/core/websocket/useMarimoKernelConnection.tsx +18 -1
- package/src/css/globals.css +2 -0
- package/src/hooks/__tests__/useInterval.test.tsx +104 -0
- package/src/hooks/useInterval.ts +32 -6
- package/src/mount.tsx +6 -0
- package/src/plugins/impl/chat/ChatPlugin.tsx +2 -4
- package/src/plugins/impl/chat/chat-ui.tsx +62 -191
- package/src/plugins/impl/chat/types.ts +5 -12
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +3 -1
- package/src/utils/events.ts +1 -0
- package/dist/assets/__vite-browser-external-CpAWmIPM.js +0 -1
|
@@ -593,7 +593,7 @@ const PopoverFilterByValues = <TData, TValue>({
|
|
|
593
593
|
<>
|
|
594
594
|
<Command className="text-sm outline-hidden" shouldFilter={false}>
|
|
595
595
|
<CommandInput
|
|
596
|
-
placeholder=
|
|
596
|
+
placeholder={`Search among the top ${data.length} values`}
|
|
597
597
|
autoFocus={true}
|
|
598
598
|
onValueChange={(value) => setQuery(value.trim())}
|
|
599
599
|
/>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { useAtom } from "jotai";
|
|
4
|
+
import { CopyIcon, HomeIcon, XCircleIcon } from "lucide-react";
|
|
5
|
+
import { kernelStartupErrorAtom } from "@/core/errors/state";
|
|
6
|
+
import {
|
|
7
|
+
AlertDialog,
|
|
8
|
+
AlertDialogAction,
|
|
9
|
+
AlertDialogContent,
|
|
10
|
+
AlertDialogDescription,
|
|
11
|
+
AlertDialogFooter,
|
|
12
|
+
AlertDialogHeader,
|
|
13
|
+
AlertDialogTitle,
|
|
14
|
+
} from "../ui/alert-dialog";
|
|
15
|
+
import { Button } from "../ui/button";
|
|
16
|
+
import { toast } from "../ui/use-toast";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Modal that displays kernel startup errors.
|
|
20
|
+
* Shows when the kernel fails to start in sandbox mode,
|
|
21
|
+
* displaying the stderr output so users can diagnose the issue.
|
|
22
|
+
*/
|
|
23
|
+
export const KernelStartupErrorModal: React.FC = () => {
|
|
24
|
+
const [error, setError] = useAtom(kernelStartupErrorAtom);
|
|
25
|
+
|
|
26
|
+
if (error === null) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const handleCopy = async () => {
|
|
31
|
+
try {
|
|
32
|
+
await navigator.clipboard.writeText(error);
|
|
33
|
+
toast({
|
|
34
|
+
title: "Copied to clipboard",
|
|
35
|
+
description: "Error details have been copied to your clipboard.",
|
|
36
|
+
});
|
|
37
|
+
} catch {
|
|
38
|
+
toast({
|
|
39
|
+
title: "Failed to copy",
|
|
40
|
+
description: "Could not copy to clipboard.",
|
|
41
|
+
variant: "danger",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleClose = () => {
|
|
47
|
+
setError(null);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const handleReturnHome = () => {
|
|
51
|
+
const withoutSearch = document.baseURI.split("?")[0];
|
|
52
|
+
window.open(withoutSearch, "_self");
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<AlertDialog open={true} onOpenChange={(open) => !open && handleClose()}>
|
|
57
|
+
<AlertDialogContent className="max-w-2xl">
|
|
58
|
+
<AlertDialogHeader>
|
|
59
|
+
<AlertDialogTitle className="flex items-center gap-2 text-destructive">
|
|
60
|
+
<XCircleIcon className="h-5 w-5" />
|
|
61
|
+
Kernel Startup Failed
|
|
62
|
+
</AlertDialogTitle>
|
|
63
|
+
<AlertDialogDescription>
|
|
64
|
+
The kernel failed to start. This usually happens when the package
|
|
65
|
+
manager can't install your notebook's dependencies.
|
|
66
|
+
</AlertDialogDescription>
|
|
67
|
+
</AlertDialogHeader>
|
|
68
|
+
<div className="my-4 overflow-hidden">
|
|
69
|
+
<div className="flex items-center justify-between mb-2">
|
|
70
|
+
<span className="text-sm font-medium text-muted-foreground">
|
|
71
|
+
Error Details
|
|
72
|
+
</span>
|
|
73
|
+
<Button
|
|
74
|
+
variant="outline"
|
|
75
|
+
size="xs"
|
|
76
|
+
onClick={handleCopy}
|
|
77
|
+
className="flex items-center gap-1"
|
|
78
|
+
>
|
|
79
|
+
<CopyIcon className="h-3 w-3" />
|
|
80
|
+
Copy
|
|
81
|
+
</Button>
|
|
82
|
+
</div>
|
|
83
|
+
<pre className="bg-muted p-4 rounded-md text-sm font-mono overflow-auto max-h-80">
|
|
84
|
+
{error}
|
|
85
|
+
</pre>
|
|
86
|
+
</div>
|
|
87
|
+
<AlertDialogFooter>
|
|
88
|
+
<Button
|
|
89
|
+
variant="outline"
|
|
90
|
+
onClick={handleReturnHome}
|
|
91
|
+
className="flex items-center gap-2"
|
|
92
|
+
>
|
|
93
|
+
<HomeIcon className="h-4 w-4" />
|
|
94
|
+
Return to Home
|
|
95
|
+
</Button>
|
|
96
|
+
<AlertDialogAction onClick={handleClose}>Dismiss</AlertDialogAction>
|
|
97
|
+
</AlertDialogFooter>
|
|
98
|
+
</AlertDialogContent>
|
|
99
|
+
</AlertDialog>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
@@ -93,11 +93,17 @@ export const NameCellContentEditable: React.FC<{
|
|
|
93
93
|
onChange={inputProps.onChange}
|
|
94
94
|
onBlur={inputProps.onBlur}
|
|
95
95
|
onFocus={inputProps.onFocus}
|
|
96
|
-
onKeyDown={
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
onKeyDown={(e) => {
|
|
97
|
+
// Prevent all key presses from triggering hotkeys
|
|
98
|
+
e.stopPropagation();
|
|
99
|
+
|
|
100
|
+
// On Enter, blur the input to commit the change
|
|
101
|
+
if (e.key === "Enter") {
|
|
102
|
+
if (e.target instanceof HTMLElement) {
|
|
103
|
+
e.target.blur();
|
|
104
|
+
}
|
|
99
105
|
}
|
|
100
|
-
}
|
|
106
|
+
}}
|
|
101
107
|
>
|
|
102
108
|
{value}
|
|
103
109
|
</span>
|
|
@@ -124,7 +124,7 @@ export const AcceptCompletionButton: React.FC<{
|
|
|
124
124
|
size={size}
|
|
125
125
|
disabled={isLoading}
|
|
126
126
|
onClick={handleAcceptAndRun}
|
|
127
|
-
className={`${baseClasses} rounded-l-none px-1.5 ${borderless && "border-0 border-l
|
|
127
|
+
className={`${baseClasses} rounded-l-none px-1.5 ${borderless && "border-0 border-l"} ${playButtonStyles}`}
|
|
128
128
|
>
|
|
129
129
|
<PlayIcon className="h-2.5 w-2.5" />
|
|
130
130
|
</Button>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useAtomValue } from "jotai";
|
|
4
4
|
import { LoadingEllipsis } from "@/components/icons/loading-ellipsis";
|
|
5
|
+
import { Spinner } from "@/components/icons/spinner";
|
|
5
6
|
import { Button } from "@/components/ui/button";
|
|
6
7
|
import { DelayMount } from "@/components/utils/delay-mount";
|
|
7
8
|
import {
|
|
@@ -10,24 +11,50 @@ import {
|
|
|
10
11
|
isNotStartedAtom,
|
|
11
12
|
} from "@/core/network/connection";
|
|
12
13
|
import { useConnectToRuntime } from "@/core/runtime/config";
|
|
14
|
+
import { Banner } from "@/plugins/impl/common/error-banner";
|
|
13
15
|
import { Tooltip } from "../../ui/tooltip";
|
|
14
16
|
import { FloatingAlert } from "./floating-alert";
|
|
15
17
|
|
|
16
18
|
const SHORT_DELAY_MS = 1000; // 1 second
|
|
19
|
+
const LONG_DELAY_MS = 5000; // 5 seconds
|
|
17
20
|
|
|
18
21
|
export const ConnectingAlert: React.FC = () => {
|
|
19
22
|
const isConnecting = useAtomValue(isConnectingAtom);
|
|
20
23
|
const isClosed = useAtomValue(isClosedAtom);
|
|
21
24
|
|
|
22
25
|
if (isConnecting) {
|
|
26
|
+
const subtleNotification = (
|
|
27
|
+
<Tooltip content="Connecting to a marimo runtime">
|
|
28
|
+
<div className="flex items-center">
|
|
29
|
+
<LoadingEllipsis size={5} className="text-yellow-500" />
|
|
30
|
+
</div>
|
|
31
|
+
</Tooltip>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const longNotification = (
|
|
35
|
+
<Banner
|
|
36
|
+
kind="info"
|
|
37
|
+
className="flex flex-col rounded py-2 px-4 animate-in slide-in-from-top w-fit"
|
|
38
|
+
>
|
|
39
|
+
<div className="flex flex-col gap-4 justify-between items-start text-muted-foreground text-base">
|
|
40
|
+
<div className="flex items-center gap-2">
|
|
41
|
+
<Spinner className="h-4 w-4" />
|
|
42
|
+
<p>Connecting to a marimo runtime ...</p>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</Banner>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// This waits for 1 second to show the subtle notification, then shows the long notification after 5 seconds.
|
|
23
49
|
return (
|
|
24
50
|
<DelayMount milliseconds={SHORT_DELAY_MS}>
|
|
25
|
-
<div className="
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
51
|
+
<div className="m-0 flex items-center min-h-[28px] fixed top-5 left-1/2 transform -translate-x-1/2 z-200">
|
|
52
|
+
<DelayMount
|
|
53
|
+
milliseconds={LONG_DELAY_MS}
|
|
54
|
+
fallback={subtleNotification}
|
|
55
|
+
>
|
|
56
|
+
{longNotification}
|
|
57
|
+
</DelayMount>
|
|
31
58
|
</div>
|
|
32
59
|
</DelayMount>
|
|
33
60
|
);
|
|
@@ -194,10 +194,8 @@ export function isPanelHidden(
|
|
|
194
194
|
if (panel.hidden) {
|
|
195
195
|
return true;
|
|
196
196
|
}
|
|
197
|
-
if (panel.requiredCapability) {
|
|
198
|
-
|
|
199
|
-
return true;
|
|
200
|
-
}
|
|
197
|
+
if (panel.requiredCapability && !capabilities[panel.requiredCapability]) {
|
|
198
|
+
return true;
|
|
201
199
|
}
|
|
202
200
|
return false;
|
|
203
201
|
}
|
|
@@ -20,7 +20,7 @@ import { XIcon } from "lucide-react";
|
|
|
20
20
|
import { Button } from "@/components/ui/button";
|
|
21
21
|
import { ReorderableList } from "@/components/ui/reorderable-list";
|
|
22
22
|
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
23
|
-
import {
|
|
23
|
+
import { LazyActivity } from "@/components/utils/lazy-mount";
|
|
24
24
|
import { cellErrorCount } from "@/core/cells/cells";
|
|
25
25
|
import { capabilitiesAtom } from "@/core/config/capabilities";
|
|
26
26
|
import { getFeatureFlag } from "@/core/config/feature-flag";
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
PANEL_MAP,
|
|
35
35
|
PANELS,
|
|
36
36
|
type PanelDescriptor,
|
|
37
|
+
type PanelType,
|
|
37
38
|
} from "../types";
|
|
38
39
|
import { BackendConnectionStatus } from "./footer-items/backend-status";
|
|
39
40
|
import { PanelsWrapper } from "./panels";
|
|
@@ -253,6 +254,29 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
253
254
|
return <LazyChatPanel />;
|
|
254
255
|
};
|
|
255
256
|
|
|
257
|
+
const SIDEBAR_PANELS: Record<PanelType, React.ReactNode> = {
|
|
258
|
+
files: <LazyFileExplorerPanel />,
|
|
259
|
+
variables: <LazySessionPanel />,
|
|
260
|
+
dependencies: <LazyDependencyGraphPanel />,
|
|
261
|
+
packages: <LazyPackagesPanel />,
|
|
262
|
+
outline: <LazyOutlinePanel />,
|
|
263
|
+
documentation: <LazyDocumentationPanel />,
|
|
264
|
+
snippets: <LazySnippetsPanel />,
|
|
265
|
+
ai: renderAiPanel(),
|
|
266
|
+
errors: <LazyErrorsPanel />,
|
|
267
|
+
scratchpad: <LazyScratchpadPanel />,
|
|
268
|
+
tracing: <LazyTracingPanel />,
|
|
269
|
+
secrets: <LazySecretsPanel />,
|
|
270
|
+
logs: <LazyLogsPanel />,
|
|
271
|
+
terminal: (
|
|
272
|
+
<LazyTerminal
|
|
273
|
+
visible={isSidebarOpen && selectedPanel === "terminal"}
|
|
274
|
+
onClose={() => setIsSidebarOpen(false)}
|
|
275
|
+
/>
|
|
276
|
+
),
|
|
277
|
+
cache: <LazyCachePanel />,
|
|
278
|
+
};
|
|
279
|
+
|
|
256
280
|
const helpPaneBody = (
|
|
257
281
|
<ErrorBoundary>
|
|
258
282
|
<PanelSectionProvider value="sidebar">
|
|
@@ -328,26 +352,14 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
328
352
|
</div>
|
|
329
353
|
<Suspense>
|
|
330
354
|
<TooltipProvider>
|
|
331
|
-
{
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
{selectedPanel === "errors" && <LazyErrorsPanel />}
|
|
340
|
-
{selectedPanel === "scratchpad" && <LazyScratchpadPanel />}
|
|
341
|
-
{selectedPanel === "tracing" && <LazyTracingPanel />}
|
|
342
|
-
{selectedPanel === "secrets" && <LazySecretsPanel />}
|
|
343
|
-
{selectedPanel === "logs" && <LazyLogsPanel />}
|
|
344
|
-
{selectedPanel === "terminal" && (
|
|
345
|
-
<LazyTerminal
|
|
346
|
-
visible={isSidebarOpen}
|
|
347
|
-
onClose={() => setIsSidebarOpen(false)}
|
|
348
|
-
/>
|
|
349
|
-
)}
|
|
350
|
-
{selectedPanel === "cache" && <LazyCachePanel />}
|
|
355
|
+
{Object.entries(SIDEBAR_PANELS).map(([key, Panel]) => (
|
|
356
|
+
<LazyActivity
|
|
357
|
+
key={key}
|
|
358
|
+
mode={selectedPanel === key ? "visible" : "hidden"}
|
|
359
|
+
>
|
|
360
|
+
{Panel}
|
|
361
|
+
</LazyActivity>
|
|
362
|
+
))}
|
|
351
363
|
</TooltipProvider>
|
|
352
364
|
</Suspense>
|
|
353
365
|
</div>
|
|
@@ -388,6 +400,18 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
388
400
|
</Panel>
|
|
389
401
|
);
|
|
390
402
|
|
|
403
|
+
const DEVELOPER_PANELS: Record<PanelType, React.ReactNode> = {
|
|
404
|
+
...SIDEBAR_PANELS,
|
|
405
|
+
terminal: (
|
|
406
|
+
<LazyTerminal
|
|
407
|
+
visible={
|
|
408
|
+
isDeveloperPanelOpen && selectedDeveloperPanelTab === "terminal"
|
|
409
|
+
}
|
|
410
|
+
onClose={() => setIsDeveloperPanelOpen(false)}
|
|
411
|
+
/>
|
|
412
|
+
),
|
|
413
|
+
};
|
|
414
|
+
|
|
391
415
|
const bottomPanel = (
|
|
392
416
|
<Panel
|
|
393
417
|
ref={developerPanelRef}
|
|
@@ -475,43 +499,16 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
475
499
|
<Suspense fallback={<div />}>
|
|
476
500
|
<PanelSectionProvider value="developer-panel">
|
|
477
501
|
<div className="flex-1 overflow-hidden">
|
|
478
|
-
{
|
|
479
|
-
<
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
<LazyPackagesPanel />
|
|
489
|
-
)}
|
|
490
|
-
{selectedDeveloperPanelTab === "outline" && <LazyOutlinePanel />}
|
|
491
|
-
{selectedDeveloperPanelTab === "documentation" && (
|
|
492
|
-
<LazyDocumentationPanel />
|
|
493
|
-
)}
|
|
494
|
-
{selectedDeveloperPanelTab === "snippets" && (
|
|
495
|
-
<LazySnippetsPanel />
|
|
496
|
-
)}
|
|
497
|
-
{selectedDeveloperPanelTab === "ai" && renderAiPanel()}
|
|
498
|
-
{selectedDeveloperPanelTab === "errors" && <LazyErrorsPanel />}
|
|
499
|
-
{selectedDeveloperPanelTab === "scratchpad" && (
|
|
500
|
-
<LazyScratchpadPanel />
|
|
501
|
-
)}
|
|
502
|
-
{selectedDeveloperPanelTab === "tracing" && <LazyTracingPanel />}
|
|
503
|
-
{selectedDeveloperPanelTab === "secrets" && <LazySecretsPanel />}
|
|
504
|
-
{selectedDeveloperPanelTab === "logs" && <LazyLogsPanel />}
|
|
505
|
-
{/* LazyMount needed for Terminal to avoid spurious connection */}
|
|
506
|
-
{selectedDeveloperPanelTab === "terminal" && (
|
|
507
|
-
<LazyMount isOpen={isDeveloperPanelOpen}>
|
|
508
|
-
<LazyTerminal
|
|
509
|
-
visible={isDeveloperPanelOpen}
|
|
510
|
-
onClose={() => setIsDeveloperPanelOpen(false)}
|
|
511
|
-
/>
|
|
512
|
-
</LazyMount>
|
|
513
|
-
)}
|
|
514
|
-
{selectedDeveloperPanelTab === "cache" && <LazyCachePanel />}
|
|
502
|
+
{Object.entries(DEVELOPER_PANELS).map(([key, Panel]) => (
|
|
503
|
+
<LazyActivity
|
|
504
|
+
key={key}
|
|
505
|
+
mode={
|
|
506
|
+
selectedDeveloperPanelTab === key ? "visible" : "hidden"
|
|
507
|
+
}
|
|
508
|
+
>
|
|
509
|
+
{Panel}
|
|
510
|
+
</LazyActivity>
|
|
511
|
+
))}
|
|
515
512
|
</div>
|
|
516
513
|
</PanelSectionProvider>
|
|
517
514
|
</Suspense>
|
|
@@ -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
|
);
|