@marimo-team/islands 0.23.2-dev24 → 0.23.2-dev27

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.
@@ -6,7 +6,7 @@ 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-Bp6CK_Fg.js";
9
- import { A as MarimoIncomingMessageEvent, An as Trash2, Bt as variablesAtom, C as contextToXml, Cn as Anchor2, D as AccordionContent, E as Accordion, Hn as CircleX, I as ChatBubbleIcon, In as Info, Jt as getTableType, Kt as allTablesAtom, Ln as File$1, Mt as moveToEndOfEditor, O as AccordionItem, Pn as LoaderCircle, Q as cellErrorsAtom, S as Sections, St as displayCellName, T as AIContextRegistry, U as deserializeBlob, Vt as PluralWord, W as base64ToDataURL, Xt as getRequestClient, Z as renderHTML, a as toPng, an as ZodLocalStorage, d as Spinner, en as singleFacet, f as Popover, g as isOutputEmpty, h as PopoverTrigger, k as AccordionTrigger, kn as Wrench, kt as createVariableInfoElement, m as PopoverContent, n as blobToString, nt as notebookAtom, o as MarkdownRenderer, qt as dataSourceConnectionsAtom, t as processOutput, un as CellOutputId, w as AIContextProvider, x as Boosts, xn as atomWithStorage, y as DatasourceContextProvider, zt as jotaiJsonStorage } from "./process-output-BM9cXHzx.js";
9
+ import { A as MarimoIncomingMessageEvent, An as Trash2, Bt as variablesAtom, C as contextToXml, Cn as Anchor2, D as AccordionContent, E as Accordion, Hn as CircleX, I as ChatBubbleIcon, In as Info, Jt as getTableType, Kt as allTablesAtom, Ln as File$1, Mt as moveToEndOfEditor, O as AccordionItem, Pn as LoaderCircle, Q as cellErrorsAtom, S as Sections, St as displayCellName, T as AIContextRegistry, U as deserializeBlob, Vt as PluralWord, W as base64ToDataURL, Xt as getRequestClient, Z as renderHTML, a as toPng, an as ZodLocalStorage, d as Spinner, en as singleFacet, f as Popover, g as isOutputEmpty, h as PopoverTrigger, k as AccordionTrigger, kn as Wrench, kt as createVariableInfoElement, m as PopoverContent, n as blobToString, nt as notebookAtom, o as MarkdownRenderer, qt as dataSourceConnectionsAtom, t as processOutput, un as CellOutputId, w as AIContextProvider, x as Boosts, xn as atomWithStorage, y as DatasourceContextProvider, zt as jotaiJsonStorage } from "./process-output-CzeGyEyz.js";
10
10
  import "./chunk-5FQGJX7Z-VIref9gx.js";
11
11
  import { u as createLucideIcon } from "./dist-CTtLBPLZ.js";
12
12
  import { C as logNever, I as X, n as Strings, t as Label } from "./label-BebYlsDV.js";
