@marimo-team/islands 0.25.2-dev66 → 0.25.2-dev89
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-BHvUXPtK.js → ErrorBoundary-DhBCglR0.js} +1 -1
- package/dist/{cells-DzqPprAQ.js → cells-DZi0ioak.js} +9 -2
- package/dist/{chat-ui-Da2o4rps.js → chat-ui-CwOWzoSO.js} +4 -4
- package/dist/{code-visibility-a6v4Kwtn.js → code-visibility-DVtowxt1.js} +2 -2
- package/dist/{common-Lbz4UoEr.js → common-CeQoafB5.js} +3 -3
- package/dist/{data-grid-overlay-editor-C7u6VQ9U.js → data-grid-overlay-editor-Df0vkYi7.js} +1 -1
- package/dist/{error-entries-CdgPvJVz.js → error-entries-BovkFYNy.js} +1 -1
- package/dist/{feedback-button-C_dzhSZo.js → feedback-button-mqHtzKAF.js} +4 -4
- package/dist/{glide-data-editor-CQKpxgZb.js → glide-data-editor-BtaerHsr.js} +3 -3
- package/dist/{globals-B0wv8u9V.js → globals-rsMlVnSz.js} +1 -1
- package/dist/{html-to-image-C-XXpUFD.js → html-to-image-Cn1_16-x.js} +1 -1
- package/dist/main.js +11 -11
- package/dist/{number-overlay-editor-BfWfXUbU.js → number-overlay-editor-Ci2JathI.js} +1 -1
- package/dist/{process-output-CdDN3Pdp.js → process-output-CUG57KRp.js} +2 -2
- package/dist/{reveal-component-D2i9ey2a.js → reveal-component-BFuZ3Pb9.js} +3 -3
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/__tests__/mount.test.ts +6 -6
- package/src/components/editor/actions/useRestartKernel.tsx +2 -2
- package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +224 -17
- package/src/components/editor/alerts/connection-details.tsx +61 -0
- package/src/components/editor/alerts/connection-notice.tsx +46 -53
- package/src/components/editor/alerts/startup-progress.tsx +73 -129
- package/src/components/editor/app-container.tsx +2 -2
- package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +2 -2
- package/src/components/editor/cell/CreateCellButton.tsx +2 -2
- package/src/components/editor/cell/DeleteButton.tsx +2 -2
- package/src/components/editor/cell/RunButton.tsx +3 -3
- package/src/components/editor/cell/StopButton.tsx +2 -2
- package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +4 -4
- package/src/components/editor/chrome/components/feedback-button.tsx +3 -3
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +8 -8
- package/src/components/editor/chrome/panels/__tests__/{sandbox-details.test.tsx → runtime-details.test.tsx} +94 -22
- package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +4 -4
- package/src/components/editor/chrome/panels/packages-panel.tsx +8 -29
- package/src/components/editor/chrome/panels/{sandbox-details-state.ts → runtime-details-state.ts} +1 -1
- package/src/components/editor/chrome/panels/{sandbox-panel.tsx → runtime-panel.tsx} +38 -66
- package/src/components/editor/chrome/panels/runtime-status-toggle.tsx +56 -0
- package/src/components/editor/chrome/panels/sandbox-controller.tsx +2 -2
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +3 -3
- package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +2 -2
- package/src/components/editor/controls/Controls.tsx +3 -3
- package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +2 -2
- package/src/components/editor/header/__tests__/status.test.tsx +4 -4
- package/src/components/editor/header/app-header.tsx +2 -2
- package/src/components/editor/header/status.tsx +3 -3
- package/src/components/ui/progress-stages.tsx +114 -0
- package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +106 -5
- package/src/core/codemirror/lsp/notebook-lsp.ts +16 -2
- package/src/core/codemirror/readonly/__tests__/extension.test.ts +6 -6
- package/src/core/codemirror/readonly/extension.ts +2 -2
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +2 -2
- package/src/core/edit-app.tsx +5 -1
- package/src/core/export/hooks.ts +2 -2
- package/src/core/network/__tests__/connection.test.ts +3 -3
- package/src/core/network/connection-notice.ts +5 -5
- package/src/core/network/connection.ts +9 -9
- package/src/core/network/requests-lazy.ts +2 -2
- package/src/core/packages/__tests__/useSandboxController.test.tsx +2 -2
- package/src/core/packages/useSandboxController.ts +6 -6
- package/src/core/runtime/__tests__/adapter.test.ts +6 -6
- package/src/core/runtime/adapter.ts +7 -7
- package/src/core/runtime/config.ts +2 -2
- package/src/core/saving/filename.ts +2 -2
- package/src/core/saving/save-component.tsx +5 -5
- package/src/core/saving/useAutoSave.ts +2 -2
- package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +30 -25
- package/src/core/websocket/__tests__/useMarimoKernelConnection.test.ts +5 -5
- package/src/core/websocket/connection-utils.ts +21 -21
- package/src/core/websocket/types.ts +8 -9
- package/src/core/websocket/useMarimoKernelConnection.tsx +21 -21
- package/src/mount.tsx +2 -2
- package/src/plugins/core/__test__/registerReactComponent.test.ts +55 -0
- package/src/plugins/core/registerReactComponent.tsx +3 -1
- package/src/stories/cell.stories.tsx +2 -2
- package/src/stories/layout/vertical/one-column.stories.tsx +5 -5
- package/src/stories/progress-stages.stories.tsx +62 -0
- package/src/stories/runtime-existing.stories.tsx +44 -0
- package/src/stories/runtime-maintenance.stories.tsx +40 -0
- package/src/stories/runtime-pixi.stories.tsx +28 -0
- package/src/stories/{sandbox.stories.tsx → runtime-story.tsx} +191 -152
- package/src/stories/runtime-uv.stories.tsx +56 -0
- package/src/components/editor/chrome/panels/sandbox-toggle.tsx +0 -52
|
@@ -1,41 +1,44 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import { useAtomValue } from "jotai";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
ProgressStages,
|
|
5
|
+
ProgressStatusIcon,
|
|
6
|
+
type ProgressStage,
|
|
7
|
+
type ProgressState,
|
|
8
|
+
} from "@/components/ui/progress-stages";
|
|
5
9
|
import { preparationAtom } from "@/core/packages/sandbox-state";
|
|
6
10
|
import { startupProgressAtom } from "@/core/network/connection";
|
|
7
11
|
import type { DisplayConnectionNotice } from "@/core/network/useConnectionNotice";
|
|
8
|
-
import {
|
|
9
|
-
import { StartupOutput, type StartupOutputState } from "./startup-output";
|
|
12
|
+
import { StartupOutput } from "./startup-output";
|
|
10
13
|
|
|
11
14
|
const STEPS = [
|
|
12
15
|
{
|
|
13
16
|
phase: "preparing-environment",
|
|
14
17
|
titles: {
|
|
15
|
-
|
|
18
|
+
succeeded: "Environment prepared",
|
|
16
19
|
failed: "Environment setup failed",
|
|
17
|
-
|
|
20
|
+
running: "Preparing environment",
|
|
18
21
|
waiting: "Prepare environment",
|
|
19
22
|
},
|
|
20
23
|
descriptions: {
|
|
21
|
-
|
|
24
|
+
succeeded: "Python and dependencies are available.",
|
|
22
25
|
failed: "Setup could not finish.",
|
|
23
|
-
|
|
26
|
+
running: "Set up Python and dependencies.",
|
|
24
27
|
waiting: "Set up Python and dependencies.",
|
|
25
28
|
},
|
|
26
29
|
},
|
|
27
30
|
{
|
|
28
31
|
phase: "starting-kernel",
|
|
29
32
|
titles: {
|
|
30
|
-
|
|
33
|
+
succeeded: "Kernel started",
|
|
31
34
|
failed: "Kernel failed to start",
|
|
32
|
-
|
|
35
|
+
running: "Starting kernel",
|
|
33
36
|
waiting: "Start kernel",
|
|
34
37
|
},
|
|
35
38
|
descriptions: {
|
|
36
|
-
|
|
39
|
+
succeeded: "The notebook is ready to run.",
|
|
37
40
|
failed: "The kernel could not connect.",
|
|
38
|
-
|
|
41
|
+
running: "Connecting to this notebook.",
|
|
39
42
|
waiting: "After the environment is ready.",
|
|
40
43
|
},
|
|
41
44
|
},
|
|
@@ -46,31 +49,13 @@ interface StartupProgressProps {
|
|
|
46
49
|
surface: "notebook" | "sidebar";
|
|
47
50
|
}
|
|
48
51
|
|
|
49
|
-
function
|
|
50
|
-
phase,
|
|
51
|
-
state,
|
|
52
|
-
}: {
|
|
53
|
-
phase: (typeof STEPS)[number]["phase"];
|
|
54
|
-
state: StartupOutputState;
|
|
55
|
-
}) {
|
|
56
|
-
const preparation = useAtomValue(preparationAtom);
|
|
57
|
-
const progress = useAtomValue(startupProgressAtom);
|
|
58
|
-
const preparing = phase === "preparing-environment";
|
|
59
|
-
const logs = preparing
|
|
60
|
-
? (preparation?.logs.environment ?? "")
|
|
61
|
-
: progress?.phase === phase
|
|
62
|
-
? progress.logs
|
|
63
|
-
: "";
|
|
64
|
-
|
|
52
|
+
export function hasStartupStages(notice: DisplayConnectionNotice): boolean {
|
|
65
53
|
return (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
preparing ? "environment preparation output" : "kernel startup output"
|
|
72
|
-
}
|
|
73
|
-
/>
|
|
54
|
+
notice.kind === "startup" &&
|
|
55
|
+
(!notice.sandbox ||
|
|
56
|
+
notice.ready ||
|
|
57
|
+
notice.phase === "preparing-environment" ||
|
|
58
|
+
notice.phase === "starting-kernel")
|
|
74
59
|
);
|
|
75
60
|
}
|
|
76
61
|
|
|
@@ -85,9 +70,13 @@ function StartupSummary({ notice }: { notice: DisplayConnectionNotice }) {
|
|
|
85
70
|
</h2>
|
|
86
71
|
<p className="text-muted-foreground mt-3 text-sm leading-6">
|
|
87
72
|
{notice.ready
|
|
88
|
-
?
|
|
73
|
+
? notice.sandbox
|
|
74
|
+
? "Your environment and kernel are ready."
|
|
75
|
+
: "Your kernel is ready."
|
|
89
76
|
: notice.pending
|
|
90
|
-
?
|
|
77
|
+
? notice.sandbox
|
|
78
|
+
? "Preparing Python and dependencies for this notebook."
|
|
79
|
+
: "Connecting to this notebook’s Python kernel."
|
|
91
80
|
: "Review the setup details below to continue."}
|
|
92
81
|
</p>
|
|
93
82
|
</header>
|
|
@@ -99,106 +88,61 @@ export function ConnectionStatusIcon({
|
|
|
99
88
|
}: {
|
|
100
89
|
notice: DisplayConnectionNotice;
|
|
101
90
|
}) {
|
|
102
|
-
if (notice.ready) {
|
|
103
|
-
return (
|
|
104
|
-
<CheckIcon
|
|
105
|
-
className="size-4 shrink-0 text-(--grass-11)"
|
|
106
|
-
aria-hidden={true}
|
|
107
|
-
/>
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
if (notice.pending) {
|
|
111
|
-
return (
|
|
112
|
-
<Spinner
|
|
113
|
-
className="size-4 shrink-0 motion-reduce:animate-none"
|
|
114
|
-
aria-hidden={true}
|
|
115
|
-
/>
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
91
|
return (
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
aria-hidden={true}
|
|
92
|
+
<ProgressStatusIcon
|
|
93
|
+
state={notice.ready ? "succeeded" : notice.pending ? "running" : "failed"}
|
|
122
94
|
/>
|
|
123
95
|
);
|
|
124
96
|
}
|
|
125
97
|
|
|
126
98
|
export function StartupProgress({ notice, surface }: StartupProgressProps) {
|
|
99
|
+
const preparation = useAtomValue(preparationAtom);
|
|
100
|
+
const progress = useAtomValue(startupProgressAtom);
|
|
101
|
+
const activePhase = notice.sandbox ? notice.phase : "starting-kernel";
|
|
102
|
+
const stages: ProgressStage[] = STEPS.filter(
|
|
103
|
+
(step) => notice.sandbox || step.phase === "starting-kernel",
|
|
104
|
+
).map(({ phase, titles, descriptions }) => {
|
|
105
|
+
const preparing = phase === "preparing-environment";
|
|
106
|
+
const state: ProgressState =
|
|
107
|
+
notice.ready || (preparing && activePhase === "starting-kernel")
|
|
108
|
+
? "succeeded"
|
|
109
|
+
: activePhase === phase
|
|
110
|
+
? notice.pending
|
|
111
|
+
? "running"
|
|
112
|
+
: "failed"
|
|
113
|
+
: "waiting";
|
|
114
|
+
const logs = preparing
|
|
115
|
+
? (preparation?.logs.environment ?? "")
|
|
116
|
+
: progress?.phase === phase
|
|
117
|
+
? progress.logs
|
|
118
|
+
: "";
|
|
119
|
+
return {
|
|
120
|
+
id: phase,
|
|
121
|
+
state,
|
|
122
|
+
title: titles[state],
|
|
123
|
+
description: descriptions[state],
|
|
124
|
+
details: surface === "sidebar" && (
|
|
125
|
+
<StartupOutput
|
|
126
|
+
key={preparation?.operation_id}
|
|
127
|
+
logs={logs}
|
|
128
|
+
state={state === "waiting" ? "succeeded" : state}
|
|
129
|
+
label={
|
|
130
|
+
preparing
|
|
131
|
+
? "environment preparation output"
|
|
132
|
+
: "kernel startup output"
|
|
133
|
+
}
|
|
134
|
+
/>
|
|
135
|
+
),
|
|
136
|
+
};
|
|
137
|
+
});
|
|
127
138
|
return (
|
|
128
139
|
<>
|
|
129
140
|
{surface === "notebook" && <StartupSummary notice={notice} />}
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const complete =
|
|
136
|
-
notice.ready || (index === 0 && notice.phase === "starting-kernel");
|
|
137
|
-
const active = !notice.ready && notice.phase === phase;
|
|
138
|
-
const failed = active && !notice.pending;
|
|
139
|
-
const state = complete
|
|
140
|
-
? "complete"
|
|
141
|
-
: failed
|
|
142
|
-
? "failed"
|
|
143
|
-
: active
|
|
144
|
-
? "pending"
|
|
145
|
-
: "waiting";
|
|
146
|
-
return (
|
|
147
|
-
<li
|
|
148
|
-
key={phase}
|
|
149
|
-
aria-current={active ? "step" : undefined}
|
|
150
|
-
className="relative flex items-start gap-3"
|
|
151
|
-
>
|
|
152
|
-
{index === 0 && (
|
|
153
|
-
<span
|
|
154
|
-
aria-hidden={true}
|
|
155
|
-
className="absolute left-2 top-6 -bottom-4 border-l border-border"
|
|
156
|
-
/>
|
|
157
|
-
)}
|
|
158
|
-
<span
|
|
159
|
-
className={cn(
|
|
160
|
-
"mt-0.5",
|
|
161
|
-
complete ? "text-(--grass-11)" : "text-muted-foreground",
|
|
162
|
-
)}
|
|
163
|
-
>
|
|
164
|
-
{complete ? (
|
|
165
|
-
<CheckIcon className="size-4" aria-hidden={true} />
|
|
166
|
-
) : active ? (
|
|
167
|
-
<ConnectionStatusIcon notice={notice} />
|
|
168
|
-
) : (
|
|
169
|
-
<CircleIcon
|
|
170
|
-
className="size-4 text-muted-foreground/50"
|
|
171
|
-
aria-hidden={true}
|
|
172
|
-
/>
|
|
173
|
-
)}
|
|
174
|
-
</span>
|
|
175
|
-
<div className="min-w-0 flex-1">
|
|
176
|
-
<div
|
|
177
|
-
className={cn(
|
|
178
|
-
"text-sm",
|
|
179
|
-
failed
|
|
180
|
-
? "text-(--red-11)"
|
|
181
|
-
: complete || active
|
|
182
|
-
? "text-foreground"
|
|
183
|
-
: "text-muted-foreground",
|
|
184
|
-
)}
|
|
185
|
-
>
|
|
186
|
-
{titles[state]}
|
|
187
|
-
</div>
|
|
188
|
-
<p className="mt-1 text-xs text-muted-foreground">
|
|
189
|
-
{descriptions[state]}
|
|
190
|
-
</p>
|
|
191
|
-
{surface === "sidebar" && (
|
|
192
|
-
<StartupStepOutput
|
|
193
|
-
phase={phase}
|
|
194
|
-
state={failed ? "failed" : active ? "running" : "succeeded"}
|
|
195
|
-
/>
|
|
196
|
-
)}
|
|
197
|
-
</div>
|
|
198
|
-
</li>
|
|
199
|
-
);
|
|
200
|
-
})}
|
|
201
|
-
</ol>
|
|
141
|
+
<ProgressStages
|
|
142
|
+
stages={stages}
|
|
143
|
+
label="Notebook startup stages"
|
|
144
|
+
className={surface === "notebook" ? "mt-8" : undefined}
|
|
145
|
+
/>
|
|
202
146
|
</>
|
|
203
147
|
);
|
|
204
148
|
}
|
|
@@ -7,7 +7,7 @@ import { PyodideLoader } from "@/core/wasm/PyodideLoader";
|
|
|
7
7
|
import {
|
|
8
8
|
type ConnectionStatus,
|
|
9
9
|
WebSocketClosedReason,
|
|
10
|
-
|
|
10
|
+
ConnectionState,
|
|
11
11
|
} from "@/core/websocket/types";
|
|
12
12
|
import { cn } from "@/utils/cn";
|
|
13
13
|
import { DynamicFavicon } from "./dynamic-favicon";
|
|
@@ -47,7 +47,7 @@ export const AppContainer: React.FC<PropsWithChildren<Props>> = ({
|
|
|
47
47
|
data-connection-state={connectionState}
|
|
48
48
|
className={cn(
|
|
49
49
|
"mathjax_ignore",
|
|
50
|
-
connection.state ===
|
|
50
|
+
connection.state === ConnectionState.CLOSED &&
|
|
51
51
|
connection.code !==
|
|
52
52
|
WebSocketClosedReason.KERNEL_STARTUP_ERROR &&
|
|
53
53
|
"disconnected",
|
|
@@ -14,7 +14,7 @@ import { requestClientAtom } from "@/core/network/requests";
|
|
|
14
14
|
import type { EnvironmentInfo } from "@/core/network/types";
|
|
15
15
|
import { filenameAtom } from "@/core/saving/file-state";
|
|
16
16
|
import { store } from "@/core/state/jotai";
|
|
17
|
-
import {
|
|
17
|
+
import { ConnectionState } from "@/core/websocket/types";
|
|
18
18
|
import { ErrorBoundary } from "../ErrorBoundary";
|
|
19
19
|
|
|
20
20
|
vi.mock("@/utils/copy", () => ({
|
|
@@ -144,7 +144,7 @@ function resetSharedState() {
|
|
|
144
144
|
store.set(requestClientAtom, null);
|
|
145
145
|
store.set(notebookAtom, initialNotebookState());
|
|
146
146
|
store.set(viewStateAtom, { mode: "edit", cellAnchor: null });
|
|
147
|
-
store.set(connectionAtom, { state:
|
|
147
|
+
store.set(connectionAtom, { state: ConnectionState.OPEN });
|
|
148
148
|
store.set(filenameAtom, "/project/example.py");
|
|
149
149
|
}
|
|
150
150
|
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
getConnectionTooltip,
|
|
18
18
|
isAppInteractionDisabled,
|
|
19
19
|
} from "@/core/websocket/connection-utils";
|
|
20
|
-
import type {
|
|
20
|
+
import type { ConnectionState } from "@/core/websocket/types";
|
|
21
21
|
import { cn } from "@/utils/cn";
|
|
22
22
|
import { Tooltip } from "../../ui/tooltip";
|
|
23
23
|
import { MarkdownIcon, PythonIcon } from "./code/icons";
|
|
@@ -28,7 +28,7 @@ export const CreateCellButton = ({
|
|
|
28
28
|
tooltipContent,
|
|
29
29
|
oneClickShortcut,
|
|
30
30
|
}: {
|
|
31
|
-
connectionState:
|
|
31
|
+
connectionState: ConnectionState;
|
|
32
32
|
tooltipContent: React.ReactNode;
|
|
33
33
|
onClick: ((opts: { code: string; hideCode?: boolean }) => void) | undefined;
|
|
34
34
|
oneClickShortcut: "shift" | "mod";
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getConnectionTooltip,
|
|
7
7
|
isAppInteractionDisabled,
|
|
8
8
|
} from "@/core/websocket/connection-utils";
|
|
9
|
-
import type {
|
|
9
|
+
import type { ConnectionState } from "@/core/websocket/types";
|
|
10
10
|
import { cn } from "@/utils/cn";
|
|
11
11
|
import { Events } from "@/utils/events";
|
|
12
12
|
import { Button } from "../../ui/button";
|
|
@@ -14,7 +14,7 @@ import { Tooltip } from "../../ui/tooltip";
|
|
|
14
14
|
|
|
15
15
|
export const DeleteButton = (props: {
|
|
16
16
|
status: RuntimeState;
|
|
17
|
-
connectionState:
|
|
17
|
+
connectionState: ConnectionState;
|
|
18
18
|
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
19
19
|
}): JSX.Element => {
|
|
20
20
|
const { status, connectionState, onClick } = props;
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getConnectionTooltip,
|
|
7
7
|
isAppInteractionDisabled,
|
|
8
8
|
} from "@/core/websocket/connection-utils";
|
|
9
|
-
import type {
|
|
9
|
+
import type { ConnectionState } from "@/core/websocket/types";
|
|
10
10
|
import { renderShortcut } from "../../shortcuts/renderShortcut";
|
|
11
11
|
import { ToolbarItem } from "./toolbar";
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ function computeColor({
|
|
|
16
16
|
loading,
|
|
17
17
|
inactive,
|
|
18
18
|
}: {
|
|
19
|
-
connectionState:
|
|
19
|
+
connectionState: ConnectionState;
|
|
20
20
|
needsRun: boolean;
|
|
21
21
|
loading: boolean;
|
|
22
22
|
inactive: boolean;
|
|
@@ -37,7 +37,7 @@ export const RunButton = (props: {
|
|
|
37
37
|
edited: boolean;
|
|
38
38
|
status: RuntimeState;
|
|
39
39
|
needsRun: boolean;
|
|
40
|
-
connectionState:
|
|
40
|
+
connectionState: ConnectionState;
|
|
41
41
|
config: CellConfig;
|
|
42
42
|
onClick?: () => void;
|
|
43
43
|
}): JSX.Element => {
|
|
@@ -4,7 +4,7 @@ import type { JSX } from "react";
|
|
|
4
4
|
import { useRequestClient } from "@/core/network/requests";
|
|
5
5
|
import type { RuntimeState } from "@/core/network/types";
|
|
6
6
|
import { isAppInteractionDisabled } from "@/core/websocket/connection-utils";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ConnectionState } from "@/core/websocket/types";
|
|
8
8
|
import { Functions } from "@/utils/functions";
|
|
9
9
|
import { renderShortcut } from "../../shortcuts/renderShortcut";
|
|
10
10
|
import { ToolbarItem } from "./toolbar";
|
|
@@ -12,7 +12,7 @@ import { useShouldShowInterrupt } from "./useShouldShowInterrupt";
|
|
|
12
12
|
|
|
13
13
|
export const StopButton = (props: {
|
|
14
14
|
status: RuntimeState;
|
|
15
|
-
connectionState:
|
|
15
|
+
connectionState: ConnectionState;
|
|
16
16
|
}): JSX.Element => {
|
|
17
17
|
const { connectionState, status } = props;
|
|
18
18
|
const { sendInterrupt } = useRequestClient();
|
|
@@ -14,7 +14,7 @@ import { requestClientAtom } from "@/core/network/requests";
|
|
|
14
14
|
import type { EnvironmentInfo } from "@/core/network/types";
|
|
15
15
|
import { filenameAtom } from "@/core/saving/file-state";
|
|
16
16
|
import { store } from "@/core/state/jotai";
|
|
17
|
-
import {
|
|
17
|
+
import { ConnectionState } from "@/core/websocket/types";
|
|
18
18
|
import * as copyModule from "@/utils/copy";
|
|
19
19
|
import { FeedbackModal } from "../feedback-button";
|
|
20
20
|
|
|
@@ -53,7 +53,7 @@ describe("FeedbackModal issue reporting", () => {
|
|
|
53
53
|
localStorage.clear();
|
|
54
54
|
store.set(requestClientAtom, MockRequestClient.create());
|
|
55
55
|
store.set(viewStateAtom, { mode: "edit", cellAnchor: null });
|
|
56
|
-
store.set(connectionAtom, { state:
|
|
56
|
+
store.set(connectionAtom, { state: ConnectionState.OPEN });
|
|
57
57
|
store.set(filenameAtom, "/project/example.py");
|
|
58
58
|
});
|
|
59
59
|
|
|
@@ -156,7 +156,7 @@ describe("FeedbackModal issue reporting", () => {
|
|
|
156
156
|
});
|
|
157
157
|
|
|
158
158
|
it("disables include code and explains why when disconnected", async () => {
|
|
159
|
-
store.set(connectionAtom, { state:
|
|
159
|
+
store.set(connectionAtom, { state: ConnectionState.CONNECTING });
|
|
160
160
|
store.set(
|
|
161
161
|
requestClientAtom,
|
|
162
162
|
MockRequestClient.create({
|
|
@@ -244,7 +244,7 @@ describe("FeedbackModal issue reporting", () => {
|
|
|
244
244
|
"marimo:issue-report:include-code",
|
|
245
245
|
JSON.stringify(true),
|
|
246
246
|
);
|
|
247
|
-
store.set(connectionAtom, { state:
|
|
247
|
+
store.set(connectionAtom, { state: ConnectionState.CONNECTING });
|
|
248
248
|
store.set(requestClientAtom, null);
|
|
249
249
|
render(<FeedbackModal onClose={vi.fn()} />, { wrapper });
|
|
250
250
|
|
|
@@ -39,7 +39,7 @@ import { connectionAtom } from "@/core/network/connection";
|
|
|
39
39
|
import { requestClientAtom } from "@/core/network/requests";
|
|
40
40
|
import { filenameAtom } from "@/core/saving/file-state";
|
|
41
41
|
import { store } from "@/core/state/jotai";
|
|
42
|
-
import {
|
|
42
|
+
import { ConnectionState } from "@/core/websocket/types";
|
|
43
43
|
import { useAsyncData } from "@/hooks/useAsyncData";
|
|
44
44
|
import { useLocalStorage } from "@/hooks/useLocalStorage";
|
|
45
45
|
import { cn } from "@/utils/cn";
|
|
@@ -78,7 +78,7 @@ function getNotebookSourceUnavailableReason(args: {
|
|
|
78
78
|
hasRequestClient: boolean;
|
|
79
79
|
filename: string | null;
|
|
80
80
|
codeAvailable: boolean;
|
|
81
|
-
connectionState:
|
|
81
|
+
connectionState: ConnectionState;
|
|
82
82
|
}): string | undefined {
|
|
83
83
|
if (!args.hasRequestClient) {
|
|
84
84
|
return "Notebook source is unavailable.";
|
|
@@ -89,7 +89,7 @@ function getNotebookSourceUnavailableReason(args: {
|
|
|
89
89
|
if (!args.codeAvailable) {
|
|
90
90
|
return "Notebook source is hidden in this view.";
|
|
91
91
|
}
|
|
92
|
-
if (args.connectionState !==
|
|
92
|
+
if (args.connectionState !== ConnectionState.OPEN) {
|
|
93
93
|
return "Connect the notebook to include its source.";
|
|
94
94
|
}
|
|
95
95
|
return undefined;
|
|
@@ -22,10 +22,10 @@ import { withPackageInvalidation } from "@/core/packages/package-data";
|
|
|
22
22
|
import { useInstallPackages } from "@/core/packages/useInstallPackage";
|
|
23
23
|
import { sandboxAtom, sandboxSyncAtom } from "@/core/packages/sandbox-state";
|
|
24
24
|
import { store } from "@/core/state/jotai";
|
|
25
|
-
import {
|
|
25
|
+
import { ConnectionState } from "@/core/websocket/types";
|
|
26
26
|
import PackagesPanel from "../packages-panel";
|
|
27
27
|
import { PanelSectionProvider } from "../panel-context";
|
|
28
|
-
import {
|
|
28
|
+
import { RuntimeStatusToggle } from "../runtime-status-toggle";
|
|
29
29
|
|
|
30
30
|
const { openSettings } = vi.hoisted(() => ({
|
|
31
31
|
openSettings: vi.fn(),
|
|
@@ -71,7 +71,7 @@ function renderPanel(
|
|
|
71
71
|
? { backend: context.backend, manifest: "", filename: "notebook.py" }
|
|
72
72
|
: null,
|
|
73
73
|
);
|
|
74
|
-
store.set(connectionAtom, { state:
|
|
74
|
+
store.set(connectionAtom, { state: ConnectionState.OPEN });
|
|
75
75
|
store.set(sandboxSyncAtom, { kind: "succeeded" });
|
|
76
76
|
const getPackageList = vi.fn().mockResolvedValue({ packages: [] });
|
|
77
77
|
const client = MockRequestClient.create({
|
|
@@ -87,7 +87,7 @@ function renderPanel(
|
|
|
87
87
|
<Provider store={store}>
|
|
88
88
|
<TooltipProvider>
|
|
89
89
|
<PanelSectionProvider value="sidebar">
|
|
90
|
-
<
|
|
90
|
+
<RuntimeStatusToggle section="sidebar" />
|
|
91
91
|
<PackagesPanel />
|
|
92
92
|
</PanelSectionProvider>
|
|
93
93
|
</TooltipProvider>
|
|
@@ -186,7 +186,7 @@ it("refreshes an open panel when a package is installed elsewhere, after install
|
|
|
186
186
|
manifest: "",
|
|
187
187
|
filename: "notebook.py",
|
|
188
188
|
});
|
|
189
|
-
store.set(connectionAtom, { state:
|
|
189
|
+
store.set(connectionAtom, { state: ConnectionState.OPEN });
|
|
190
190
|
store.set(sandboxSyncAtom, { kind: "succeeded" });
|
|
191
191
|
store.set(requestClientAtom, withPackageInvalidation(client));
|
|
192
192
|
function InstallElsewhere() {
|
|
@@ -201,7 +201,7 @@ it("refreshes an open panel when a package is installed elsewhere, after install
|
|
|
201
201
|
<Provider store={store}>
|
|
202
202
|
<TooltipProvider>
|
|
203
203
|
<PanelSectionProvider value="sidebar">
|
|
204
|
-
<
|
|
204
|
+
<RuntimeStatusToggle section="sidebar" />
|
|
205
205
|
<PackagesPanel />
|
|
206
206
|
</PanelSectionProvider>
|
|
207
207
|
<InstallElsewhere />
|
|
@@ -221,7 +221,7 @@ it("refreshes an open panel when a package is installed elsewhere, after install
|
|
|
221
221
|
});
|
|
222
222
|
|
|
223
223
|
it("keeps packages and the install draft visible while blocking mutations during sync", async () => {
|
|
224
|
-
store.set(connectionAtom, { state:
|
|
224
|
+
store.set(connectionAtom, { state: ConnectionState.OPEN });
|
|
225
225
|
renderPanel({ kind: "sandbox", backend: "pixi" }, populatedTree);
|
|
226
226
|
await screen.findByRole("treeitem", { name: /polars/ });
|
|
227
227
|
const input = screen.getByPlaceholderText("Add packages to pixi sandbox...");
|
|
@@ -235,7 +235,7 @@ it("keeps packages and the install draft visible while blocking mutations during
|
|
|
235
235
|
expect(
|
|
236
236
|
screen.queryByRole("list", { name: "Notebook startup stages" }),
|
|
237
237
|
).not.toBeInTheDocument();
|
|
238
|
-
const toggle = screen.getByRole("button", { name:
|
|
238
|
+
const toggle = screen.getByRole("button", { name: /^pixi sandbox, / });
|
|
239
239
|
fireEvent.click(toggle);
|
|
240
240
|
expect(toggle).toHaveAttribute("aria-expanded", "false");
|
|
241
241
|
act(() =>
|