@marimo-team/islands 0.24.3-dev81 → 0.24.3-dev83
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-CCi-VkF7.js → ErrorBoundary-Uf_LvjvY.js} +1 -1
- package/dist/{cells-BIfOnGBK.js → cells-DYIkSxs6.js} +4 -0
- package/dist/{chat-ui-LWkjhObe.js → chat-ui-BXj3uYjy.js} +4 -4
- package/dist/{code-visibility-Bsfqbe2z.js → code-visibility-DxgQWu1j.js} +2 -2
- package/dist/{common-BnKC1tWB.js → common-ByAtncLr.js} +3 -3
- package/dist/{data-grid-overlay-editor-CJnlWykO.js → data-grid-overlay-editor-DL_blFyL.js} +1 -1
- package/dist/{error-entries-CR0oClSL.js → error-entries-C0NsUqXl.js} +1 -1
- package/dist/{feedback-button-MWISfIIf.js → feedback-button-AZcBqfoV.js} +4 -4
- package/dist/{glide-data-editor-dcmP8mKS.js → glide-data-editor-BJdZncJk.js} +3 -3
- package/dist/{globals-fCMBgbAD.js → globals-yWarpyN4.js} +1 -1
- package/dist/{html-to-image-_i03yR4q.js → html-to-image-CeYYvQNb.js} +1 -1
- package/dist/main.js +12 -11
- package/dist/{number-overlay-editor-DhNE6pBe.js → number-overlay-editor-BatBVYxr.js} +1 -1
- package/dist/{process-output-D3zQyTAS.js → process-output-BCTjlyuH.js} +2 -2
- package/dist/{reveal-component-Cdcgngkc.js → reveal-component-D02jcpiJ.js} +3 -3
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +186 -0
- package/src/components/editor/alerts/__tests__/startup-progress.test.tsx +185 -0
- package/src/components/editor/alerts/connection-notice.tsx +100 -54
- package/src/components/editor/alerts/startup-output.tsx +173 -0
- package/src/components/editor/alerts/startup-progress.tsx +204 -0
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +53 -4
- package/src/components/editor/chrome/panels/__tests__/sandbox-details.test.tsx +358 -0
- package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +5 -2
- package/src/components/editor/chrome/panels/packages-panel.tsx +32 -21
- package/src/components/editor/chrome/panels/sandbox-details-state.ts +38 -0
- package/src/components/editor/chrome/panels/sandbox-panel.tsx +188 -131
- package/src/components/editor/chrome/panels/sandbox-toggle.tsx +52 -0
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +7 -0
- package/src/components/editor/package-alert.tsx +112 -66
- package/src/core/alerts/__tests__/environment.test.ts +183 -0
- package/src/core/alerts/__tests__/state.test.tsx +240 -0
- package/src/core/alerts/environment.ts +57 -0
- package/src/core/alerts/state.ts +155 -99
- package/src/core/islands/bootstrap.ts +2 -1
- package/src/core/kernel/messages.ts +2 -2
- package/src/core/network/connection-notice.ts +45 -12
- package/src/core/network/connection.ts +19 -0
- package/src/core/network/useConnectionNotice.ts +53 -0
- package/src/core/packages/__tests__/useSandboxController.test.tsx +86 -5
- package/src/core/packages/sandbox-state.ts +56 -4
- package/src/core/packages/useSandboxController.ts +27 -7
- package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +199 -8
- package/src/core/websocket/types.ts +1 -1
- package/src/core/websocket/useMarimoKernelConnection.tsx +31 -19
- package/src/stories/sandbox.stories.tsx +230 -50
|
@@ -3,14 +3,15 @@ import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
|
3
3
|
import { createStore, Provider, useAtomValue } from "jotai";
|
|
4
4
|
import { useEffect, useRef, useState } from "react";
|
|
5
5
|
import { ConnectionNotice } from "@/components/editor/alerts/connection-notice";
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "@/components/editor/chrome/panels/sandbox-panel";
|
|
6
|
+
import PackagesPanel from "@/components/editor/chrome/panels/packages-panel";
|
|
7
|
+
import { PanelSectionProvider } from "@/components/editor/chrome/panels/panel-context";
|
|
8
|
+
import { SandboxToggle } from "@/components/editor/chrome/panels/sandbox-toggle";
|
|
10
9
|
import { SandboxController } from "@/components/editor/chrome/panels/sandbox-controller";
|
|
11
10
|
import { chromeAtom } from "@/components/editor/chrome/state";
|
|
12
11
|
import { Cell } from "@/components/editor/notebook-cell";
|
|
13
12
|
import { VerticalLayoutWrapper } from "@/components/editor/renderers/vertical-layout/vertical-layout-wrapper";
|
|
13
|
+
import { alertAtom } from "@/core/alerts/state";
|
|
14
|
+
import type { EnvironmentOperation } from "@/core/alerts/environment";
|
|
14
15
|
import {
|
|
15
16
|
createNotebookActions,
|
|
16
17
|
notebookAtom,
|
|
@@ -18,18 +19,15 @@ import {
|
|
|
18
19
|
} from "@/core/cells/cells";
|
|
19
20
|
import { userConfigAtom } from "@/core/config/config";
|
|
20
21
|
import {
|
|
22
|
+
type AppConfig,
|
|
21
23
|
AppConfigSchema,
|
|
22
24
|
defaultUserConfig,
|
|
23
25
|
} from "@/core/config/config-schema";
|
|
24
26
|
import { kernelStartupErrorAtom } from "@/core/errors/state";
|
|
25
|
-
import { connectionAtom } from "@/core/network/connection";
|
|
27
|
+
import { connectionAtom, startupProgressAtom } from "@/core/network/connection";
|
|
26
28
|
import { requestClientAtom } from "@/core/network/requests";
|
|
27
29
|
import { createStaticRequests } from "@/core/network/requests-static";
|
|
28
|
-
import {
|
|
29
|
-
sandboxActionsAtom,
|
|
30
|
-
sandboxAtom,
|
|
31
|
-
sandboxSyncAtom,
|
|
32
|
-
} from "@/core/packages/sandbox-state";
|
|
30
|
+
import { sandboxActionsAtom, sandboxAtom } from "@/core/packages/sandbox-state";
|
|
33
31
|
import { filenameAtom } from "@/core/saving/file-state";
|
|
34
32
|
import { WebSocketClosedReason, WebSocketState } from "@/core/websocket/types";
|
|
35
33
|
import { HTTPError } from "@/utils/errors";
|
|
@@ -46,6 +44,19 @@ description = "Explore bike trips"
|
|
|
46
44
|
const resolutionError = `No solution found when resolving dependencies:
|
|
47
45
|
Because there is no version of rich==999.0.0 and your script depends
|
|
48
46
|
on rich==999.0.0, your script's requirements are unsatisfiable.`;
|
|
47
|
+
const preparationOutput = `Using Python 3.13
|
|
48
|
+
Resolving notebook dependencies
|
|
49
|
+
Resolved 24 packages
|
|
50
|
+
Downloading polars
|
|
51
|
+
Downloading rich
|
|
52
|
+
Downloading marimo
|
|
53
|
+
Downloading pyzmq
|
|
54
|
+
Downloaded rich
|
|
55
|
+
Downloaded polars
|
|
56
|
+
Downloaded marimo
|
|
57
|
+
Preparing packages
|
|
58
|
+
Installing packages
|
|
59
|
+
`;
|
|
49
60
|
|
|
50
61
|
interface Props {
|
|
51
62
|
surface: "notebook" | "packages" | "manifest";
|
|
@@ -55,11 +66,68 @@ interface Props {
|
|
|
55
66
|
| "failed"
|
|
56
67
|
| "ready"
|
|
57
68
|
| "syncing"
|
|
58
|
-
| "sync-failed"
|
|
69
|
+
| "sync-failed"
|
|
70
|
+
| "synced"
|
|
71
|
+
| "restart-required";
|
|
59
72
|
existingCells: boolean;
|
|
60
73
|
backend: "uv" | "pixi";
|
|
61
74
|
saveResult: "success" | "failure" | "stale";
|
|
62
75
|
theme: "light" | "dark";
|
|
76
|
+
interactive: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function SandboxPreview({
|
|
80
|
+
props,
|
|
81
|
+
appConfig,
|
|
82
|
+
reconnect,
|
|
83
|
+
}: {
|
|
84
|
+
props: Props;
|
|
85
|
+
appConfig: AppConfig;
|
|
86
|
+
reconnect: () => Promise<void>;
|
|
87
|
+
}) {
|
|
88
|
+
const chrome = useAtomValue(chromeAtom);
|
|
89
|
+
const notebook = useAtomValue(notebookAtom);
|
|
90
|
+
const userConfig = useAtomValue(userConfigAtom);
|
|
91
|
+
const showPackages = props.surface === "packages" || chrome.isSidebarOpen;
|
|
92
|
+
return (
|
|
93
|
+
<div
|
|
94
|
+
className="flex bg-background text-foreground border rounded min-h-[460px]"
|
|
95
|
+
style={{ width: props.surface === "notebook" ? 1000 : 300 }}
|
|
96
|
+
data-testid="sandbox-story"
|
|
97
|
+
>
|
|
98
|
+
{showPackages && props.surface !== "manifest" && (
|
|
99
|
+
<aside className="flex flex-col w-[300px] shrink-0 border-r h-[520px]">
|
|
100
|
+
<div className="flex items-center justify-between px-3 py-2 border-b text-sm">
|
|
101
|
+
Packages
|
|
102
|
+
<SandboxToggle section="sidebar" />
|
|
103
|
+
</div>
|
|
104
|
+
<PanelSectionProvider value="sidebar">
|
|
105
|
+
<PackagesPanel />
|
|
106
|
+
</PanelSectionProvider>
|
|
107
|
+
</aside>
|
|
108
|
+
)}
|
|
109
|
+
{props.surface === "notebook" && (
|
|
110
|
+
<div className="flex-1 min-w-0 pt-12">
|
|
111
|
+
<ConnectionNotice appConfig={appConfig} onRetry={reconnect} />
|
|
112
|
+
{notebook.cellIds.inOrderIds.map((cellId) => (
|
|
113
|
+
<VerticalLayoutWrapper key={cellId} appConfig={appConfig}>
|
|
114
|
+
<Cell
|
|
115
|
+
cellId={cellId}
|
|
116
|
+
theme={props.theme}
|
|
117
|
+
mode="edit"
|
|
118
|
+
showPlaceholder={false}
|
|
119
|
+
canDelete={true}
|
|
120
|
+
isCollapsed={false}
|
|
121
|
+
collapseCount={0}
|
|
122
|
+
canMoveX={false}
|
|
123
|
+
userConfig={userConfig}
|
|
124
|
+
/>
|
|
125
|
+
</VerticalLayoutWrapper>
|
|
126
|
+
))}
|
|
127
|
+
</div>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
63
131
|
}
|
|
64
132
|
|
|
65
133
|
function OpenManifest() {
|
|
@@ -121,9 +189,74 @@ function SandboxStory(props: Props) {
|
|
|
121
189
|
kernelStartupErrorAtom,
|
|
122
190
|
props.phase === "failed" ? resolutionError : null,
|
|
123
191
|
);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
192
|
+
const syncStatus: EnvironmentOperation["status"] | null =
|
|
193
|
+
props.phase === "syncing"
|
|
194
|
+
? { kind: "running" }
|
|
195
|
+
: props.phase === "sync-failed"
|
|
196
|
+
? { kind: "failed", error: resolutionError }
|
|
197
|
+
: props.phase === "restart-required"
|
|
198
|
+
? {
|
|
199
|
+
kind: "restart-required",
|
|
200
|
+
reason:
|
|
201
|
+
"The manifest requires Python 3.14. This kernel uses Python 3.13.",
|
|
202
|
+
}
|
|
203
|
+
: props.phase === "synced"
|
|
204
|
+
? { kind: "succeeded" }
|
|
205
|
+
: null;
|
|
206
|
+
state.set(alertAtom, (value) => ({
|
|
207
|
+
...value,
|
|
208
|
+
environments: {
|
|
209
|
+
...value.environments,
|
|
210
|
+
kernel: {
|
|
211
|
+
restart_required: props.phase === "restart-required",
|
|
212
|
+
operations: [
|
|
213
|
+
{
|
|
214
|
+
operation_id: "story-preparation",
|
|
215
|
+
action: "prepare",
|
|
216
|
+
source: "kernel",
|
|
217
|
+
status:
|
|
218
|
+
props.phase === "failed"
|
|
219
|
+
? { kind: "failed", error: resolutionError }
|
|
220
|
+
: props.phase === "preparing"
|
|
221
|
+
? { kind: "running" }
|
|
222
|
+
: { kind: "succeeded" },
|
|
223
|
+
packages: {},
|
|
224
|
+
logs: {
|
|
225
|
+
environment:
|
|
226
|
+
props.phase === "failed"
|
|
227
|
+
? resolutionError
|
|
228
|
+
: preparationOutput,
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
...(syncStatus
|
|
232
|
+
? [
|
|
233
|
+
{
|
|
234
|
+
operation_id: "story-sync",
|
|
235
|
+
action: "sync" as const,
|
|
236
|
+
source: "kernel" as const,
|
|
237
|
+
status: syncStatus,
|
|
238
|
+
packages: {},
|
|
239
|
+
logs: {
|
|
240
|
+
environment:
|
|
241
|
+
"Reading notebook manifest\nResolving dependencies\nChecking Python version\n",
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
]
|
|
245
|
+
: []),
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
}));
|
|
250
|
+
state.set(startupProgressAtom, {
|
|
251
|
+
phase:
|
|
252
|
+
props.phase !== "preparing" && props.phase !== "failed"
|
|
253
|
+
? "starting-kernel"
|
|
254
|
+
: "preparing-environment",
|
|
255
|
+
logs:
|
|
256
|
+
props.phase !== "preparing" && props.phase !== "failed"
|
|
257
|
+
? "Launching kernel process\nUsing /home/user/.cache/uv/environments-v2/bike-trips-a274bddc/bin/python\nWaiting for kernel connection\n"
|
|
258
|
+
: "",
|
|
259
|
+
log_mode: "replace",
|
|
127
260
|
});
|
|
128
261
|
if (props.existingCells) {
|
|
129
262
|
const actions = createNotebookActions((action) =>
|
|
@@ -143,6 +276,18 @@ function SandboxStory(props: Props) {
|
|
|
143
276
|
manifest: currentManifest,
|
|
144
277
|
filename: "bike_trips.py",
|
|
145
278
|
}),
|
|
279
|
+
getDependencyTree: async () => ({
|
|
280
|
+
context: { kind: "sandbox", backend: props.backend },
|
|
281
|
+
tree: {
|
|
282
|
+
name: "<root>",
|
|
283
|
+
version: null,
|
|
284
|
+
tags: [],
|
|
285
|
+
dependencies: [
|
|
286
|
+
{ name: "marimo", version: "0.24.2", tags: [], dependencies: [] },
|
|
287
|
+
{ name: "polars", version: "1.34.0", tags: [], dependencies: [] },
|
|
288
|
+
],
|
|
289
|
+
},
|
|
290
|
+
}),
|
|
146
291
|
updateManifest: async ({ contents }) => {
|
|
147
292
|
if (props.saveResult === "stale") {
|
|
148
293
|
throw new HTTPError(
|
|
@@ -184,46 +329,56 @@ function SandboxStory(props: Props) {
|
|
|
184
329
|
const reconnect = async () => {
|
|
185
330
|
store.set(connectionAtom, { state: WebSocketState.OPEN });
|
|
186
331
|
};
|
|
332
|
+
useEffect(() => {
|
|
333
|
+
if (!props.interactive) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const appendPreparation = (line: string) =>
|
|
337
|
+
store.set(alertAtom, (value) => ({
|
|
338
|
+
...value,
|
|
339
|
+
environments: {
|
|
340
|
+
...value.environments,
|
|
341
|
+
kernel: {
|
|
342
|
+
...value.environments.kernel,
|
|
343
|
+
operations: value.environments.kernel.operations.map(
|
|
344
|
+
(operation) => ({
|
|
345
|
+
...operation,
|
|
346
|
+
logs: { environment: operation.logs.environment + line },
|
|
347
|
+
}),
|
|
348
|
+
),
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
}));
|
|
352
|
+
const timers = [
|
|
353
|
+
setTimeout(() => appendPreparation("Installed 24 packages\n"), 1500),
|
|
354
|
+
setTimeout(() => appendPreparation("Environment prepared\n"), 2500),
|
|
355
|
+
setTimeout(() => {
|
|
356
|
+
store.set(startupProgressAtom, {
|
|
357
|
+
phase: "starting-kernel",
|
|
358
|
+
logs: "Launching kernel process\nWaiting for kernel connection\n",
|
|
359
|
+
log_mode: "replace",
|
|
360
|
+
});
|
|
361
|
+
store.set(connectionAtom, {
|
|
362
|
+
state: WebSocketState.CONNECTING,
|
|
363
|
+
phase: "starting-kernel",
|
|
364
|
+
});
|
|
365
|
+
}, 3500),
|
|
366
|
+
setTimeout(
|
|
367
|
+
() => store.set(connectionAtom, { state: WebSocketState.OPEN }),
|
|
368
|
+
5500,
|
|
369
|
+
),
|
|
370
|
+
];
|
|
371
|
+
return () => timers.forEach(clearTimeout);
|
|
372
|
+
}, [props.interactive, store]);
|
|
187
373
|
return (
|
|
188
374
|
<Provider store={store}>
|
|
189
375
|
<SandboxController onReconnect={reconnect} />
|
|
190
376
|
{props.surface === "manifest" && <OpenManifest />}
|
|
191
|
-
<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}}
|
|
197
|
-
>
|
|
198
|
-
{props.surface === "notebook" && (
|
|
199
|
-
<>
|
|
200
|
-
<ConnectionNotice appConfig={appConfig} onRetry={reconnect} />
|
|
201
|
-
{store.get(notebookAtom).cellIds.inOrderIds.map((cellId) => (
|
|
202
|
-
<VerticalLayoutWrapper key={cellId} appConfig={appConfig}>
|
|
203
|
-
<Cell
|
|
204
|
-
cellId={cellId}
|
|
205
|
-
theme={props.theme}
|
|
206
|
-
mode="edit"
|
|
207
|
-
showPlaceholder={false}
|
|
208
|
-
canDelete={true}
|
|
209
|
-
isCollapsed={false}
|
|
210
|
-
collapseCount={0}
|
|
211
|
-
canMoveX={false}
|
|
212
|
-
userConfig={store.get(userConfigAtom)}
|
|
213
|
-
/>
|
|
214
|
-
</VerticalLayoutWrapper>
|
|
215
|
-
))}
|
|
216
|
-
</>
|
|
217
|
-
)}
|
|
218
|
-
{props.surface === "packages" &&
|
|
219
|
-
(props.phase === "failed" ||
|
|
220
|
-
props.phase === "sync-failed" ||
|
|
221
|
-
props.phase === "preparing" ? (
|
|
222
|
-
<SandboxStartupPanel />
|
|
223
|
-
) : (
|
|
224
|
-
<SandboxFooter />
|
|
225
|
-
))}
|
|
226
|
-
</div>
|
|
377
|
+
<SandboxPreview
|
|
378
|
+
props={props}
|
|
379
|
+
appConfig={appConfig}
|
|
380
|
+
reconnect={reconnect}
|
|
381
|
+
/>
|
|
227
382
|
</Provider>
|
|
228
383
|
);
|
|
229
384
|
}
|
|
@@ -239,6 +394,7 @@ const meta = {
|
|
|
239
394
|
backend: "uv",
|
|
240
395
|
saveResult: "success",
|
|
241
396
|
theme: "light",
|
|
397
|
+
interactive: false,
|
|
242
398
|
},
|
|
243
399
|
render: (args, context) => (
|
|
244
400
|
<SandboxStory
|
|
@@ -262,6 +418,14 @@ export const StartingKernel: Story = {
|
|
|
262
418
|
name: "Startup notice / starting kernel",
|
|
263
419
|
args: { phase: "starting" },
|
|
264
420
|
};
|
|
421
|
+
export const StartupTransition: Story = {
|
|
422
|
+
name: "Startup / completion transition",
|
|
423
|
+
args: { interactive: true, backend: "pixi" },
|
|
424
|
+
};
|
|
425
|
+
export const EmptyStartupTransition: Story = {
|
|
426
|
+
name: "Empty notebook / completion transition",
|
|
427
|
+
args: { interactive: true, existingCells: false, backend: "pixi" },
|
|
428
|
+
};
|
|
265
429
|
export const ExistingNotebookFailed: Story = {
|
|
266
430
|
name: "Startup notice / failed",
|
|
267
431
|
args: { phase: "failed" },
|
|
@@ -274,6 +438,14 @@ export const PackagesPreparing: Story = {
|
|
|
274
438
|
name: "Setup details / preparing",
|
|
275
439
|
args: { surface: "packages" },
|
|
276
440
|
};
|
|
441
|
+
export const PackagesStarting: Story = {
|
|
442
|
+
name: "Setup details / starting kernel",
|
|
443
|
+
args: { surface: "packages", phase: "starting" },
|
|
444
|
+
};
|
|
445
|
+
export const PackagesStartupTransition: Story = {
|
|
446
|
+
name: "Setup details / live output",
|
|
447
|
+
args: { surface: "packages", interactive: true },
|
|
448
|
+
};
|
|
277
449
|
export const PackagesFailed: Story = {
|
|
278
450
|
name: "Setup details / failed",
|
|
279
451
|
args: { surface: "packages", phase: "failed" },
|
|
@@ -290,6 +462,14 @@ export const PackagesSyncFailed: Story = {
|
|
|
290
462
|
name: "Setup details / sync failed",
|
|
291
463
|
args: { surface: "packages", phase: "sync-failed" },
|
|
292
464
|
};
|
|
465
|
+
export const PackagesSynced: Story = {
|
|
466
|
+
name: "Setup details / sync completed",
|
|
467
|
+
args: { surface: "packages", phase: "synced" },
|
|
468
|
+
};
|
|
469
|
+
export const PackagesRestartRequired: Story = {
|
|
470
|
+
name: "Setup details / restart required",
|
|
471
|
+
args: { surface: "packages", phase: "restart-required" },
|
|
472
|
+
};
|
|
293
473
|
export const PixiPackagesReady: Story = {
|
|
294
474
|
name: "Status row / pixi",
|
|
295
475
|
args: { surface: "packages", phase: "ready", backend: "pixi" },
|