@marimo-team/islands 0.25.3-dev311 → 0.25.3-dev316
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-DdteSMhq.js → ErrorBoundary-C3G05Nb1.js} +1 -1
- package/dist/{chat-ui-DkuxGEDp.js → chat-ui-DASKYW38.js} +13 -13
- package/dist/{code-visibility-BzqsfUpE.js → code-visibility-B3_gXvem.js} +31 -32
- package/dist/{common-CfI-FyP-.js → common-Vd6TgXHQ.js} +5074 -5074
- package/dist/{config-BVYA1P0C.js → config-CL7mwGLX.js} +87 -129
- package/dist/{data-grid-overlay-editor-BM-WjDgA.js → data-grid-overlay-editor-DLEPVcX1.js} +1 -1
- package/dist/{error-entries-istW7Xbs.js → error-entries-kb4H6PAT.js} +533 -508
- package/dist/feedback-button-gqE30Uez.js +370 -0
- package/dist/{formats-CMa7L3E8.js → formats-qhBmYb0l.js} +1 -1
- package/dist/{glide-data-editor-BQCggnhx.js → glide-data-editor-BmtEcZoo.js} +3 -3
- package/dist/{globals-DJuYoG49.js → globals-BIt_qRYC.js} +1 -1
- package/dist/{html-to-image-pPbR2cDx.js → html-to-image-DR8VPB7E.js} +4018 -4021
- package/dist/main.js +4638 -4624
- package/dist/{number-overlay-editor-rhy7Cfzx.js → number-overlay-editor-Bbxt9i1c.js} +1 -1
- package/dist/{process-output-BySO1nIs.js → process-output-BDMtqL6K.js} +2 -2
- package/dist/{reveal-component-Deq9swmP.js → reveal-component-DXFsIk5S.js} +4 -4
- package/dist/static-state-Dtocd9UO.js +68 -0
- package/dist/{vega-component-Bly2lDhz.js → vega-component-CeN8zClP.js} +9 -9
- package/package.json +1 -1
- package/src/__tests__/mount.test.ts +17 -58
- package/src/components/editor/actions/useRestartKernel.tsx +0 -5
- package/src/components/editor/cell/__tests__/useRunCells.test.tsx +0 -3
- package/src/components/editor/cell/useRunCells.ts +2 -2
- package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +2 -16
- package/src/components/editor/renderers/cell-array.tsx +0 -3
- package/src/core/edit-app.tsx +2 -7
- package/src/core/executions/__tests__/run.test.ts +0 -3
- package/src/core/executions/index.ts +1 -1
- package/src/core/executions/run.ts +1 -14
- package/src/core/islands/bootstrap.ts +0 -1
- package/src/core/network/__tests__/requests-network.test.ts +0 -16
- package/src/core/network/connection.ts +0 -5
- package/src/core/network/requests-toasting.tsx +1 -49
- package/src/core/network/resolve.ts +1 -5
- package/src/core/notebook/replica/__tests__/replica.test.ts +3 -3
- package/src/core/notebook/replica/connection.ts +1 -5
- package/src/core/runtime/__tests__/createWsUrl.test.ts +4 -16
- package/src/core/runtime/__tests__/runtime.test.ts +58 -168
- package/src/core/runtime/adapter.ts +1 -8
- package/src/core/runtime/config.ts +4 -59
- package/src/core/runtime/runtime.ts +1 -31
- package/src/core/runtime/types.ts +0 -5
- package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +5 -5
- package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +125 -29
- package/src/core/session/connection-utils.ts +2 -14
- package/src/core/session/useNotebookSession.tsx +19 -12
- package/src/mount.tsx +3 -9
- package/src/utils/errors.ts +0 -7
- package/dist/feedback-button-BGtR35Ev.js +0 -371
- package/dist/toDate-5qPtZ6HL.js +0 -94
- package/src/components/editor/alerts/connecting-alert.tsx +0 -27
- package/src/core/network/__tests__/requests-lazy.test.ts +0 -322
- package/src/core/network/requests-lazy.ts +0 -222
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as e } from "./rolldown-runtime-BPCzCO3I.js";
|
|
2
2
|
import { t } from "./react-CHbZqgBF.js";
|
|
3
|
-
import { a as n } from "./glide-data-editor-
|
|
3
|
+
import { a as n } from "./glide-data-editor-BmtEcZoo.js";
|
|
4
4
|
//#region ../node_modules/.pnpm/@glideapps+glide-data-grid@6.0.4-alpha24_lodash@4.17.21_marked@15.0.12_react-dom@19.3.0_27cffe7f1bc30287d59ac27db3240c5b/node_modules/@glideapps/glide-data-grid/dist/esm/internal/data-grid-overlay-editor/private/number-overlay-editor-style.js
|
|
5
5
|
var r = /* @__PURE__ */ e(t()), i = /*#__PURE__*/ n("div")({
|
|
6
6
|
name: "NumberOverlayEditorStyle",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { T as e } from "./html-to-image-
|
|
1
|
+
import { T as e } from "./html-to-image-DR8VPB7E.js";
|
|
2
2
|
import { h as t } from "./tooltip-BekOCQ3v.js";
|
|
3
|
-
import {
|
|
3
|
+
import { $ as n, Q as r } from "./error-entries-kb4H6PAT.js";
|
|
4
4
|
import { r as i } from "./assertNever-efcK_v3t.js";
|
|
5
5
|
import { n as a } from "./semaphore-8KhQouXt.js";
|
|
6
6
|
var o = t("file", [["path", {
|
|
@@ -3,15 +3,15 @@ import { g as t, h as n, i as r, m as i, t as a } from "./button-BuSV-mLI.js";
|
|
|
3
3
|
import { t as o } from "./react-CHbZqgBF.js";
|
|
4
4
|
import { t as s } from "./compiler-runtime-DNezxW8I.js";
|
|
5
5
|
import { h as c, t as l } from "./tooltip-BekOCQ3v.js";
|
|
6
|
-
import { $ as u, Q as d, _n as f, an as p, bn as m, et as h, gn as g, i as _, l as v, n as y, on as b, r as x, t as S, u as C } from "./common-
|
|
6
|
+
import { $ as u, Q as d, _n as f, an as p, bn as m, et as h, gn as g, i as _, l as v, n as y, on as b, r as x, t as S, u as C } from "./common-Vd6TgXHQ.js";
|
|
7
7
|
import { M as w } from "./select-XmXyen3r.js";
|
|
8
8
|
import { Y as T } from "./dropdown-menu-CAejOChE.js";
|
|
9
|
-
import {
|
|
9
|
+
import { Nt as E } from "./error-entries-kb4H6PAT.js";
|
|
10
10
|
import { t as D } from "./jsx-runtime-6ZiU38At.js";
|
|
11
11
|
import { Ft as O, Rt as k, d as A, r as ee } from "./use-restore-focus-DyrKLdSB.js";
|
|
12
12
|
import { t as j } from "./useEvent-xDnF2X04.js";
|
|
13
|
-
import {
|
|
14
|
-
import { n as ne, t as re } from "./code-visibility-
|
|
13
|
+
import { o as te } from "./static-state-Dtocd9UO.js";
|
|
14
|
+
import { n as ne, t as re } from "./code-visibility-B3_gXvem.js";
|
|
15
15
|
/* empty css */
|
|
16
16
|
var M = c("sticky-note", [["path", {
|
|
17
17
|
d: "M21 9a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 15 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2z",
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { t as e } from "./compiler-runtime-DNezxW8I.js";
|
|
2
|
+
import { Ft as t, Rt as n, d as r, m as i, yt as a } from "./use-restore-focus-DyrKLdSB.js";
|
|
3
|
+
import { t as o } from "./invariant-DLmrl-hA.js";
|
|
4
|
+
//#region src/core/wasm/utils.ts
|
|
5
|
+
function s() {
|
|
6
|
+
return typeof document < "u" && document.querySelector("marimo-wasm") !== null;
|
|
7
|
+
}
|
|
8
|
+
var c = 6048e5, l = 864e5, u = Symbol.for("constructDateFrom");
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region ../node_modules/.pnpm/date-fns@4.4.0/node_modules/date-fns/constructFrom.js
|
|
11
|
+
function d(e, t) {
|
|
12
|
+
return typeof e == "function" ? e(t) : e && typeof e == "object" && u in e ? e[u](t) : e instanceof Date ? new e.constructor(t) : new Date(t);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region ../node_modules/.pnpm/date-fns@4.4.0/node_modules/date-fns/toDate.js
|
|
16
|
+
function f(e, t) {
|
|
17
|
+
return d(t || e, e);
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/utils/assertExists.ts
|
|
21
|
+
var p = e();
|
|
22
|
+
function m(e, t) {
|
|
23
|
+
if (e == null) throw Error(t || `Expected value but got ${e}`);
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/core/mode.ts
|
|
27
|
+
function h() {
|
|
28
|
+
let e = a.get(_);
|
|
29
|
+
return m(e, "internal-error: initial mode not found"), o(e !== "present", "internal-error: initial mode cannot be 'present'"), e;
|
|
30
|
+
}
|
|
31
|
+
var g = n({
|
|
32
|
+
mode: r() ? "read" : "not-set",
|
|
33
|
+
cellAnchor: null
|
|
34
|
+
}), _ = n(void 0);
|
|
35
|
+
function v() {
|
|
36
|
+
let e = a.get(_);
|
|
37
|
+
return e !== "home" && e !== "gallery";
|
|
38
|
+
}
|
|
39
|
+
var y = n(!1);
|
|
40
|
+
function b() {
|
|
41
|
+
let e = (0, p.c)(1), { mode: n } = t(g), r = t(y), a;
|
|
42
|
+
return e[0] === Symbol.for("react.memo_cache_sentinel") ? (a = new URLSearchParams(window.location.search).get(i.kiosk), e[0] = a) : a = e[0], n !== "read" && !r && a !== "true";
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/core/static/static-state.ts
|
|
46
|
+
function x(e) {
|
|
47
|
+
if (typeof e != "object" || !e || Array.isArray(e)) return !1;
|
|
48
|
+
for (let t of Object.values(e)) if (typeof t != "string") return !1;
|
|
49
|
+
return !0;
|
|
50
|
+
}
|
|
51
|
+
function S(e) {
|
|
52
|
+
if (typeof e != "object" || !e || Array.isArray(e)) return !1;
|
|
53
|
+
let t = e;
|
|
54
|
+
return !(!x(t.files) || t.modelNotifications !== void 0 && !Array.isArray(t.modelNotifications));
|
|
55
|
+
}
|
|
56
|
+
function C() {
|
|
57
|
+
let e = typeof window > "u" ? void 0 : window.__MARIMO_STATIC__;
|
|
58
|
+
return S(e) ? e : void 0;
|
|
59
|
+
}
|
|
60
|
+
function w() {
|
|
61
|
+
return C() !== void 0;
|
|
62
|
+
}
|
|
63
|
+
function T() {
|
|
64
|
+
let e = C();
|
|
65
|
+
return o(e !== void 0, "Not a static notebook"), e.files;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { v as a, g as c, d, l as f, _ as i, m as l, s as m, w as n, y as o, c as p, h as r, b as s, T as t, f as u };
|
|
@@ -3,14 +3,14 @@ import { g as t, h as n, m as r, s as i } from "./button-BuSV-mLI.js";
|
|
|
3
3
|
import { t as a } from "./react-CHbZqgBF.js";
|
|
4
4
|
import { t as o } from "./compiler-runtime-DNezxW8I.js";
|
|
5
5
|
import { t as s } from "./tooltip-BekOCQ3v.js";
|
|
6
|
-
import {
|
|
6
|
+
import { l as c, t as l } from "./config-CL7mwGLX.js";
|
|
7
7
|
import { t as u } from "./jsx-runtime-6ZiU38At.js";
|
|
8
8
|
import { u as d } from "./use-restore-focus-DyrKLdSB.js";
|
|
9
9
|
import { n as f } from "./error-banner-DkQNU4bn.js";
|
|
10
10
|
import { t as p } from "./debounce-DrhhziJv.js";
|
|
11
11
|
import { t as ee } from "./objects-DCmMvZtn.js";
|
|
12
12
|
import { t as te } from "./useEvent-xDnF2X04.js";
|
|
13
|
-
import { a as ne, i as re, n as ie, t as m } from "./formats-
|
|
13
|
+
import { a as ne, i as re, n as ie, t as m } from "./formats-qhBmYb0l.js";
|
|
14
14
|
import { a as h, t as g } from "./arrays-DoQ-AILx.js";
|
|
15
15
|
import { t as ae } from "./useAsyncData-DMBliR6D.js";
|
|
16
16
|
import { t as _ } from "./semaphore-8KhQouXt.js";
|
|
@@ -22,7 +22,7 @@ import { t as de } from "./use-vega-container-remeasure-DFBTESqc.js";
|
|
|
22
22
|
//#region src/plugins/impl/vega/fix-relative-url.ts
|
|
23
23
|
var fe = /* @__PURE__ */ e(a(), 1), pe = o();
|
|
24
24
|
function me(e) {
|
|
25
|
-
return e.data && "url" in e.data && (e.data.url =
|
|
25
|
+
return e.data && "url" in e.data && (e.data.url = l(e.data.url).href), e;
|
|
26
26
|
}
|
|
27
27
|
//#endregion
|
|
28
28
|
//#region src/plugins/impl/vega/types.ts
|
|
@@ -487,7 +487,7 @@ async function W(e) {
|
|
|
487
487
|
}), !e.data || !("url" in e.data)) return e;
|
|
488
488
|
let i;
|
|
489
489
|
try {
|
|
490
|
-
i =
|
|
490
|
+
i = l(e.data.url);
|
|
491
491
|
} catch {
|
|
492
492
|
return e;
|
|
493
493
|
}
|
|
@@ -525,7 +525,7 @@ var K = (e) => {
|
|
|
525
525
|
embedOptions: s
|
|
526
526
|
}), t[5] = i, t[6] = s, t[7] = a, t[8] = u, t[9] = r, t[10] = n, t[11] = p) : p = t[11], p;
|
|
527
527
|
}, q = (e) => {
|
|
528
|
-
let a = (0, pe.c)(50), { value: o, setValue:
|
|
528
|
+
let a = (0, pe.c)(50), { value: o, setValue: l, chartSelection: u, fieldSelection: f, spec: ne, embedOptions: m } = e, { theme: h } = d(), g = (0, fe.useRef)(null), ae = (0, fe.useRef)(void 0), [_, se] = (0, fe.useState)(), v;
|
|
529
529
|
bb0: {
|
|
530
530
|
if (m && "actions" in m) {
|
|
531
531
|
v = m.actions;
|
|
@@ -545,12 +545,12 @@ var K = (e) => {
|
|
|
545
545
|
let C = x, w;
|
|
546
546
|
a[5] === C ? w = a[6] : (w = E(C), a[5] = C, a[6] = w);
|
|
547
547
|
let T = w, D;
|
|
548
|
-
a[7] !==
|
|
549
|
-
|
|
548
|
+
a[7] !== l || a[8] !== o ? (D = (e) => {
|
|
549
|
+
l({
|
|
550
550
|
...o,
|
|
551
551
|
...e
|
|
552
552
|
});
|
|
553
|
-
}, a[7] =
|
|
553
|
+
}, a[7] = l, a[8] = o, a[9] = D) : D = a[9];
|
|
554
554
|
let O = te(D), k;
|
|
555
555
|
a[10] === O ? k = a[11] : (k = p((e, n) => {
|
|
556
556
|
t.debug("[Vega signal]", e, n);
|
|
@@ -587,7 +587,7 @@ var K = (e) => {
|
|
|
587
587
|
className: "text-xs flex flex-col",
|
|
588
588
|
children: e.map(ve)
|
|
589
589
|
}),
|
|
590
|
-
children: /* @__PURE__ */ (0, G.jsx)(
|
|
590
|
+
children: /* @__PURE__ */ (0, G.jsx)(c, { className: "absolute bottom-1 right-0 m-2 h-4 w-4 cursor-help text-muted-foreground hover:text-foreground" })
|
|
591
591
|
});
|
|
592
592
|
}, a[20] = T, a[21] = R);
|
|
593
593
|
let z = R, B = h === "dark" ? "dark" : void 0, V;
|
package/package.json
CHANGED
|
@@ -4,10 +4,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
4
4
|
import { getSerializedLayout } from "@/core/layout/layout";
|
|
5
5
|
import { initialLayoutState, layoutStateAtom } from "@/core/layout/state";
|
|
6
6
|
import { kioskModeAtom } from "@/core/mode";
|
|
7
|
-
import {
|
|
7
|
+
import { runtimeConfigAtom } from "@/core/runtime/config";
|
|
8
|
+
import { RuntimeManager } from "@/core/runtime/runtime";
|
|
8
9
|
import { store } from "@/core/state/jotai";
|
|
9
10
|
import { isStaticNotebook } from "@/core/static/static-state";
|
|
10
|
-
import { ConnectionState } from "@/core/session/types";
|
|
11
11
|
import { pairConfigAtom } from "@/core/config/pair";
|
|
12
12
|
import { PAIR_CONFIG } from "./fixtures/pair-config";
|
|
13
13
|
import { mount, visibleForTesting } from "../mount";
|
|
@@ -58,8 +58,7 @@ describe("mount", () => {
|
|
|
58
58
|
vi.mocked(isStaticNotebook).mockReturnValue(false);
|
|
59
59
|
store.set(layoutStateAtom, initialLayoutState());
|
|
60
60
|
store.set(kioskModeAtom, false);
|
|
61
|
-
|
|
62
|
-
store.set(connectionAtom, { state: ConnectionState.NOT_STARTED });
|
|
61
|
+
vi.spyOn(RuntimeManager.prototype, "init").mockResolvedValue(undefined);
|
|
63
62
|
});
|
|
64
63
|
|
|
65
64
|
afterEach(() => {
|
|
@@ -100,63 +99,23 @@ describe("mount", () => {
|
|
|
100
99
|
expect(store.get(pairConfigAtom)).toBeUndefined();
|
|
101
100
|
});
|
|
102
101
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
mount(
|
|
106
|
-
{
|
|
107
|
-
...baseOptions,
|
|
108
|
-
runtimeConfig: [{ url: "http://localhost:8080", lazy: false }],
|
|
109
|
-
},
|
|
110
|
-
mockElement,
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
const connection = store.get(connectionAtom);
|
|
114
|
-
expect(connection.state).toBe(ConnectionState.CONNECTING);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("should keep connection as NOT_STARTED when runtimeConfig has lazy=true", () => {
|
|
118
|
-
mount(
|
|
119
|
-
{
|
|
120
|
-
...baseOptions,
|
|
121
|
-
runtimeConfig: [{ url: "http://localhost:8080", lazy: true }],
|
|
122
|
-
},
|
|
123
|
-
mockElement,
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
const connection = store.get(connectionAtom);
|
|
127
|
-
expect(connection.state).toBe(ConnectionState.NOT_STARTED);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it("should keep connection as NOT_STARTED when no runtimeConfig is provided", () => {
|
|
131
|
-
mount(
|
|
132
|
-
{
|
|
133
|
-
...baseOptions,
|
|
134
|
-
runtimeConfig: [],
|
|
135
|
-
},
|
|
136
|
-
mockElement,
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
const connection = store.get(connectionAtom);
|
|
140
|
-
expect(connection.state).toBe(ConnectionState.NOT_STARTED);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("should keep connection as NOT_STARTED for static notebooks even with lazy=false", () => {
|
|
144
|
-
vi.mocked(isStaticNotebook).mockReturnValue(true);
|
|
102
|
+
it("starts looking for the page's runtime", () => {
|
|
103
|
+
mountRead();
|
|
145
104
|
|
|
146
|
-
|
|
147
|
-
|
|
105
|
+
expect(RuntimeManager.prototype.init).toHaveBeenCalledOnce();
|
|
106
|
+
});
|
|
148
107
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
|
|
108
|
+
it("accepts a runtime config that still carries `lazy`", () => {
|
|
109
|
+
const error = mount(
|
|
110
|
+
{
|
|
111
|
+
...baseOptions,
|
|
112
|
+
runtimeConfig: [{ url: "http://localhost:8080", lazy: true }],
|
|
113
|
+
},
|
|
114
|
+
mockElement,
|
|
115
|
+
);
|
|
156
116
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
});
|
|
117
|
+
expect(error).toBeUndefined();
|
|
118
|
+
expect(store.get(runtimeConfigAtom).url).toBe("http://localhost:8080");
|
|
160
119
|
});
|
|
161
120
|
|
|
162
121
|
it("hydrates the layout embedded in the mount config", () => {
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import { useSetAtom } from "jotai";
|
|
4
3
|
import { useImperativeModal } from "@/components/modal/ImperativeModal";
|
|
5
4
|
import { AlertDialogDestructiveAction } from "@/components/ui/alert-dialog";
|
|
6
|
-
import { connectionAtom } from "@/core/network/connection";
|
|
7
5
|
import { useRequestClient } from "@/core/network/requests";
|
|
8
|
-
import { ConnectionState } from "@/core/session/types";
|
|
9
6
|
import { reloadSafe } from "@/utils/reload-safe";
|
|
10
7
|
|
|
11
8
|
export function useRestartKernel() {
|
|
12
9
|
const { openConfirm } = useImperativeModal();
|
|
13
|
-
const setConnection = useSetAtom(connectionAtom);
|
|
14
10
|
const { sendRestart } = useRequestClient();
|
|
15
11
|
|
|
16
12
|
return () => {
|
|
@@ -22,7 +18,6 @@ export function useRestartKernel() {
|
|
|
22
18
|
confirmAction: (
|
|
23
19
|
<AlertDialogDestructiveAction
|
|
24
20
|
onClick={async () => {
|
|
25
|
-
setConnection({ state: ConnectionState.CLOSING });
|
|
26
21
|
await sendRestart();
|
|
27
22
|
reloadSafe();
|
|
28
23
|
}}
|
|
@@ -27,9 +27,6 @@ const toast = vi.fn();
|
|
|
27
27
|
vi.mock("@/components/ui/use-toast", () => ({
|
|
28
28
|
toast: (...args: unknown[]) => toast(...args),
|
|
29
29
|
}));
|
|
30
|
-
vi.mock("@/core/runtime/config", () => ({
|
|
31
|
-
startRuntimeIfLazy: async () => undefined,
|
|
32
|
-
}));
|
|
33
30
|
|
|
34
31
|
const C1 = cellId("c1");
|
|
35
32
|
const C2 = cellId("c2");
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
cellFreshnessAtom,
|
|
14
14
|
runCells,
|
|
15
15
|
syncEdits,
|
|
16
|
-
|
|
16
|
+
waitForRuntimeRunning,
|
|
17
17
|
} from "@/core/executions";
|
|
18
18
|
import { getCurrentLanguageAdapter } from "@/core/codemirror/language/commands";
|
|
19
19
|
import { activeDocumentModelAtom } from "@/core/session/active-notebook";
|
|
@@ -36,7 +36,7 @@ export function useRunStaleCells() {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
try {
|
|
39
|
-
await
|
|
39
|
+
await waitForRuntimeRunning(store);
|
|
40
40
|
} catch (error) {
|
|
41
41
|
if (store.get(activeDocumentModelAtom) !== model) {
|
|
42
42
|
return;
|
|
@@ -6,11 +6,10 @@ import type React from "react";
|
|
|
6
6
|
import { Spinner } from "@/components/icons/spinner";
|
|
7
7
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
8
8
|
import { connectionAtom } from "@/core/network/connection";
|
|
9
|
-
import {
|
|
9
|
+
import { useRuntimeManager } from "@/core/runtime/config";
|
|
10
10
|
import { store } from "@/core/state/jotai";
|
|
11
11
|
import { isWasm } from "@/core/wasm/utils";
|
|
12
12
|
import {
|
|
13
|
-
isAppClosing,
|
|
14
13
|
isAppConnected,
|
|
15
14
|
isAppConnecting,
|
|
16
15
|
isAppNotStarted,
|
|
@@ -36,7 +35,6 @@ export function getConnectionStatus(): ConnectionStatus {
|
|
|
36
35
|
export const BackendConnectionStatus: React.FC = () => {
|
|
37
36
|
const connection = useAtomValue(connectionAtom).state;
|
|
38
37
|
const runtime = useRuntimeManager();
|
|
39
|
-
const connectToRuntime = useConnectToRuntime();
|
|
40
38
|
const setConnectionStatus = useSetAtom(connectionStatusAtom);
|
|
41
39
|
|
|
42
40
|
const { isFetching, error, data, refetch } = useAsyncData(async () => {
|
|
@@ -103,10 +101,6 @@ export const BackendConnectionStatus: React.FC = () => {
|
|
|
103
101
|
return <Spinner size="small" />;
|
|
104
102
|
}
|
|
105
103
|
|
|
106
|
-
if (isAppClosing(connection)) {
|
|
107
|
-
return <Spinner className="text-destructive" size="small" />;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
104
|
if (isAppConnected(connection)) {
|
|
111
105
|
if (data?.isHealthy) {
|
|
112
106
|
return <CheckCircle2Icon className="w-4 h-4 text-(--green-9)" />;
|
|
@@ -123,14 +117,6 @@ export const BackendConnectionStatus: React.FC = () => {
|
|
|
123
117
|
return <PowerOffIcon className="w-4 h-4 text-red-500" />;
|
|
124
118
|
};
|
|
125
119
|
|
|
126
|
-
const handleClick = () => {
|
|
127
|
-
if (isAppNotStarted(connection)) {
|
|
128
|
-
void connectToRuntime();
|
|
129
|
-
} else {
|
|
130
|
-
refetch();
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
120
|
return (
|
|
135
121
|
<Tooltip
|
|
136
122
|
content={
|
|
@@ -147,7 +133,7 @@ export const BackendConnectionStatus: React.FC = () => {
|
|
|
147
133
|
>
|
|
148
134
|
<button
|
|
149
135
|
type="button"
|
|
150
|
-
onClick={
|
|
136
|
+
onClick={refetch}
|
|
151
137
|
className="p-1 hover:bg-accent rounded flex items-center gap-1.5 text-xs text-muted-foreground"
|
|
152
138
|
data-testid="backend-status"
|
|
153
139
|
>
|
|
@@ -29,7 +29,6 @@ import type { AppConfig, UserConfig } from "../../../core/config/config-schema";
|
|
|
29
29
|
import type { AppMode } from "../../../core/mode";
|
|
30
30
|
import { useHotkey } from "../../../hooks/useHotkey";
|
|
31
31
|
import { type Theme, useTheme } from "../../../theme/useTheme";
|
|
32
|
-
import { NotStartedConnectionAlert } from "../alerts/connecting-alert";
|
|
33
32
|
import { FloatingOutline } from "../chrome/panels/outline/floating-outline";
|
|
34
33
|
import { useChromeActions } from "../chrome/state";
|
|
35
34
|
import { Column } from "../columns/cell-column";
|
|
@@ -124,8 +123,6 @@ const CellArrayInternal: React.FC<CellArrayProps> = ({
|
|
|
124
123
|
<StartupLogsAlert />
|
|
125
124
|
<StdinBlockingAlert />
|
|
126
125
|
<NotebookBanner width={appConfig.width} />
|
|
127
|
-
{/* Only show if not cells, otherwise running a single cell will start the connection */}
|
|
128
|
-
{cellIds.length === 0 && <NotStartedConnectionAlert />}
|
|
129
126
|
<div
|
|
130
127
|
className={cn(
|
|
131
128
|
appConfig.width === "columns" &&
|
package/src/core/edit-app.tsx
CHANGED
|
@@ -7,7 +7,6 @@ const TooltipProvider = Tooltip.Provider;
|
|
|
7
7
|
|
|
8
8
|
import { useAtomValue } from "jotai";
|
|
9
9
|
import { lazy, useEffect } from "react";
|
|
10
|
-
import { NotStartedConnectionAlert } from "@/components/editor/alerts/connecting-alert";
|
|
11
10
|
import { Controls } from "@/components/editor/controls/Controls";
|
|
12
11
|
import { SandboxController } from "@/components/editor/chrome/panels/sandbox-controller";
|
|
13
12
|
import { ConnectionNotice } from "@/components/editor/alerts/connection-notice";
|
|
@@ -196,12 +195,8 @@ export const EditApp: React.FC<EditAppProps> = ({
|
|
|
196
195
|
canOpenPackages={!hideControls}
|
|
197
196
|
/>
|
|
198
197
|
|
|
199
|
-
{/* Don't render until we have a single cell.
|
|
200
|
-
|
|
201
|
-
<ProgressiveBoundary
|
|
202
|
-
requires={hasCellsAtom}
|
|
203
|
-
fallback={<NotStartedConnectionAlert />}
|
|
204
|
-
>
|
|
198
|
+
{/* Don't render until we have a single cell. */}
|
|
199
|
+
<ProgressiveBoundary requires={hasCellsAtom}>
|
|
205
200
|
<CellsRenderer appConfig={appConfig} mode={viewState.mode}>
|
|
206
201
|
{editableCellsArray}
|
|
207
202
|
</CellsRenderer>
|
|
@@ -30,9 +30,6 @@ const toast = vi.fn();
|
|
|
30
30
|
vi.mock("@/components/ui/use-toast", () => ({
|
|
31
31
|
toast: (...args: unknown[]) => toast(...args),
|
|
32
32
|
}));
|
|
33
|
-
vi.mock("@/core/runtime/config", () => ({
|
|
34
|
-
startRuntimeIfLazy: async () => undefined,
|
|
35
|
-
}));
|
|
36
33
|
|
|
37
34
|
const C1 = cellId("c1");
|
|
38
35
|
const C2 = cellId("c2");
|
|
@@ -22,7 +22,7 @@ export {
|
|
|
22
22
|
} from "./atoms";
|
|
23
23
|
export type { CellFreshness, CellFreshnessLookup } from "./freshness";
|
|
24
24
|
export { replyInput } from "./input";
|
|
25
|
-
export { runCells, syncEdits
|
|
25
|
+
export { runCells, syncEdits } from "./run";
|
|
26
26
|
export {
|
|
27
27
|
useCellExecution,
|
|
28
28
|
useCellFreshness,
|
|
@@ -6,7 +6,6 @@ import type * as Protocol from "@marimo-team/client/protocol";
|
|
|
6
6
|
import type { createStore } from "jotai";
|
|
7
7
|
import type { DocumentModel } from "@/core/notebook/document";
|
|
8
8
|
import { toast } from "@/components/ui/use-toast";
|
|
9
|
-
import { startRuntimeIfLazy } from "@/core/runtime/config";
|
|
10
9
|
import { activeDocumentModelAtom } from "@/core/session/active-notebook";
|
|
11
10
|
import { prettyError } from "@/utils/errors";
|
|
12
11
|
import { Logger } from "@/utils/Logger";
|
|
@@ -20,18 +19,6 @@ import {
|
|
|
20
19
|
|
|
21
20
|
type Store = ReturnType<typeof createStore>;
|
|
22
21
|
|
|
23
|
-
/**
|
|
24
|
-
* Start a lazy runtime and wait until the host reports it running.
|
|
25
|
-
*
|
|
26
|
-
* The host refuses a run while its runtime is not running, so a request
|
|
27
|
-
* made during startup waits here instead of failing. It rejects once the
|
|
28
|
-
* runtime cannot come up, so the request is not left waiting.
|
|
29
|
-
*/
|
|
30
|
-
export async function waitForRuntime(store: Store): Promise<void> {
|
|
31
|
-
await startRuntimeIfLazy();
|
|
32
|
-
await waitForRuntimeRunning(store);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
22
|
/**
|
|
36
23
|
* Get this browser's edits to the host before a command that names cells.
|
|
37
24
|
*
|
|
@@ -69,7 +56,7 @@ export async function runCells(
|
|
|
69
56
|
// notebook, has been seen.
|
|
70
57
|
let request = requestRun(store, cellIds);
|
|
71
58
|
try {
|
|
72
|
-
await
|
|
59
|
+
await waitForRuntimeRunning(store);
|
|
73
60
|
request ??= requestRun(store, cellIds);
|
|
74
61
|
if (request === null) {
|
|
75
62
|
throw new Error("No notebook is shown");
|
|
@@ -4,16 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
6
|
import * as apiModule from "../api";
|
|
7
|
-
import { visibleForTesting } from "../requests-lazy";
|
|
8
7
|
import { createNetworkRequests } from "../requests-network";
|
|
9
8
|
|
|
10
|
-
const { ACTIONS } = visibleForTesting;
|
|
11
|
-
|
|
12
9
|
// Mock dependencies
|
|
13
10
|
vi.mock("../../runtime/config", () => ({
|
|
14
11
|
getRuntimeManager: vi.fn(() => ({
|
|
15
12
|
sessionHeaders: vi.fn(() => ({ "X-Test-Header": "test" })),
|
|
16
|
-
isLazy: true,
|
|
17
13
|
})),
|
|
18
14
|
}));
|
|
19
15
|
|
|
@@ -64,18 +60,6 @@ describe("createNetworkRequests", () => {
|
|
|
64
60
|
);
|
|
65
61
|
});
|
|
66
62
|
|
|
67
|
-
it("all request methods have an action defined", () => {
|
|
68
|
-
const requests = createNetworkRequests();
|
|
69
|
-
const methodNames = Object.keys(requests);
|
|
70
|
-
|
|
71
|
-
for (const methodName of methodNames) {
|
|
72
|
-
expect(
|
|
73
|
-
ACTIONS[methodName as keyof typeof ACTIONS],
|
|
74
|
-
`Method ${methodName} has no action defined`,
|
|
75
|
-
).toBeDefined();
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
|
|
79
63
|
describe("special behavior", () => {
|
|
80
64
|
it("exportAsHTML should set assetUrl in dev/test mode", async () => {
|
|
81
65
|
const originalEnv = process.env.NODE_ENV;
|
|
@@ -75,8 +75,3 @@ export const isClosedAtom = atom((get) => {
|
|
|
75
75
|
const connection = get(connectionAtom);
|
|
76
76
|
return connection.state === ConnectionState.CLOSED;
|
|
77
77
|
});
|
|
78
|
-
|
|
79
|
-
export const isNotStartedAtom = atom((get) => {
|
|
80
|
-
const connection = get(connectionAtom);
|
|
81
|
-
return connection.state === ConnectionState.NOT_STARTED;
|
|
82
|
-
});
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
/* oxlint-disable typescript/no-explicit-any */
|
|
3
3
|
|
|
4
|
-
import { useAtomValue } from "jotai";
|
|
5
|
-
import { Spinner } from "@/components/icons/spinner";
|
|
6
|
-
import { Button } from "@/components/ui/button";
|
|
7
4
|
import { toast } from "@/components/ui/use-toast";
|
|
8
|
-
import { HTTPError,
|
|
5
|
+
import { HTTPError, prettyError } from "@/utils/errors";
|
|
9
6
|
import { Logger } from "@/utils/Logger";
|
|
10
|
-
import { useConnectToRuntime } from "../runtime/config";
|
|
11
|
-
import { store } from "../state/jotai";
|
|
12
|
-
import { isConnectingAtom } from "./connection";
|
|
13
7
|
import type { EditRequests, RequestKey, RunRequests } from "./types";
|
|
14
8
|
|
|
15
9
|
export function createErrorToastingRequests(
|
|
@@ -95,26 +89,6 @@ export function createErrorToastingRequests(
|
|
|
95
89
|
try {
|
|
96
90
|
return await handler(...args);
|
|
97
91
|
} catch (error) {
|
|
98
|
-
// Special handling for NoKernelConnectedError error
|
|
99
|
-
if (error instanceof NoKernelConnectedError) {
|
|
100
|
-
// If we are connecting to a kernel, don't show the toast
|
|
101
|
-
const isConnecting = store.get(isConnectingAtom);
|
|
102
|
-
if (isConnecting) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const toastId = toast({
|
|
107
|
-
title: "Kernel Not Connected",
|
|
108
|
-
description:
|
|
109
|
-
"You need to connect to a kernel to perform this action.",
|
|
110
|
-
variant: "default",
|
|
111
|
-
action: <ConnectButton onConnect={() => toastId.dismiss()} />,
|
|
112
|
-
});
|
|
113
|
-
Logger.error(`Failed to handle request: ${key}`, error);
|
|
114
|
-
// Rethrow the error so that the caller can handle it
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
92
|
// A capability 403: the connection is read-only for this action. The
|
|
119
93
|
// live capability notification already moved the UI to viewer state,
|
|
120
94
|
// so don't alarm the user with an error toast.
|
|
@@ -141,25 +115,3 @@ export function createErrorToastingRequests(
|
|
|
141
115
|
|
|
142
116
|
return handlers;
|
|
143
117
|
}
|
|
144
|
-
|
|
145
|
-
export const ConnectButton: React.FC<{ onConnect: () => void }> = ({
|
|
146
|
-
onConnect,
|
|
147
|
-
}) => {
|
|
148
|
-
const connectToRuntime = useConnectToRuntime();
|
|
149
|
-
const isConnecting = useAtomValue(isConnectingAtom);
|
|
150
|
-
return (
|
|
151
|
-
<Button
|
|
152
|
-
size="xs"
|
|
153
|
-
onClick={() => {
|
|
154
|
-
connectToRuntime();
|
|
155
|
-
setTimeout(() => {
|
|
156
|
-
onConnect();
|
|
157
|
-
}, 800);
|
|
158
|
-
}}
|
|
159
|
-
disabled={isConnecting}
|
|
160
|
-
>
|
|
161
|
-
{isConnecting && <Spinner size="small" className="mr-1" />}
|
|
162
|
-
Connect
|
|
163
|
-
</Button>
|
|
164
|
-
);
|
|
165
|
-
};
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import { withPackageInvalidation } from "../packages/package-data";
|
|
3
|
-
import { getRuntimeManager } from "../runtime/config";
|
|
4
3
|
import { isStaticNotebook } from "../static/static-state";
|
|
5
4
|
import { PyodideBridge } from "../wasm/bridge";
|
|
6
5
|
import { isWasm } from "../wasm/utils";
|
|
7
|
-
import { createLazyRequests } from "./requests-lazy";
|
|
8
6
|
import { createNetworkRequests } from "./requests-network";
|
|
9
7
|
import { createStaticRequests } from "./requests-static";
|
|
10
8
|
import { createErrorToastingRequests } from "./requests-toasting";
|
|
@@ -17,9 +15,7 @@ export function resolveRequestClient(): EditRequests & RunRequests {
|
|
|
17
15
|
} else if (isStaticNotebook()) {
|
|
18
16
|
base = createStaticRequests();
|
|
19
17
|
} else {
|
|
20
|
-
base =
|
|
21
|
-
getRuntimeManager(),
|
|
22
|
-
);
|
|
18
|
+
base = createNetworkRequests();
|
|
23
19
|
}
|
|
24
20
|
return withPackageInvalidation(createErrorToastingRequests(base));
|
|
25
21
|
}
|