package/dist/main.js CHANGED
@@ -22,7 +22,7 @@ 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-Bp6CK_Fg.js";
25
- import { $ as createActions, $t as isUninstantiated, A as MarimoIncomingMessageEvent, An as Trash2, At as PathBuilder, B as DotFilledIcon, Bn as Database, Ct as getValidName, D as AccordionContent, Dn as Root2$4, Dt as customPythonLanguageSupport, E as Accordion, En as Item$1, Et as Checkbox, F as BorderAllIcon, Fn as Layers, Ft as generateUUID, G as base64ToDataView, Gn as esm_default$1, Gt as require_client, H as PinRightIcon, Hn as CircleX, Ht as PluralWords, In as Info, It as useChromeActions, J as extractBase64FromDataURL, K as base64ToUint8Array, Kn as import_lib, L as CheckIcon, Ln as File, Lt as repl, M as MarimoValueReadyEvent, Mn as PaintRoller, N as MarimoValueUpdateEvent, Nn as NotebookPen, Nt as goToCellLine, O as AccordionItem, On as Trigger2, Ot as MarkdownLanguageAdapter, P as createInputEvent, Pn as LoaderCircle, Pt as DeferredRequestRegistry, Qt as useRequestClient, R as ChevronDownIcon, Rn as FileText, Rt as adaptForLocalStorage, Sn as selectAtom, St as displayCellName, Tn as Content2$1, Tt as normalizeName, U as deserializeBlob, Un as CircleAlert, Ut as DATA_TYPE_ICON, V as PinLeftIcon, Vn as Columns2, Vt as PluralWord, Wn as Braces, Wt as getDataTypeColor, X as safeExtractSetUIElementMessageBuffers, Xt as getRequestClient, Y as isDataURLString, Yt as convertStatsName, Z as renderHTML, Zt as requestClientAtom, _ as useExpandedConsoleOutput, _n as jsonParseWithSpecialChar, _t as isErrorMime, a as toPng, at as reducer, b as getDatasourceContext, bn as atomWithReducer, bt as DATA_CELL_ID, c as useCellFocusActions, cn as parseDataset, ct as useCellNames, d as Spinner, dn as HTMLCellId, dt as getInitialAppMode, et as getCellEditorView, f as Popover$1, fn as SCRATCH_CELL_ID, ft as initialModeAtom, g as isOutputEmpty, gn as RANDOM_ID_ATTR, gt as outputIsStale, h as PopoverTrigger, hn as OBJECT_ID_ATTR, ht as outputIsLoading, i as PythonIcon, in as NotebookScopedLocalStorage, it as numColumnsAtom, j as MarimoValueInputEvent, jn as Table2, jt as Paths, k as AccordionTrigger, kn as Wrench, l as useLastFocusedCellId, ln as parseInitialValue, lt as createCell, m as PopoverContent, mn as findCellId, mt as viewStateAtom, n as blobToString, nn as extractAllTracebackInfo, nt as notebookAtom, o as MarkdownRenderer, on as filenameAtom, ot as useCellActions, p as PopoverClose$1, pn as UIElementId, pt as kioskModeAtom, q as dataViewToBase64, r as filesToBase64, rn as getTracebackInfo, rt as notebookOutline, s as LazyAnyLanguageCodeMirror, sn as parseAttrValue, st as useCellIds, t as processOutput, tn as elementContainsMarimoCellFile, tt as getCellNames, u as maybeAddAltairImport, un as CellOutputId, ut as AnsiUp, v as useExpandedOutput, vn as jsonToMarkdown, vt as headingToIdentifier, wn as Close$1, wt as isInternalCellName, xn as atomWithStorage, xt as getCellDomProps, yn as jsonToTSV, yt as sanitizeHtml, z as ChevronRightIcon, zn as Eye, zt as jotaiJsonStorage, __tla as __tla_0 } from "./process-output-BM9cXHzx.js";
25
+ import { $ as createActions, $t as isUninstantiated, A as MarimoIncomingMessageEvent, An as Trash2, At as PathBuilder, B as DotFilledIcon, Bn as Database, Ct as getValidName, D as AccordionContent, Dn as Root2$4, Dt as customPythonLanguageSupport, E as Accordion, En as Item$1, Et as Checkbox, F as BorderAllIcon, Fn as Layers, Ft as generateUUID, G as base64ToDataView, Gn as esm_default$1, Gt as require_client, H as PinRightIcon, Hn as CircleX, Ht as PluralWords, In as Info, It as useChromeActions, J as extractBase64FromDataURL, K as base64ToUint8Array, Kn as import_lib, L as CheckIcon, Ln as File, Lt as repl, M as MarimoValueReadyEvent, Mn as PaintRoller, N as MarimoValueUpdateEvent, Nn as NotebookPen, Nt as goToCellLine, O as AccordionItem, On as Trigger2, Ot as MarkdownLanguageAdapter, P as createInputEvent, Pn as LoaderCircle, Pt as DeferredRequestRegistry, Qt as useRequestClient, R as ChevronDownIcon, Rn as FileText, Rt as adaptForLocalStorage, Sn as selectAtom, St as displayCellName, Tn as Content2$1, Tt as normalizeName, U as deserializeBlob, Un as CircleAlert, Ut as DATA_TYPE_ICON, V as PinLeftIcon, Vn as Columns2, Vt as PluralWord, Wn as Braces, Wt as getDataTypeColor, X as safeExtractSetUIElementMessageBuffers, Xt as getRequestClient, Y as isDataURLString, Yt as convertStatsName, Z as renderHTML, Zt as requestClientAtom, _ as useExpandedConsoleOutput, _n as jsonParseWithSpecialChar, _t as isErrorMime, a as toPng, at as reducer, b as getDatasourceContext, bn as atomWithReducer, bt as DATA_CELL_ID, c as useCellFocusActions, cn as parseDataset, ct as useCellNames, d as Spinner, dn as HTMLCellId, dt as getInitialAppMode, et as getCellEditorView, f as Popover$1, fn as SCRATCH_CELL_ID, ft as initialModeAtom, g as isOutputEmpty, gn as RANDOM_ID_ATTR, gt as outputIsStale, h as PopoverTrigger, hn as OBJECT_ID_ATTR, ht as outputIsLoading, i as PythonIcon, in as NotebookScopedLocalStorage, it as numColumnsAtom, j as MarimoValueInputEvent, jn as Table2, jt as Paths, k as AccordionTrigger, kn as Wrench, l as useLastFocusedCellId, ln as parseInitialValue, lt as createCell, m as PopoverContent, mn as findCellId, mt as viewStateAtom, n as blobToString, nn as extractAllTracebackInfo, nt as notebookAtom, o as MarkdownRenderer, on as filenameAtom, ot as useCellActions, p as PopoverClose$1, pn as UIElementId, pt as kioskModeAtom, q as dataViewToBase64, r as filesToBase64, rn as getTracebackInfo, rt as notebookOutline, s as LazyAnyLanguageCodeMirror, sn as parseAttrValue, st as useCellIds, t as processOutput, tn as elementContainsMarimoCellFile, tt as getCellNames, u as maybeAddAltairImport, un as CellOutputId, ut as AnsiUp, v as useExpandedOutput, vn as jsonToMarkdown, vt as headingToIdentifier, wn as Close$1, wt as isInternalCellName, xn as atomWithStorage, xt as getCellDomProps, yn as jsonToTSV, yt as sanitizeHtml, z as ChevronRightIcon, zn as Eye, zt as jotaiJsonStorage, __tla as __tla_0 } from "./process-output-CzeGyEyz.js";
26
26
  import { __tla as __tla_1 } from "./chunk-5FQGJX7Z-VIref9gx.js";
