@marimo-team/islands 0.23.6-dev30 → 0.23.6-dev32
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/{chat-ui-M5YTKtUS.js → chat-ui-BbKzQxV1.js} +2 -2
- package/dist/{code-visibility-DeEP5EQR.js → code-visibility-CyBvO931.js} +2 -2
- package/dist/{html-to-image-CH84rWtl.js → html-to-image-Gawx981h.js} +1 -1
- package/dist/main.js +5 -5
- package/dist/{process-output-BDGfLHfB.js → process-output-CmYK3dvZ.js} +1 -1
- package/dist/{reveal-component-DoErMqfp.js → reveal-component-_FaJp0v-.js} +2 -2
- package/package.json +1 -1
- package/src/components/editor/chrome/wrapper/footer-items/pyodide-status.tsx +47 -0
- package/src/components/editor/chrome/wrapper/footer.tsx +2 -0
- package/src/core/codemirror/markdown/__tests__/commands.test.ts +36 -0
- package/src/core/codemirror/markdown/commands.ts +4 -1
- package/src/core/run-app.tsx +9 -2
- package/src/core/wasm/PyodideLoader.tsx +54 -16
- package/src/core/wasm/__tests__/PyodideLoader.test.ts +72 -0
- package/src/core/wasm/bridge.ts +6 -2
- package/src/core/wasm/state.ts +3 -0
|
@@ -6,13 +6,13 @@ import { _ as Logger, c as Objects, g as cn, l as useEventListener, t as Button
|
|
|
6
6
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
7
7
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
8
8
|
import { r as toast } from "./copy-TGGAUEWp.js";
|
|
9
|
-
import { C as AccordionContent, D as ChatBubbleIcon, En as Trash2, Ft as jotaiJsonStorage, G as cellErrorsAtom, Ht as allTablesAtom, It as variablesAtom, Kt as getRequestClient, Lt as PluralWord, Nn as Info, Ot as moveToEndOfEditor, P as base64ToDataURL, Rn as CircleX, S as Accordion, T as AccordionTrigger, Tn as Wrench, Tt as createVariableInfoElement, Ut as dataSourceConnectionsAtom, V as renderHTML, Wt as getTableType, Xt as singleFacet, Y as notebookAtom, _ as Boosts, _n as atomWithStorage, b as AIContextProvider, c as Popover, d as PopoverTrigger, f as isOutputEmpty, h as DatasourceContextProvider, jn as LoaderCircle, n as MarkdownRenderer, on as CellOutputId, s as Spinner, t as toPng, tn as ZodLocalStorage, u as PopoverContent, v as Sections, vt as displayCellName, w as AccordionItem, x as AIContextRegistry, y as contextToXml, yn as Anchor2 } from "./html-to-image-
|
|
9
|
+
import { C as AccordionContent, D as ChatBubbleIcon, En as Trash2, Ft as jotaiJsonStorage, G as cellErrorsAtom, Ht as allTablesAtom, It as variablesAtom, Kt as getRequestClient, Lt as PluralWord, Nn as Info, Ot as moveToEndOfEditor, P as base64ToDataURL, Rn as CircleX, S as Accordion, T as AccordionTrigger, Tn as Wrench, Tt as createVariableInfoElement, Ut as dataSourceConnectionsAtom, V as renderHTML, Wt as getTableType, Xt as singleFacet, Y as notebookAtom, _ as Boosts, _n as atomWithStorage, b as AIContextProvider, c as Popover, d as PopoverTrigger, f as isOutputEmpty, h as DatasourceContextProvider, jn as LoaderCircle, n as MarkdownRenderer, on as CellOutputId, s as Spinner, t as toPng, tn as ZodLocalStorage, u as PopoverContent, v as Sections, vt as displayCellName, w as AccordionItem, x as AIContextRegistry, y as contextToXml, yn as Anchor2 } from "./html-to-image-Gawx981h.js";
|
|
10
10
|
import "./chunk-5FQGJX7Z-CO1e63h_.js";
|
|
11
11
|
import { u as createLucideIcon } from "./dist-ESg7xyoD.js";
|
|
12
12
|
import { F as X, S as logNever, t as Strings } from "./strings-B_FOH6eV.js";
|
|
13
13
|
import { a as NumberField, b as DropdownMenuTrigger, d as DropdownMenuContent, p as DropdownMenuItem, r as Input, u as DropdownMenu } from "./input-BAOe64zx.js";
|
|
14
14
|
import { v as CircleQuestionMark } from "./toDate-CGmcCn8J.js";
|
|
15
|
-
import { a as MarimoIncomingMessageEvent, d as File$1, n as blobToString, t as processOutput, u as deserializeBlob } from "./process-output-
|
|
15
|
+
import { a as MarimoIncomingMessageEvent, d as File$1, n as blobToString, t as processOutput, u as deserializeBlob } from "./process-output-CmYK3dvZ.js";
|
|
16
16
|
import "./react-dom-BWRJ_g_k.js";
|
|
17
17
|
import { t as require_jsx_runtime } from "./jsx-runtime-COBk7ree.js";
|
|
18
18
|
import { B as union, C as any, D as discriminatedUnion, E as custom, H as safeParseAsync, I as record, L as strictObject, M as never, N as number, O as lazy, P as object$1, R as string, S as _null, T as boolean, V as unknown, W as toJSONSchema, b as _enum, k as literal, w as array$1, x as _instanceof } from "./zod-BxdsqRPd.js";
|
|
@@ -6,7 +6,7 @@ import { _ as Logger, c as Objects, g as cn, h as Events, m as useComposedRefs,
|
|
|
6
6
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
7
7
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
8
8
|
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-TGGAUEWp.js";
|
|
9
|
-
import { $ as useCellActions, $t as getTracebackInfo, A as ChevronRightIcon, An as Minus, Bn as Braces, C as AccordionContent, En as Trash2, Ft as jotaiJsonStorage, Hn as import_lib, I as base64ToUint8Array, Jt as useRequestClient, Kt as getRequestClient, Lt as PluralWord, M as PinLeftIcon, Mt as useChromeActions, N as PinRightIcon, O as CheckIcon, Pn as FileText, Pt as adaptForLocalStorage, Qt as extractAllTracebackInfo, R as extractBase64FromDataURL, Rn as CircleX, S as Accordion, St as Checkbox, T as AccordionTrigger, Tn as Wrench, V as renderHTML, Vn as esm_default, Y as notebookAtom, Zt as elementContainsMarimoCellFile, _n as atomWithStorage, _t as getCellDomProps, at as AnsiUp, bn as Close$1, c as Popover, cn as SCRATCH_CELL_ID, ct as kioskModeAtom, d as PopoverTrigger, dt as outputIsLoading, et as useCellIds, g as getDatasourceContext, gt as DATA_CELL_ID, hn as jsonToTSV, ht as sanitizeHtml, j as DotFilledIcon, jn as LoaderCircle, kn as NotebookPen, kt as goToCellLine, l as PopoverClose$1, lt as useInstallAllowed, m as useExpandedOutput, mn as jsonToMarkdown, n as MarkdownRenderer, nn as filenameAtom, on as CellOutputId, pn as jsonParseWithSpecialChar, q as getCellEditorView, s as Spinner, sn as HTMLCellId, t as toPng, tt as useCellNames, u as PopoverContent, ut as viewStateAtom, vt as displayCellName, w as AccordionItem, z as isDataURLString, zt as DATA_TYPE_ICON, __tla as __tla_0 } from "./html-to-image-
|
|
9
|
+
import { $ as useCellActions, $t as getTracebackInfo, A as ChevronRightIcon, An as Minus, Bn as Braces, C as AccordionContent, En as Trash2, Ft as jotaiJsonStorage, Hn as import_lib, I as base64ToUint8Array, Jt as useRequestClient, Kt as getRequestClient, Lt as PluralWord, M as PinLeftIcon, Mt as useChromeActions, N as PinRightIcon, O as CheckIcon, Pn as FileText, Pt as adaptForLocalStorage, Qt as extractAllTracebackInfo, R as extractBase64FromDataURL, Rn as CircleX, S as Accordion, St as Checkbox, T as AccordionTrigger, Tn as Wrench, V as renderHTML, Vn as esm_default, Y as notebookAtom, Zt as elementContainsMarimoCellFile, _n as atomWithStorage, _t as getCellDomProps, at as AnsiUp, bn as Close$1, c as Popover, cn as SCRATCH_CELL_ID, ct as kioskModeAtom, d as PopoverTrigger, dt as outputIsLoading, et as useCellIds, g as getDatasourceContext, gt as DATA_CELL_ID, hn as jsonToTSV, ht as sanitizeHtml, j as DotFilledIcon, jn as LoaderCircle, kn as NotebookPen, kt as goToCellLine, l as PopoverClose$1, lt as useInstallAllowed, m as useExpandedOutput, mn as jsonToMarkdown, n as MarkdownRenderer, nn as filenameAtom, on as CellOutputId, pn as jsonParseWithSpecialChar, q as getCellEditorView, s as Spinner, sn as HTMLCellId, t as toPng, tt as useCellNames, u as PopoverContent, ut as viewStateAtom, vt as displayCellName, w as AccordionItem, z as isDataURLString, zt as DATA_TYPE_ICON, __tla as __tla_0 } from "./html-to-image-Gawx981h.js";
|
|
10
10
|
import { o as useSize, u as createLucideIcon } from "./dist-ESg7xyoD.js";
|
|
11
11
|
import { i as createReducerAndAtoms, r as Badge } from "./useLifecycle-CjMjllqy.js";
|
|
12
12
|
import { a as ListFilter, i as Table$1, o as ChartPie, t as $896ba0a80a8f4d36$export$85fd5fdf27bacc79 } from "./useDateFormatter-B3mCQMP3.js";
|
|
@@ -25507,7 +25507,7 @@ ${_}`,
|
|
|
25507
25507
|
return Logger.warn("Failed to get version from mount config"), null;
|
|
25508
25508
|
}
|
|
25509
25509
|
}
|
|
25510
|
-
marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.6-
|
|
25510
|
+
marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.6-dev32");
|
|
25511
25511
|
showCodeInRunModeAtom = atom(true);
|
|
25512
25512
|
atom(null);
|
|
25513
25513
|
var import_compiler_runtime = require_compiler_runtime();
|
|
@@ -20682,7 +20682,7 @@ ${n.sqlString}
|
|
|
20682
20682
|
name: n2,
|
|
20683
20683
|
contents: e2
|
|
20684
20684
|
});
|
|
20685
|
-
c.success ? (i = (_a2 = c.info) == null ? void 0 : _a2.path, i && o2 && i.startsWith(o2) && (i = Paths.rest(i, o2)), toast({
|
|
20685
|
+
c.success ? (i = (_a2 = c.info) == null ? void 0 : _a2.path, i && o2 && i.startsWith(o2) && (i = Paths.rest(i, o2).replaceAll("\\", "/")), toast({
|
|
20686
20686
|
title: "Image uploaded successfully",
|
|
20687
20687
|
description: `We've uploaded your image at ${i}`
|
|
20688
20688
|
})) : toast({
|
package/dist/main.js
CHANGED
|
@@ -22,18 +22,18 @@ import { _ as Logger, c as Objects, g as cn, h as Events, i as NOT_SET, l as use
|
|
|
22
22
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
23
23
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
24
24
|
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-TGGAUEWp.js";
|
|
25
|
-
import { $ as useCellActions, At as DeferredRequestRegistry, B as safeExtractSetUIElementMessageBuffers, Bn as Braces, Bt as getDataTypeColor, C as AccordionContent, Cn as Root2$1, Ct as customPythonLanguageSupport, Dn as Table2, Dt as Paths, E as BorderAllIcon, En as Trash2, Et as PathBuilder, F as base64ToDataView, Fn as Eye, Ft as jotaiJsonStorage, Gt as convertStatsName, H as getMarimoExportContext, In as Database, J as getCellNames, Jt as useRequestClient, K as createActions, Kt as getRequestClient, L as dataViewToBase64, Ln as Columns2, Mn as Layers, Nn as Info, Nt as repl, On as PaintRoller, Pn as FileText, Q as reducer, Rt as PluralWords, S as Accordion, Sn as Item$1, St as Checkbox, T as AccordionTrigger, U as hasTrustedExportContext, V as renderHTML, Vt as require_client, W as hasRunAnyCellAtom, X as notebookOutline, Y as notebookAtom, Yt as isUninstantiated, Z as numColumnsAtom, _n as atomWithStorage, a as useLastFocusedCellId, an as parseInitialValue, bt as isInternalCellName, ct as kioskModeAtom, dn as OBJECT_ID_ATTR, dt as outputIsLoading, en as NotebookScopedLocalStorage, et as useCellIds, f as isOutputEmpty, fn as RANDOM_ID_ATTR, ft as outputIsStale, gn as atomWithReducer, i as useCellFocusActions, in as parseDataset, jn as LoaderCircle, jt as generateUUID, k as ChevronDownIcon, ln as UIElementId, mt as headingToIdentifier, nt as createCell, o as maybeAddAltairImport, ot as getInitialAppMode, p as useExpandedConsoleOutput, pn as jsonParseWithSpecialChar, pt as isErrorMime, qt as requestClientAtom, r as LazyAnyLanguageCodeMirror, rn as parseAttrValue, s as Spinner, sn as HTMLCellId, st as initialModeAtom, un as findCellId, vn as selectAtom, w as AccordionItem, wn as Trigger2, wt as MarkdownLanguageAdapter, xn as Content2, xt as normalizeName, yt as getValidName, zn as CircleAlert, zt as DATA_TYPE_ICON, __tla as __tla_0 } from "./html-to-image-
|
|
25
|
+
import { $ as useCellActions, At as DeferredRequestRegistry, B as safeExtractSetUIElementMessageBuffers, Bn as Braces, Bt as getDataTypeColor, C as AccordionContent, Cn as Root2$1, Ct as customPythonLanguageSupport, Dn as Table2, Dt as Paths, E as BorderAllIcon, En as Trash2, Et as PathBuilder, F as base64ToDataView, Fn as Eye, Ft as jotaiJsonStorage, Gt as convertStatsName, H as getMarimoExportContext, In as Database, J as getCellNames, Jt as useRequestClient, K as createActions, Kt as getRequestClient, L as dataViewToBase64, Ln as Columns2, Mn as Layers, Nn as Info, Nt as repl, On as PaintRoller, Pn as FileText, Q as reducer, Rt as PluralWords, S as Accordion, Sn as Item$1, St as Checkbox, T as AccordionTrigger, U as hasTrustedExportContext, V as renderHTML, Vt as require_client, W as hasRunAnyCellAtom, X as notebookOutline, Y as notebookAtom, Yt as isUninstantiated, Z as numColumnsAtom, _n as atomWithStorage, a as useLastFocusedCellId, an as parseInitialValue, bt as isInternalCellName, ct as kioskModeAtom, dn as OBJECT_ID_ATTR, dt as outputIsLoading, en as NotebookScopedLocalStorage, et as useCellIds, f as isOutputEmpty, fn as RANDOM_ID_ATTR, ft as outputIsStale, gn as atomWithReducer, i as useCellFocusActions, in as parseDataset, jn as LoaderCircle, jt as generateUUID, k as ChevronDownIcon, ln as UIElementId, mt as headingToIdentifier, nt as createCell, o as maybeAddAltairImport, ot as getInitialAppMode, p as useExpandedConsoleOutput, pn as jsonParseWithSpecialChar, pt as isErrorMime, qt as requestClientAtom, r as LazyAnyLanguageCodeMirror, rn as parseAttrValue, s as Spinner, sn as HTMLCellId, st as initialModeAtom, un as findCellId, vn as selectAtom, w as AccordionItem, wn as Trigger2, wt as MarkdownLanguageAdapter, xn as Content2, xt as normalizeName, yt as getValidName, zn as CircleAlert, zt as DATA_TYPE_ICON, __tla as __tla_0 } from "./html-to-image-Gawx981h.js";
|
|
26
26
|
import { __tla as __tla_1 } from "./chunk-5FQGJX7Z-CO1e63h_.js";
|
|
27
27
|
import { o as useSize, s as Root$3, u as createLucideIcon } from "./dist-ESg7xyoD.js";
|
|
28
28
|
import { A as SquareFunction, C as DEFAULT_COLOR_SCHEME, D as SCALE_TYPE_DESCRIPTIONS, E as EMPTY_VALUE$1, O as TIME_UNIT_DESCRIPTIONS, S as DEFAULT_AGGREGATION, T as DEFAULT_TIME_UNIT, _ as AGGREGATION_TYPE_DESCRIPTIONS, a as AGGREGATION_FNS$1, b as COLOR_SCHEMES, c as COLOR_BY_FIELDS, d as NONE_VALUE, f as SELECTABLE_DATA_TYPES, g as TIME_UNITS, h as STRING_AGGREGATION_FNS, i as convertDataTypeToSelectable, j as ChartColumn, k as escapeFieldName, l as COMBINED_TIME_UNITS, m as SORT_TYPES, n as createSpecWithoutData, o as BIN_AGGREGATION, p as SINGLE_TIME_UNITS, r as isFieldSet, s as CHART_TYPES, t as augmentSpecWithData, u as ChartType, v as AGGREGATION_TYPE_ICON, w as DEFAULT_MAX_BINS_FACET, x as COUNT_FIELD, y as CHART_TYPE_ICON } from "./spec-DSIuqd3f.js";
|
|
29
|
-
import { $ as getPageIndexForRow, A as contextAwarePanelType, At as EyeOff, B as TableHead, Bt as ArrowDownWideNarrow, C as useInternalStateWithSync, Ct as RenderTextWithLinks, D as PANEL_TYPES, Dt as TextWrap, E as ContextAwarePanelItem, Et as EmotionCacheProvider, F as Fill, Ft as ChevronsUpDown, G as inferFieldTypes, H as TableRow, I as Provider$1, It as ChevronsRight, J as ColumnChartSpecModel, K as renderCellValue, L as Table, Lt as ChevronsLeft, M as SlotNames, Mt as Ellipsis, N as slotsController, Nt as Download, O as contextAwarePanelOpen, Ot as GripHorizontal, P as Toggle, Pt as Code, Q as filtersToFilterGroup, R as TableBody, Rt as ChevronsDownUp, S as prettifyRowCount, St as useOverflowDetection, T as ComboboxItem, Tt as HtmlOutput, U as NAMELESS_COLUMN_PREFIX, V as TableHeader, W as generateColumns, X as useIntersectionObserver, Y as DelayMount, Z as usePrevious$1, _ as downloadBlob, _t as TabsTrigger, at as toFieldTypes, b as Filenames, bt as ChartLoadingState, c as Slide, ct as CommandEmpty, d as JsonOutput, dt as CommandList, et as loadTableAndRawData, f as OutputArea, ft as CommandSeparator, g as ADD_PRINTING_CLASS, gt as TabsList, h as InstallPackageButton, ht as TabsContent, it as TOO_MANY_ROWS, j as isCellAwareAtom, k as contextAwarePanelOwner, kt as Funnel, l as RadioGroup, lt as CommandInput, m as DataTable, mt as Tabs, n as marimoVersionAtom, nt as INDEX_COLUMN_NAME, o as SLIDE_TYPE_OPTIONS_BY_VALUE, ot as getMimeValues, p as OutputRenderer, pt as Maps, q as ColumnChartContext, r as showCodeInRunModeAtom, rt as SELECT_COLUMN_ID, st as Command, t as useNotebookCodeAvailable, tt as loadTableData, u as RadioGroupItem, ut as CommandItem, v as downloadByURL, vt as ChartErrorState, w as Combobox, wt as Kbd, x as prettifyRowColumnCount, xt as LazyVegaEmbed, y as downloadHTMLAsImage, yt as ChartInfoState, z as TableCell, zt as ChevronLeft, __tla as __tla_2 } from "./code-visibility-
|
|
29
|
+
import { $ as getPageIndexForRow, A as contextAwarePanelType, At as EyeOff, B as TableHead, Bt as ArrowDownWideNarrow, C as useInternalStateWithSync, Ct as RenderTextWithLinks, D as PANEL_TYPES, Dt as TextWrap, E as ContextAwarePanelItem, Et as EmotionCacheProvider, F as Fill, Ft as ChevronsUpDown, G as inferFieldTypes, H as TableRow, I as Provider$1, It as ChevronsRight, J as ColumnChartSpecModel, K as renderCellValue, L as Table, Lt as ChevronsLeft, M as SlotNames, Mt as Ellipsis, N as slotsController, Nt as Download, O as contextAwarePanelOpen, Ot as GripHorizontal, P as Toggle, Pt as Code, Q as filtersToFilterGroup, R as TableBody, Rt as ChevronsDownUp, S as prettifyRowCount, St as useOverflowDetection, T as ComboboxItem, Tt as HtmlOutput, U as NAMELESS_COLUMN_PREFIX, V as TableHeader, W as generateColumns, X as useIntersectionObserver, Y as DelayMount, Z as usePrevious$1, _ as downloadBlob, _t as TabsTrigger, at as toFieldTypes, b as Filenames, bt as ChartLoadingState, c as Slide, ct as CommandEmpty, d as JsonOutput, dt as CommandList, et as loadTableAndRawData, f as OutputArea, ft as CommandSeparator, g as ADD_PRINTING_CLASS, gt as TabsList, h as InstallPackageButton, ht as TabsContent, it as TOO_MANY_ROWS, j as isCellAwareAtom, k as contextAwarePanelOwner, kt as Funnel, l as RadioGroup, lt as CommandInput, m as DataTable, mt as Tabs, n as marimoVersionAtom, nt as INDEX_COLUMN_NAME, o as SLIDE_TYPE_OPTIONS_BY_VALUE, ot as getMimeValues, p as OutputRenderer, pt as Maps, q as ColumnChartContext, r as showCodeInRunModeAtom, rt as SELECT_COLUMN_ID, st as Command, t as useNotebookCodeAvailable, tt as loadTableData, u as RadioGroupItem, ut as CommandItem, v as downloadByURL, vt as ChartErrorState, w as Combobox, wt as Kbd, x as prettifyRowColumnCount, xt as LazyVegaEmbed, y as downloadHTMLAsImage, yt as ChartInfoState, z as TableCell, zt as ChevronLeft, __tla as __tla_2 } from "./code-visibility-CyBvO931.js";
|
|
30
30
|
import { c as Calendar, i as createReducerAndAtoms, n as useOnUnmount, o as ToggleLeft, t as useOnMount } from "./useLifecycle-CjMjllqy.js";
|
|
31
31
|
import { n as $fb18d541ea1ad717$export$ad991b66133851cf, r as $5a387cc49350e6db$export$722debc0e56fea39, t as $896ba0a80a8f4d36$export$85fd5fdf27bacc79 } from "./useDateFormatter-B3mCQMP3.js";
|
|
32
32
|
import { t as Check } from "./check-CFM2mVDr.js";
|
|
33
33
|
import { A as Trigger$1, C as $a916eb452884faea$export$b7a616150fdb9f44, D as $b5e257d569688ac6$export$535bd6ca7f90a273, E as $18f2051aff69b9bf$export$a54013f0d02a8f82, F as X, L as ChevronDown, M as usePrevious$2, N as useDirection, P as createCollection, S as logNever, T as $18f2051aff69b9bf$export$43bb16f9c6d9e3f7, a as SelectGroup, c as SelectSeparator, d as NativeSelect, f as selectStyles, i as SelectContent, j as clamp$2, k as Icon, l as SelectTrigger, n as capitalize, o as SelectItem, r as Select, s as SelectLabel, t as Strings, u as SelectValue, w as $488c6ddbf4ef74c2$export$cc77c4ff7e8673c5, x as assertNever } from "./strings-B_FOH6eV.js";
|
|
34
34
|
import { $ as $e5be200c675c3b3a$export$aca958c65c314e6c, A as $d2b4bc8c273e7be6$export$24d547caef80ccd1, At as $c87311424ea30a05$export$fedb369cb70207f1, B as $64fa3d84918910a7$export$c62b8e45d58ddad9, Bt as $431fbd86ca7dc216$export$f21a1ffae260145a, C as $a049562f99e7db0e$export$eb2fcfdbd7ba97d4, Ct as $8ae05eaa5c114e9c$export$7f54fc3180508a52, D as $ee014567cb39d3f0$export$ff05c3ac10437e03, Dt as $c87311424ea30a05$export$78551043582a6a98, E as $ee014567cb39d3f0$export$f551688fc98f2e09, Et as $c87311424ea30a05$export$6446a186d09e379e, F as $64fa3d84918910a7$export$2881499e37b75b9a, Ft as $d4ee10de306f2510$export$b4f377a2b6254582, H as $64fa3d84918910a7$export$ef03459518577ad4, Ht as $bdb11010cef70236$export$b4cc09c592e8fdb8, I as $64fa3d84918910a7$export$29f1550f4b0d4415, It as $d4ee10de306f2510$export$cd4e5573fbe2b576, J as $d2e8511e6f209edf$export$e908e06f4b8e3402, K as useDebounceControlledState, L as $64fa3d84918910a7$export$4d86445c2cf5e3, Lt as $d4ee10de306f2510$export$e58f029f0fbfdb29, M as $01b77f81d0f07f68$export$75b6ee27786ba447, Mt as $65484d02dcb7eb3e$export$457c3d6518dd4c6f, N as $01b77f81d0f07f68$export$b04be29aa201d4f5, Nt as $3ef42575df84b30b$export$9d1611c77c2fe928, O as $514c0188e459b4c0$export$5f1af8db9871e1d6, Ot as $c87311424ea30a05$export$9ac100e40613ea10, P as $f39a9eba43920ace$export$b5d7cc18bb8d2b59, Pt as $d4ee10de306f2510$export$4282f70798064fe0, Q as $e5be200c675c3b3a$export$a763b9476acd3eb, R as $64fa3d84918910a7$export$9d4c57ee4c6ffdd8, Rt as $f4e2df6bd15f8569$export$98658e8c59125e6a, S as $3985021b0ad6602f$export$f5b8910cec6cf069, St as $e9faafb641e167db$export$90fc3a17d93f704c, T as $d3e0e05bdfcf66bd$export$c24727297075ec6a, Tt as $313b98861ee5dd6c$export$d6875122194c7b44, U as $64fa3d84918910a7$export$fabf2dc03a41866e, Ut as $bdb11010cef70236$export$f680877a34711e37, V as $64fa3d84918910a7$export$df3a06d6289f983e, Vt as $ff5963eb1fccf552$export$e08e3b67e392101e, Wt as $f0a04ccd8dbdd83b$export$e5c5a5f917a5871c, X as $e93e671b31057976$export$b8473d3665f3a75a, Y as $2baaea4c71418dea$export$294aa081a6c6f55d, Z as $e5be200c675c3b3a$export$75ee7c75d68f5b0e, _t as $9446cca9a3875146$export$7d15b64cf5a3a4c4, a as NumberField, at as $6c7bd7858deea686$export$cd11ab140839f11d, b as DropdownMenuTrigger, bt as $b4b717babfbb907b$export$bebd5a1431fec25d, c as prettyNumber, ct as $6db58dc88e78b024$export$2f817fcdc4b89ae0, d as DropdownMenuContent, dt as $9ab94262bd0047c7$export$420e68273165f4ec, et as $e5be200c675c3b3a$export$dad6ae84456c676a, f as DropdownMenuGroup, fn as Circle, ft as $3ad3f6e1647bc98d$export$80f3e147d781571c, g as DropdownMenuSeparator, gt as $ae1eeba8b9eafd08$export$5165eccb35aaadb5, ht as _class_private_field_init, i as OnBlurredInput, it as $701a24aa0da5b062$export$ea18c227d4417cc3, j as $d2b4bc8c273e7be6$export$353f5b6fc5456de1, jt as $7215afc6de606d6b$export$de79e2c695e052f3, k as $514c0188e459b4c0$export$9afb8bc826b033ea, kt as $c87311424ea30a05$export$a11b0059900ceec8, l as prettyScientificNumber, lt as $5b160d28a433310d$export$c17fa47878dc55b6, m as DropdownMenuLabel, mt as $f6c31cce2adf654f$export$45712eceda6fad21, n as DebouncedNumberInput, nt as $319e236875307eab$export$a9b970dcc4ae71a9, ot as $fca6afa0e843324b$export$87b761675e8eaa10, p as DropdownMenuItem, pn as ChevronRight, pt as $507fabe10e71c6fb$export$630ff653c5ada6a9, q as useDebouncedCallback, r as Input, rt as $f7dceffc5ad7768b$export$4e328f61c538687f, st as $fca6afa0e843324b$export$f12b703ca79dfbb1, t as DebouncedInput, tt as $e5be200c675c3b3a$export$fc1a364ae1f3ff10, u as DropdownMenu, ut as $6179b936705e76d3$export$ae780daf29e6d456, vt as $458b0a5536c1a7cf$export$40bfa8c7b0832715, w as $a049562f99e7db0e$export$f9c6924e160136d1, wt as $df56164dff5785e2$export$4338b53315abf666, x as $3985021b0ad6602f$export$37fb8590cf2c088c, xt as $99facab73266f662$export$5add1d006293d136, yt as $b4b717babfbb907b$export$4c063cf1350e6fed, z as $64fa3d84918910a7$export$c245e6201fed2f75, zt as $431fbd86ca7dc216$export$b204af158042fbac } from "./input-BAOe64zx.js";
|
|
35
35
|
import { _ as isWasm, c as asRemoteURL, d as isStaticNotebook, f as appendQueryParams, g as Deferred, m as require_cuid2, u as getStaticVirtualFiles, v as CircleQuestionMark } from "./toDate-CGmcCn8J.js";
|
|
36
|
-
import { a as MarimoIncomingMessageEvent, c as MarimoValueUpdateEvent, d as File, i as PythonIcon, l as createInputEvent, n as blobToString, o as MarimoValueInputEvent, r as filesToBase64, s as MarimoValueReadyEvent, t as processOutput, u as deserializeBlob } from "./process-output-
|
|
36
|
+
import { a as MarimoIncomingMessageEvent, c as MarimoValueUpdateEvent, d as File, i as PythonIcon, l as createInputEvent, n as blobToString, o as MarimoValueInputEvent, r as filesToBase64, s as MarimoValueReadyEvent, t as processOutput, u as deserializeBlob } from "./process-output-CmYK3dvZ.js";
|
|
37
37
|
import { i as Pencil, n as Trash, r as Plus, t as BulkEdit } from "./types-DBtDeUKD.js";
|
|
38
38
|
import { t as require_react_dom } from "./react-dom-BWRJ_g_k.js";
|
|
39
39
|
import { t as require_jsx_runtime } from "./jsx-runtime-COBk7ree.js";
|
|
@@ -13655,7 +13655,7 @@ Defaulting to \`null\`.`;
|
|
|
13655
13655
|
};
|
|
13656
13656
|
}
|
|
13657
13657
|
};
|
|
13658
|
-
var LazyChatbot = import_react.lazy(() => import("./chat-ui-
|
|
13658
|
+
var LazyChatbot = import_react.lazy(() => import("./chat-ui-BbKzQxV1.js").then((e) => ({
|
|
13659
13659
|
default: e.Chatbot
|
|
13660
13660
|
}))), messageSchema = array(object({
|
|
13661
13661
|
id: string(),
|
|
@@ -44649,7 +44649,7 @@ ${c}
|
|
|
44649
44649
|
if (l && l !== "slide") return l;
|
|
44650
44650
|
if (c == null ? void 0 : c.has(e)) return "skip";
|
|
44651
44651
|
}
|
|
44652
|
-
var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-
|
|
44652
|
+
var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-_FaJp0v-.js"));
|
|
44653
44653
|
const SlidesLayoutPlugin = {
|
|
44654
44654
|
type: "slides",
|
|
44655
44655
|
name: "Slides",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
3
|
-
import { it as parseHtmlContent, rt as ansiToPlainText } from "./html-to-image-
|
|
3
|
+
import { it as parseHtmlContent, rt as ansiToPlainText } from "./html-to-image-Gawx981h.js";
|
|
4
4
|
import { u as createLucideIcon } from "./dist-ESg7xyoD.js";
|
|
5
5
|
import { t as Strings } from "./strings-B_FOH6eV.js";
|
|
6
6
|
import { t as require_jsx_runtime } from "./jsx-runtime-COBk7ree.js";
|
|
@@ -6,9 +6,9 @@ import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
|
6
6
|
import { _ as Logger, g as cn, h as Events, l as useEventListener, t as Button } from "./button-CA5pI2YF.js";
|
|
7
7
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
8
8
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
9
|
-
import "./html-to-image-
|
|
9
|
+
import "./html-to-image-Gawx981h.js";
|
|
10
10
|
import "./chunk-5FQGJX7Z-CO1e63h_.js";
|
|
11
|
-
import { At as EyeOff, Pt as Code, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, jt as Expand, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-
|
|
11
|
+
import { At as EyeOff, Pt as Code, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, jt as Expand, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-CyBvO931.js";
|
|
12
12
|
import "./input-BAOe64zx.js";
|
|
13
13
|
import "./toDate-CGmcCn8J.js";
|
|
14
14
|
import "./react-dom-BWRJ_g_k.js";
|
package/package.json
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { useAtomValue } from "jotai";
|
|
4
|
+
import { AlertCircleIcon } from "lucide-react";
|
|
5
|
+
import type React from "react";
|
|
6
|
+
import { Spinner } from "@/components/icons/spinner";
|
|
7
|
+
import { Tooltip } from "@/components/ui/tooltip";
|
|
8
|
+
import { wasmInitializationAtom, wasmInitStatusAtom } from "@/core/wasm/state";
|
|
9
|
+
import { isWasm } from "@/core/wasm/utils";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Footer indicator that surfaces Pyodide initialization progress. Mirrors
|
|
13
|
+
* the "Kernel" indicator but tracks the WASM runtime instead of the server
|
|
14
|
+
* connection. Hides itself once Pyodide is ready.
|
|
15
|
+
*/
|
|
16
|
+
export const PyodideStatus: React.FC = () => {
|
|
17
|
+
const status = useAtomValue(wasmInitStatusAtom);
|
|
18
|
+
const message = useAtomValue(wasmInitializationAtom);
|
|
19
|
+
|
|
20
|
+
if (!isWasm() || status === "ready") {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const icon =
|
|
25
|
+
status === "error" ? (
|
|
26
|
+
<AlertCircleIcon className="w-4 h-4 text-destructive" />
|
|
27
|
+
) : (
|
|
28
|
+
<Spinner size="small" />
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const tooltip = status === "error" ? "Pyodide failed to initialize" : message;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Tooltip
|
|
35
|
+
content={<div className="text-sm whitespace-pre-line">{tooltip}</div>}
|
|
36
|
+
data-testid="footer-pyodide-status"
|
|
37
|
+
>
|
|
38
|
+
<div
|
|
39
|
+
className="p-1 hover:bg-accent rounded flex items-center gap-1.5 text-xs text-muted-foreground"
|
|
40
|
+
data-testid="pyodide-status"
|
|
41
|
+
>
|
|
42
|
+
{icon}
|
|
43
|
+
<span>Pyodide</span>
|
|
44
|
+
</div>
|
|
45
|
+
</Tooltip>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "./footer-items/backend-status";
|
|
19
19
|
import { CopilotStatusIcon } from "./footer-items/copilot-status";
|
|
20
20
|
import { MachineStats } from "./footer-items/machine-stats";
|
|
21
|
+
import { PyodideStatus } from "./footer-items/pyodide-status";
|
|
21
22
|
import { RTCStatus } from "./footer-items/rtc-status";
|
|
22
23
|
import { RuntimeSettings } from "./footer-items/runtime-settings";
|
|
23
24
|
import { useSetDependencyPanelTab } from "./useDependencyPanelTab";
|
|
@@ -85,6 +86,7 @@ export const Footer: React.FC = () => {
|
|
|
85
86
|
|
|
86
87
|
<div className="mx-auto" />
|
|
87
88
|
|
|
89
|
+
<PyodideStatus />
|
|
88
90
|
<ConnectingKernelIndicatorItem />
|
|
89
91
|
|
|
90
92
|
<ShowInKioskMode>
|
|
@@ -385,6 +385,42 @@ describe("insertImage", () => {
|
|
|
385
385
|
);
|
|
386
386
|
});
|
|
387
387
|
|
|
388
|
+
test("normalizes Windows backslash paths to forward slashes in image URL", async () => {
|
|
389
|
+
view = createEditor("Hello, world!");
|
|
390
|
+
view.dispatch({
|
|
391
|
+
selection: { anchor: 7, head: 7 },
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
vi.spyOn(store, "get").mockImplementation((atom) => {
|
|
395
|
+
if (atom === filenameAtom) {
|
|
396
|
+
return "C:\\Users\\user\\project\\notebook.py";
|
|
397
|
+
}
|
|
398
|
+
if (atom === requestClientAtom) {
|
|
399
|
+
return mockRequestClient;
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
mockRequestClient.sendCreateFileOrFolder.mockResolvedValueOnce({
|
|
404
|
+
success: true,
|
|
405
|
+
message: null,
|
|
406
|
+
info: {
|
|
407
|
+
path: "C:\\Users\\user\\project\\public\\hello.png",
|
|
408
|
+
name: "hello.png",
|
|
409
|
+
children: [],
|
|
410
|
+
id: "",
|
|
411
|
+
isDirectory: false,
|
|
412
|
+
isMarimoFile: false,
|
|
413
|
+
lastModified: null,
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
await insertImage(view, mockPngFile());
|
|
418
|
+
|
|
419
|
+
expect(view.state.doc.toString()).toMatchInlineSnapshot(
|
|
420
|
+
`"Hello, world!"`,
|
|
421
|
+
);
|
|
422
|
+
});
|
|
423
|
+
|
|
388
424
|
test("saves image as file different extension", async () => {
|
|
389
425
|
view = createEditor("Hello, world!");
|
|
390
426
|
view.dispatch({
|
|
@@ -360,7 +360,10 @@ export async function insertImage(view: EditorView, file: File) {
|
|
|
360
360
|
notebookDir &&
|
|
361
361
|
savedFilePath.startsWith(notebookDir)
|
|
362
362
|
) {
|
|
363
|
-
savedFilePath = Paths.rest(savedFilePath, notebookDir)
|
|
363
|
+
savedFilePath = Paths.rest(savedFilePath, notebookDir).replaceAll(
|
|
364
|
+
"\\",
|
|
365
|
+
"/",
|
|
366
|
+
);
|
|
364
367
|
}
|
|
365
368
|
|
|
366
369
|
toast({
|
package/src/core/run-app.tsx
CHANGED
|
@@ -10,7 +10,11 @@ import { buttonVariants } from "@/components/ui/button";
|
|
|
10
10
|
import { DelayMount } from "@/components/utils/delay-mount";
|
|
11
11
|
import { cn } from "@/utils/cn";
|
|
12
12
|
import { CellsRenderer } from "../components/editor/renderers/cells-renderer";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
hasCellsAtom,
|
|
15
|
+
notebookIsRunningAtom,
|
|
16
|
+
useCellActions,
|
|
17
|
+
} from "./cells/cells";
|
|
14
18
|
import type { AppConfig } from "./config/config-schema";
|
|
15
19
|
import { RuntimeState } from "./kernel/RuntimeState";
|
|
16
20
|
import { getSessionId } from "./kernel/session";
|
|
@@ -42,10 +46,13 @@ export const RunApp: React.FC<AppProps> = ({ appConfig }) => {
|
|
|
42
46
|
|
|
43
47
|
const isRunning = useAtomValue(notebookIsRunningAtom);
|
|
44
48
|
const isConnecting = isAppConnecting(connection.state);
|
|
49
|
+
// Skip the "Connecting..." gate when we already have cells to show — from
|
|
50
|
+
// an embedded snapshot or a prior connection.
|
|
51
|
+
const hasExistingCells = useAtomValue(hasCellsAtom);
|
|
45
52
|
|
|
46
53
|
const renderCells = () => {
|
|
47
54
|
// If we are connecting for more than 2 seconds, show a spinner
|
|
48
|
-
if (isConnecting) {
|
|
55
|
+
if (isConnecting && !hasExistingCells) {
|
|
49
56
|
return (
|
|
50
57
|
<DelayMount milliseconds={2000} fallback={null}>
|
|
51
58
|
<Spinner className="mx-auto" />
|
|
@@ -3,13 +3,18 @@
|
|
|
3
3
|
import { useAtomValue } from "jotai";
|
|
4
4
|
import type React from "react";
|
|
5
5
|
import type { PropsWithChildren } from "react";
|
|
6
|
+
import { useEffect, useRef } from "react";
|
|
6
7
|
import { LargeSpinner } from "@/components/icons/large-spinner";
|
|
8
|
+
import { toast } from "@/components/ui/use-toast";
|
|
9
|
+
import { hasCellsAtom } from "@/core/cells/cells";
|
|
7
10
|
import { showCodeInRunModeAtom } from "@/core/meta/state";
|
|
8
11
|
import { store } from "@/core/state/jotai";
|
|
9
12
|
import { useAsyncData } from "@/hooks/useAsyncData";
|
|
13
|
+
import { prettyError } from "@/utils/errors";
|
|
14
|
+
import { Logger } from "@/utils/Logger";
|
|
10
15
|
import { hasQueryParam } from "@/utils/urls";
|
|
11
16
|
import { KnownQueryParams } from "../constants";
|
|
12
|
-
import { getInitialAppMode } from "../mode";
|
|
17
|
+
import { type AppMode, getInitialAppMode } from "../mode";
|
|
13
18
|
import { PyodideBridge } from "./bridge";
|
|
14
19
|
import { hasAnyOutputAtom, wasmInitializationAtom } from "./state";
|
|
15
20
|
import { isWasm } from "./utils";
|
|
@@ -26,30 +31,44 @@ export const PyodideLoader: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
26
31
|
};
|
|
27
32
|
|
|
28
33
|
const PyodideLoaderInner: React.FC<PropsWithChildren> = ({ children }) => {
|
|
29
|
-
//
|
|
30
|
-
|
|
34
|
+
// Don't block render on Pyodide: a hydrated snapshot can paint immediately
|
|
35
|
+
// while Pyodide downloads in the background.
|
|
36
|
+
const { error } = useAsyncData(async () => {
|
|
31
37
|
await PyodideBridge.INSTANCE.initialized.promise;
|
|
32
38
|
return true;
|
|
33
39
|
}, []);
|
|
34
40
|
|
|
41
|
+
const hasCells = useAtomValue(hasCellsAtom);
|
|
35
42
|
const hasOutput = useAtomValue(hasAnyOutputAtom);
|
|
43
|
+
const nothingToShow = shouldShowSpinner({
|
|
44
|
+
hasCells,
|
|
45
|
+
hasOutput,
|
|
46
|
+
mode: getInitialAppMode(),
|
|
47
|
+
codeHidden: isCodeHidden(),
|
|
48
|
+
});
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
const didToastErrorRef = useRef(false);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
// With snapshot content on-screen, toast instead of throwing so the
|
|
53
|
+
// snapshot stays readable. The ref ensures we only toast once even if
|
|
54
|
+
// nothingToShow toggles later.
|
|
55
|
+
if (error && !nothingToShow && !didToastErrorRef.current) {
|
|
56
|
+
didToastErrorRef.current = true;
|
|
57
|
+
Logger.error("Pyodide failed to initialize", error);
|
|
58
|
+
toast({
|
|
59
|
+
title: "Failed to start the notebook runtime",
|
|
60
|
+
description: prettyError(error),
|
|
61
|
+
variant: "danger",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}, [error, nothingToShow]);
|
|
40
65
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// - we are not showing the code
|
|
44
|
-
// - and there is no output
|
|
45
|
-
// then show the spinner
|
|
46
|
-
if (!hasOutput && getInitialAppMode() === "read" && isCodeHidden()) {
|
|
47
|
-
return <WasmSpinner />;
|
|
66
|
+
if (error && nothingToShow) {
|
|
67
|
+
throw error;
|
|
48
68
|
}
|
|
49
69
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
throw error;
|
|
70
|
+
if (nothingToShow) {
|
|
71
|
+
return <WasmSpinner />;
|
|
53
72
|
}
|
|
54
73
|
|
|
55
74
|
return children;
|
|
@@ -65,6 +84,25 @@ function isCodeHidden() {
|
|
|
65
84
|
);
|
|
66
85
|
}
|
|
67
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Pure predicate: should the WASM loader render a spinner instead of its
|
|
89
|
+
* children? We block render only when nothing user-visible would appear:
|
|
90
|
+
* - no cells have been hydrated (Pyodide hasn't parsed the notebook), or
|
|
91
|
+
* - we are in headless run mode (code hidden) with no outputs to display.
|
|
92
|
+
*/
|
|
93
|
+
export function shouldShowSpinner(input: {
|
|
94
|
+
hasCells: boolean;
|
|
95
|
+
hasOutput: boolean;
|
|
96
|
+
mode: AppMode;
|
|
97
|
+
codeHidden: boolean;
|
|
98
|
+
}): boolean {
|
|
99
|
+
const { hasCells, hasOutput, mode, codeHidden } = input;
|
|
100
|
+
if (!hasCells) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
return !hasOutput && mode === "read" && codeHidden;
|
|
104
|
+
}
|
|
105
|
+
|
|
68
106
|
export const WasmSpinner: React.FC<PropsWithChildren> = ({ children }) => {
|
|
69
107
|
const wasmInitialization = useAtomValue(wasmInitializationAtom);
|
|
70
108
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { shouldShowSpinner } from "../PyodideLoader";
|
|
5
|
+
|
|
6
|
+
describe("shouldShowSpinner", () => {
|
|
7
|
+
it("shows the spinner when there are no cells yet (Pyodide hasn't parsed)", () => {
|
|
8
|
+
expect(
|
|
9
|
+
shouldShowSpinner({
|
|
10
|
+
hasCells: false,
|
|
11
|
+
hasOutput: false,
|
|
12
|
+
mode: "read",
|
|
13
|
+
codeHidden: false,
|
|
14
|
+
}),
|
|
15
|
+
).toBe(true);
|
|
16
|
+
|
|
17
|
+
expect(
|
|
18
|
+
shouldShowSpinner({
|
|
19
|
+
hasCells: false,
|
|
20
|
+
hasOutput: true,
|
|
21
|
+
mode: "edit",
|
|
22
|
+
codeHidden: false,
|
|
23
|
+
}),
|
|
24
|
+
).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("renders children once cells exist with code visible", () => {
|
|
28
|
+
// run mode, code visible, no outputs yet — the user can read the code
|
|
29
|
+
expect(
|
|
30
|
+
shouldShowSpinner({
|
|
31
|
+
hasCells: true,
|
|
32
|
+
hasOutput: false,
|
|
33
|
+
mode: "read",
|
|
34
|
+
codeHidden: false,
|
|
35
|
+
}),
|
|
36
|
+
).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("renders children once cells exist with cached outputs (snapshot case)", () => {
|
|
40
|
+
expect(
|
|
41
|
+
shouldShowSpinner({
|
|
42
|
+
hasCells: true,
|
|
43
|
+
hasOutput: true,
|
|
44
|
+
mode: "read",
|
|
45
|
+
codeHidden: true,
|
|
46
|
+
}),
|
|
47
|
+
).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("keeps the spinner up in headless run mode with no outputs", () => {
|
|
51
|
+
// read mode + code hidden + no outputs = nothing visible to render
|
|
52
|
+
expect(
|
|
53
|
+
shouldShowSpinner({
|
|
54
|
+
hasCells: true,
|
|
55
|
+
hasOutput: false,
|
|
56
|
+
mode: "read",
|
|
57
|
+
codeHidden: true,
|
|
58
|
+
}),
|
|
59
|
+
).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("never blocks edit mode once cells exist", () => {
|
|
63
|
+
expect(
|
|
64
|
+
shouldShowSpinner({
|
|
65
|
+
hasCells: true,
|
|
66
|
+
hasOutput: false,
|
|
67
|
+
mode: "edit",
|
|
68
|
+
codeHidden: true,
|
|
69
|
+
}),
|
|
70
|
+
).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
});
|
package/src/core/wasm/bridge.ts
CHANGED
|
@@ -37,7 +37,7 @@ import type { IConnectionTransport } from "../websocket/transports/transport";
|
|
|
37
37
|
import { PyodideRouter } from "./router";
|
|
38
38
|
import { getWorkerRPC } from "./rpc";
|
|
39
39
|
import { createShareableLink } from "./share";
|
|
40
|
-
import { wasmInitializationAtom } from "./state";
|
|
40
|
+
import { wasmInitializationAtom, wasmInitStatusAtom } from "./state";
|
|
41
41
|
import { fallbackFileStore, notebookFileStore } from "./store";
|
|
42
42
|
import { isWasm } from "./utils";
|
|
43
43
|
import type { SaveWorkerSchema } from "./worker/save-worker";
|
|
@@ -119,13 +119,15 @@ export class PyodideBridge implements RunRequests, EditRequests {
|
|
|
119
119
|
// By initializing after, we get hits on cached network requests
|
|
120
120
|
this.saveRpc = this.getSaveWorker();
|
|
121
121
|
this.setInterruptBuffer();
|
|
122
|
+
store.set(wasmInitStatusAtom, "ready");
|
|
122
123
|
this.initialized.resolve();
|
|
123
124
|
});
|
|
124
125
|
this.rpc.addMessageListener("initializingMessage", ({ message }) => {
|
|
125
126
|
store.set(wasmInitializationAtom, message);
|
|
126
127
|
});
|
|
127
128
|
this.rpc.addMessageListener("initializedError", ({ error }) => {
|
|
128
|
-
// If already
|
|
129
|
+
// If already initialized, surface as a toast and leave the deferred /
|
|
130
|
+
// init status alone — the worker is healthy, this is a runtime error.
|
|
129
131
|
if (this.initialized.status === "resolved") {
|
|
130
132
|
Logger.error(error);
|
|
131
133
|
toast({
|
|
@@ -133,7 +135,9 @@ export class PyodideBridge implements RunRequests, EditRequests {
|
|
|
133
135
|
description: error,
|
|
134
136
|
variant: "danger",
|
|
135
137
|
});
|
|
138
|
+
return;
|
|
136
139
|
}
|
|
140
|
+
store.set(wasmInitStatusAtom, "error");
|
|
137
141
|
this.initialized.reject(new Error(error));
|
|
138
142
|
});
|
|
139
143
|
this.rpc.addMessageListener("kernelMessage", ({ message }) => {
|
package/src/core/wasm/state.ts
CHANGED
|
@@ -5,6 +5,9 @@ import { isOutputEmpty } from "../cells/outputs";
|
|
|
5
5
|
|
|
6
6
|
export const wasmInitializationAtom = atom<string>("Initializing...");
|
|
7
7
|
|
|
8
|
+
export type WasmInitStatus = "loading" | "ready" | "error";
|
|
9
|
+
export const wasmInitStatusAtom = atom<WasmInitStatus>("loading");
|
|
10
|
+
|
|
8
11
|
export const hasAnyOutputAtom = atom<boolean>((get) => {
|
|
9
12
|
const notebook = get(notebookAtom);
|
|
10
13
|
const runtimeStates = Object.values(notebook.cellRuntime);
|