@marimo-team/islands 0.19.3-dev6 → 0.19.3-dev8
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/main.js +3 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/editor/KernelStartupErrorModal.tsx +101 -0
- package/src/core/MarimoApp.tsx +2 -0
- package/src/core/errors/state.ts +7 -1
- package/src/core/islands/main.ts +2 -0
- package/src/core/websocket/types.ts +1 -0
- package/src/core/websocket/useMarimoKernelConnection.tsx +18 -1
package/package.json
CHANGED
|
@@ -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">
|
|
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 whitespace-pre-wrap break-words">
|
|
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
|
+
};
|
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/errors/state.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import { useAtomValue } from "jotai";
|
|
3
|
+
import { atom, useAtomValue } from "jotai";
|
|
4
4
|
import { createReducerAndAtoms } from "@/utils/createReducer";
|
|
5
5
|
import type { Identified } from "@/utils/typed";
|
|
6
6
|
import { generateUUID } from "@/utils/uuid";
|
|
7
7
|
import type { Banner } from "../kernel/messages";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Atom for storing kernel startup error message.
|
|
11
|
+
* When set to a non-null value, shows a modal with the error details.
|
|
12
|
+
*/
|
|
13
|
+
export const kernelStartupErrorAtom = atom<string | null>(null);
|
|
14
|
+
|
|
9
15
|
interface BannerState {
|
|
10
16
|
banners: Identified<Banner>[];
|
|
11
17
|
}
|
package/src/core/islands/main.ts
CHANGED
|
@@ -16,6 +16,7 @@ export const WebSocketClosedReason = {
|
|
|
16
16
|
KERNEL_DISCONNECTED: "KERNEL_DISCONNECTED",
|
|
17
17
|
ALREADY_RUNNING: "ALREADY_RUNNING",
|
|
18
18
|
MALFORMED_QUERY: "MALFORMED_QUERY",
|
|
19
|
+
KERNEL_STARTUP_ERROR: "KERNEL_STARTUP_ERROR",
|
|
19
20
|
} as const;
|
|
20
21
|
|
|
21
22
|
export type WebSocketClosedReason =
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
} from "../datasets/request-registry";
|
|
41
41
|
import { useDatasetsActions } from "../datasets/state";
|
|
42
42
|
import { UI_ELEMENT_REGISTRY } from "../dom/uiregistry";
|
|
43
|
-
import { useBannersActions } from "../errors/state";
|
|
43
|
+
import { kernelStartupErrorAtom, useBannersActions } from "../errors/state";
|
|
44
44
|
import { FUNCTIONS_REGISTRY } from "../functions/FunctionRegistry";
|
|
45
45
|
import {
|
|
46
46
|
handleCellNotificationeration,
|
|
@@ -105,6 +105,7 @@ export function useMarimoKernelConnection(opts: {
|
|
|
105
105
|
const setCapabilities = useSetAtom(capabilitiesAtom);
|
|
106
106
|
const runtimeManager = useRuntimeManager();
|
|
107
107
|
const setCacheInfo = useSetAtom(cacheInfoAtom);
|
|
108
|
+
const setKernelStartupError = useSetAtom(kernelStartupErrorAtom);
|
|
108
109
|
|
|
109
110
|
const handleMessage = (e: MessageEvent<JsonString<NotificationPayload>>) => {
|
|
110
111
|
const msg = jsonParseWithSpecialChar(e.data);
|
|
@@ -134,6 +135,11 @@ export function useMarimoKernelConnection(opts: {
|
|
|
134
135
|
case "interrupted":
|
|
135
136
|
return;
|
|
136
137
|
|
|
138
|
+
case "kernel-startup-error":
|
|
139
|
+
// Full error received via message before websocket close
|
|
140
|
+
setKernelStartupError(msg.data.error);
|
|
141
|
+
return;
|
|
142
|
+
|
|
137
143
|
case "send-ui-element-message": {
|
|
138
144
|
const modelId = msg.data.model_id;
|
|
139
145
|
const uiElement = msg.data.ui_element;
|
|
@@ -413,6 +419,17 @@ export function useMarimoKernelConnection(opts: {
|
|
|
413
419
|
return;
|
|
414
420
|
|
|
415
421
|
default:
|
|
422
|
+
// Check for kernel startup error (full error already received via message)
|
|
423
|
+
if (e.reason === "MARIMO_KERNEL_STARTUP_ERROR") {
|
|
424
|
+
setConnection({
|
|
425
|
+
state: WebSocketState.CLOSED,
|
|
426
|
+
code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
|
|
427
|
+
reason: "Failed to start kernel sandbox",
|
|
428
|
+
});
|
|
429
|
+
ws.close(); // prevent reconnecting
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
416
433
|
// Session should be valid
|
|
417
434
|
// - browser tab might have been closed or re-opened
|
|
418
435
|
// - computer might have just woken from sleep
|