27
27
  import { o as useSize, s as Root$4, u as createLucideIcon } from "./dist-CTtLBPLZ.js";
28
28
  import { A as $896ba0a80a8f4d36$export$85fd5fdf27bacc79, C as DEFAULT_COLOR_SCHEME, D as SCALE_TYPE_DESCRIPTIONS, E as EMPTY_VALUE$1, F as ListFilter, I as ChartPie, L as ChartColumn, M as $5a387cc49350e6db$export$722debc0e56fea39, N as Table$1, O as TIME_UNIT_DESCRIPTIONS, P as SquareFunction, 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 $fb18d541ea1ad717$export$ad991b66133851cf, 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-3EPbPQZH.js";
@@ -37252,7 +37252,7 @@ ${w}`,
37252
37252
  };
37253
37253
  }
37254
37254
  };
37255
- var LazyChatbot = import_react.lazy(() => import("./chat-ui-Cv0kWRcQ.js").then((e) => ({
37255
+ var LazyChatbot = import_react.lazy(() => import("./chat-ui-CQtPb6Dj.js").then((e) => ({
37256
37256
  default: e.Chatbot
37257
37257
  }))), messageSchema = array(object({
37258
37258
  id: string(),
@@ -68920,7 +68920,7 @@ ${c}
68920
68920
  return Logger.warn("Failed to get version from mount config"), null;
68921
68921
  }
68922
68922
  }
68923
- const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.2-dev24"), showCodeInRunModeAtom = atom(true);
68923
+ const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.2-dev27"), showCodeInRunModeAtom = atom(true);
68924
68924
  atom(null);
68925
68925
  var VIRTUAL_FILE_REGEX = /\/@file\/([^\s"&'/]+)\.([\dA-Za-z]+)/g, VirtualFileTracker = class e {
68926
68926
  constructor() {
@@ -25589,8 +25589,8 @@ ${n.sqlString}
25589
25589
  message: JSON.stringify(t3)
25590
25590
  });
25591
25591
  });
25592
- let t2 = e.output.data.filter((e2) => "type" in e2 && e2.type === "exception" || e2.type === "internal");
25593
- if (t2.length > 0 && !didAlreadyToastError) {
25592
+ let t2 = e.output.data.filter((e2) => "type" in e2 && e2.type === "exception" || e2.type === "internal"), n2 = store.get(initialModeAtom) === "read";
25593
+ if (t2.length > 0 && !didAlreadyToastError && n2) {
25594
25594
  didAlreadyToastError = true;
25595
25595
  let e2 = t2.find((e3) => e3.traceback);
25596
25596
  toast(e2 ? {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.23.2-dev24",
3
+ "version": "0.23.2-dev27",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -305,4 +305,46 @@ describe("applyTransactionChanges edge cases", () => {
305
305
  "
306
306
  `);
307
307
  });
308
+
309
+ it("set-code updates the mounted editor view's document", () => {
310
+ // Existing tests only check cellData.code — this covers the editor
311
+ // view side, so regressions in the reducer's imperative sync (or in
312
+ // the CellEditor useEffect that backs it up) don't go unnoticed.
313
+ setup('x = "BEFORE"');
314
+ const [a] = state.cellIds.inOrderIds;
315
+ const editorView = state.cellHandles[a].current?.editorViewOrNull;
316
+ expect(editorView?.state.doc.toString()).toBe('x = "BEFORE"');
317
+
318
+ apply([{ type: "set-code", cellId: a, code: 'x = "AFTER"' }]);
319
+
320
+ expect(state.cellData[a].code).toBe('x = "AFTER"');
321
+ expect(editorView?.state.doc.toString()).toBe('x = "AFTER"');
322
+ });
323
+
324
+ it("create-cell then set-code on same cell updates editor", () => {
325
+ // Mirrors the code_mode flow that exposed marimo-pair#27: create_cell
326
+ // in one batch, edit_cell in a second batch, each arriving as a
327
+ // separate transaction.
328
+ setup();
329
+ apply([
330
+ {
331
+ type: "create-cell",
332
+ cellId: cellId("repro"),
333
+ code: 'x = "BEFORE"',
334
+ name: "repro_bug",
335
+ config: {},
336
+ },
337
+ ]);
338
+ const editorView =
339
+ state.cellHandles[cellId("repro")].current?.editorViewOrNull;
340
+ expect(editorView?.state.doc.toString()).toBe('x = "BEFORE"');
341
+
342
+ apply([
343
+ { type: "set-code", cellId: cellId("repro"), code: 'x = "AFTER"' },
344
+ { type: "reorder-cells", cellIds: [cellId("repro")] },
345
+ ]);
346
+
347
+ expect(state.cellData[cellId("repro")].code).toBe('x = "AFTER"');
348
+ expect(editorView?.state.doc.toString()).toBe('x = "AFTER"');
349
+ });
308
350
  });
@@ -5,6 +5,11 @@ import { cellId } from "@/__tests__/branded";
5
5
  import type { CellMessage } from "../../kernel/messages";
6
6
  import { formatLogTimestamp, getCellLogsForMessage } from "../logs";
7
7
 
8
+ // Stable mock reference so every (re)import of use-toast sees the same spy,
9
+ // even after vi.resetModules() clears the module cache between tests.
10
+ const { toastMock } = vi.hoisted(() => ({ toastMock: vi.fn() }));
11
+ vi.mock("@/components/ui/use-toast", () => ({ toast: toastMock }));
12
+
8
13
  describe("getCellLogsForMessage", () => {
9
14
  beforeEach(() => {
10
15
  // Mock console.log to avoid cluttering test output
@@ -324,6 +329,102 @@ describe("getCellLogsForMessage", () => {
324
329
  });
325
330
  });
326
331
 
332
+ describe("getCellLogsForMessage - internal error toast", () => {
333
+ // Re-imported per test after vi.resetModules() so the module-level
334
+ // `didAlreadyToastError` flag starts fresh and all jotai atom references
335
+ // (initialModeAtom, etc.) match the versions used by the reset logs.ts.
336
+ let getLogs: typeof import("../logs").getCellLogsForMessage;
337
+ let store: typeof import("@/core/state/jotai").store;
338
+ let initialModeAtom: typeof import("@/core/mode").initialModeAtom;
339
+
340
+ beforeEach(async () => {
341
+ vi.spyOn(console, "log").mockImplementation(() => {
342
+ // no-op
343
+ });
344
+ vi.resetModules();
345
+ ({ getCellLogsForMessage: getLogs } = await import("../logs"));
346
+ ({ store } = await import("@/core/state/jotai"));
347
+ ({ initialModeAtom } = await import("@/core/mode"));
348
+ });
349
+
350
+ afterEach(() => {
351
+ vi.restoreAllMocks();
352
+ vi.clearAllMocks();
353
+ });
354
+
355
+ const makeErrorCellMessage = (id: CellMessage["cell_id"]): CellMessage => ({
356
+ cell_id: id,
357
+ console: [],
358
+ output: {
359
+ mimetype: "application/vnd.marimo+error",
360
+ data: [
361
+ {
362
+ type: "exception",
363
+ exception_type: "ValueError",
364
+ msg: "something exploded",
365
+ traceback: ["File foo.py, line 1", "ValueError: something exploded"],
366
+ },
367
+ ],
368
+ channel: "marimo-error",
369
+ timestamp: 0,
370
+ } as unknown as CellMessage["output"],
371
+ status: "idle",
372
+ stale_inputs: null,
373
+ timestamp: 0,
374
+ });
375
+
376
+ test("shows toast for internal errors in app (read) mode", () => {
377
+ store.set(initialModeAtom, "read");
378
+
379
+ getLogs(makeErrorCellMessage(cellId("cell-err-1")));
380
+
381
+ expect(toastMock).toHaveBeenCalledTimes(1);
382
+ expect(toastMock).toHaveBeenCalledWith(
383
+ expect.objectContaining({
384
+ title: "An internal error occurred",
385
+ variant: "danger",
386
+ }),
387
+ );
388
+ });
389
+
390
+ test("does not show toast for internal errors in edit mode", () => {
391
+ store.set(initialModeAtom, "edit");
392
+
393
+ getLogs(makeErrorCellMessage(cellId("cell-err-2")));
394
+
395
+ expect(toastMock).not.toHaveBeenCalled();
396
+ });
397
+
398
+ test("edit-mode errors do not consume the once-per-session toast slot", () => {
399
+ // Errors received while in edit mode should be silently skipped...
400
+ store.set(initialModeAtom, "edit");
401
+ getLogs(makeErrorCellMessage(cellId("cell-err-3")));
402
+ expect(toastMock).not.toHaveBeenCalled();
403
+
404
+ // ...and a subsequent error in app mode should still toast.
405
+ store.set(initialModeAtom, "read");
406
+ getLogs(makeErrorCellMessage(cellId("cell-err-4")));
407
+ expect(toastMock).toHaveBeenCalledTimes(1);
408
+ });
409
+
410
+ test("toast only fires once across multiple app-mode errors", () => {
411
+ store.set(initialModeAtom, "read");
412
+
413
+ getLogs(makeErrorCellMessage(cellId("cell-err-5")));
414
+ getLogs(makeErrorCellMessage(cellId("cell-err-6")));
415
+
416
+ expect(toastMock).toHaveBeenCalledTimes(1);
417
+ });
418
+
419
+ test("suppresses toast when initial mode has not been set", () => {
420
+ // Leave initialModeAtom at its default (undefined); getInitialAppMode
421
+ // will throw and the logic should swallow it without toasting.
422
+ getLogs(makeErrorCellMessage(cellId("cell-err-7")));
423
+
424
+ expect(toastMock).not.toHaveBeenCalled();
425
+ });
426
+ });
427
+
327
428
  describe("formatLogTimestamp", () => {
328
429
  test("formats unix timestamp correctly", () => {
329
430
  // January 1, 2024, 12:00:00 PM UTC
@@ -7,6 +7,7 @@ import { Strings } from "@/utils/strings";
7
7
  import type { CellMessage, OutputMessage } from "../kernel/messages";
8
8
  import { isErrorMime } from "../mime";
9
9
  import type { CellId } from "./ids";
10
+ import { initialModeAtom } from "../mode";
10
11
  import { store } from "../state/jotai";
11
12
  import { tracebackModalAtom } from "../errors/traceback-atom";
12
13
  import React from "react";
@@ -83,7 +84,14 @@ export function getCellLogsForMessage(cell: CellMessage): CellLog[] {
83
84
  error.type === "internal",
84
85
  );
85
86
 
86
- if (exceptionErrors.length > 0 && !didAlreadyToastError) {
87
+ // Only show the toast in app mode: edit mode already surfaces errors in
88
+ // the cell UI, so toasting there would be noisy and duplicative. Read the
89
+ // atom directly so an unset initial mode (e.g. in tests/islands) simply
90
+ // returns undefined instead of throwing and masking real errors.
91
+ const isAppMode = store.get(initialModeAtom) === "read";
92
+
93
+ // Only show toast once, and only in app mode
94
+ if (exceptionErrors.length > 0 && !didAlreadyToastError && isAppMode) {
87
95
  didAlreadyToastError = true;
88
96
 
89
97
  // Find first error with a traceback