@marimo-team/frontend 0.25.2 → 0.25.3-dev100
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/assets/CellStatus-fK4n2NPc.js +1 -0
- package/dist/assets/{ConnectedDataExplorerComponent-t8fH_TNc.js → ConnectedDataExplorerComponent-Dft8R6l5.js} +1 -1
- package/dist/assets/{ErrorBoundary-Gl5nCA8C.js → ErrorBoundary-CAEGdoFW.js} +2 -2
- package/dist/assets/JsonOutput-CyAKmZDD.js +11 -0
- package/dist/assets/{LazyAnyLanguageCodeMirror-CKcCbG2G.js → LazyAnyLanguageCodeMirror-BPYE76jR.js} +2 -2
- package/dist/assets/MarimoErrorOutput-CgZvP0p0.js +10 -0
- package/dist/assets/{RenderHTML-BbOqmHy3.js → RenderHTML-DQvxDDNS.js} +1 -1
- package/dist/assets/RunButton-BBDnDL6G.js +1 -0
- package/dist/assets/__vite-browser-external-8vDMR0Kk.js +1 -0
- package/dist/assets/__vite-browser-external-mKcnhO20.js +1 -0
- package/dist/assets/{add-cell-with-ai-8UBC0xwR.js → add-cell-with-ai-Clg5FELx.js} +12 -12
- package/dist/assets/{add-connection-dialog-DXQnd6eB.js → add-connection-dialog-BqdWmD-7.js} +2 -2
- package/dist/assets/{agent-panel-D7kMZLG-.js → agent-panel-5RxG5Y82.js} +5 -5
- package/dist/assets/ai-model-dropdown-Bvl1ktQq.js +13 -0
- package/dist/assets/{alert-dialog-BaPGzeOK.js → alert-dialog-C-sWmKva.js} +1 -1
- package/dist/assets/any-language-editor-DUMe1UCk.js +1 -0
- package/dist/assets/{app-config-button-BKEG4x9u.js → app-config-button-0QTeQ2Mv.js} +1 -1
- package/dist/assets/arrays-0R2reF2y.js +1 -0
- package/dist/assets/{blob-D5nfNHOo.js → blob-5VcB8K_t.js} +1 -1
- package/dist/assets/{button-COI-NGrx.js → button-D8gVKwe-.js} +1 -1
- package/dist/assets/{cache-panel-DTY1dqvi.js → cache-panel-BV-c7ed0.js} +1 -1
- package/dist/assets/{capabilities-BJvf-MD4.js → capabilities-Pq1YNPlK.js} +1 -1
- package/dist/assets/cell-editor-Byw5y-oI.js +42 -0
- package/dist/assets/cell-link-C5yYyzuF.js +1 -0
- package/dist/assets/{cells-BRkCaSsh.js → cells-D_11MjVB.js} +60 -60
- package/dist/assets/{chat-display-Dnagy4Nv.js → chat-display-BCR_ySiV.js} +1 -1
- package/dist/assets/chat-panel-RPRvBsaU.js +4 -0
- package/dist/assets/chat-ui-CGviVaRA.js +4 -0
- package/dist/assets/{circle-DXf-VWZG.js → circle-B6D_6D8w.js} +1 -1
- package/dist/assets/code-visibility-DYDagVy7.js +1 -0
- package/dist/assets/coerce-DWjFeXOY.js +1 -0
- package/dist/assets/column-preview-xe533-Cn.js +1 -0
- package/dist/assets/command-palette-BB9bWdWp.js +1 -0
- package/dist/assets/{common-Cu6CDbuw.js → common-CaeItbcI.js} +1 -1
- package/dist/assets/components-CBE8cOLK.js +1 -0
- package/dist/assets/{components-CP_UoFtT.js → components-DCo7mAWO.js} +1 -1
- package/dist/assets/{components-CGw16R_N.js → components-G6frbw0c.js} +1 -1
- package/dist/assets/config-CD1IuZFJ.js +1 -0
- package/dist/assets/config-DMz7oN0r.js +1 -0
- package/dist/assets/config-DpY86_Yq.js +1 -0
- package/dist/assets/{copy-D8O_CYCG.js → copy-KlhazlhB.js} +1 -1
- package/dist/assets/{copy-icon-BIiRXh_3.js → copy-icon-8-a5vovc.js} +1 -1
- package/dist/assets/{createReducer-DgRODTW6.js → createReducer-CaI_Oa0v.js} +1 -1
- package/dist/assets/{datasource-Cq6x_5ML.js → datasource-deuXnlU-.js} +1 -1
- package/dist/assets/{dates-BbFQ2oE4.js → dates-CQMwFko2.js} +1 -1
- package/dist/assets/{dependency-graph-panel--Kgtktcw.js → dependency-graph-panel-CIykLnJe.js} +2 -2
- package/dist/assets/{dist-iaThVDkA.js → dist-jlhMTKo_.js} +1 -1
- package/dist/assets/{documentation-panel-BHmbeznw.js → documentation-panel-2PQ8kQLa.js} +1 -1
- package/dist/assets/{download-DCJXy66H.js → download-dK52bLxZ.js} +1 -1
- package/dist/assets/{dropdown-menu-C1rnl-0o.js → dropdown-menu-DS6umAnH.js} +1 -1
- package/dist/assets/edit-page-DrElzw10.js +9 -0
- package/dist/assets/{error-banner-Cd69vvyX.js → error-banner-B5kzVf_0.js} +1 -1
- package/dist/assets/{error-entries-Dk3VZ-OK.js → error-entries-3GVk2KjS.js} +1 -1
- package/dist/assets/{error-panel-BPRYmC5J.js → error-panel-CzDRGPeC.js} +1 -1
- package/dist/assets/{errors-DCrsa1nH.js → errors-CNsgAw6m.js} +1 -1
- package/dist/assets/{es-Cqst59WX.js → es-N9SHpmG7.js} +1 -1
- package/dist/assets/{feedback-button-Bik2-e33.js → feedback-button-C5NgWpFg.js} +2 -2
- package/dist/assets/feedback-button-CONwLFpw.js +1 -0
- package/dist/assets/file-explorer-panel-B50xDnTZ.js +1 -0
- package/dist/assets/{file-name-input-Cdc-TVqO.js → file-name-input-DqwMSgGU.js} +1 -1
- package/dist/assets/{floating-outline-XD9FAV-f.js → floating-outline-ChmAuvxz.js} +1 -1
- package/dist/assets/{formats-yZ06h1Pl.js → formats-zylfwejq.js} +1 -1
- package/dist/assets/{formatting-BqrP-n49.js → formatting-uom1es4b.js} +1 -1
- package/dist/assets/{fullscreen-B9tHcfpV.js → fullscreen-BWTs8pYZ.js} +1 -1
- package/dist/assets/{gallery-page-Dm6mGwBi.js → gallery-page-CiL8aMS1.js} +1 -1
- package/dist/assets/{ganttDiagram-EL5Y4UJY-2n7Ig5Jm.js → ganttDiagram-EL5Y4UJY-CYqkCfFG.js} +1 -1
- package/dist/assets/{glide-data-editor-J9CAb70d.js → glide-data-editor-CqRclBkp.js} +2 -2
- package/dist/assets/{glide-utils-CIrAxdjv.js → glide-utils-HFqhvWHI.js} +2 -2
- package/dist/assets/home-page-BgZVl4dP.js +1 -0
- package/dist/assets/{hooks-93IwHd2u.js → hooks-DM5n7Osw.js} +1 -1
- package/dist/assets/{html-to-image-DK9Zl1lU.js → html-to-image-D_0rd3_B.js} +1 -1
- package/dist/assets/index-BnhSnwvB.css +2 -0
- package/dist/assets/index-EG2n8Oht.js +30 -0
- package/dist/assets/{input-BoBxR50a.js → input-DmHMEZGh.js} +1 -1
- package/dist/assets/kiosk-mode-DFS6HopF.js +1 -0
- package/dist/assets/layout-BpP8nTjb.js +9 -0
- package/dist/assets/linear-Bma8J3iM.js +1 -0
- package/dist/assets/links-DX2w97N9.js +1 -0
- package/dist/assets/{logs-panel-ABM16htT.js → logs-panel-B5eVAZtH.js} +1 -1
- package/dist/assets/{markdown-renderer-BG3sp2rs.js → markdown-renderer-BWUzqkJM.js} +1 -1
- package/dist/assets/{menu-items-BrwnTgyK.js → menu-items-BgUyNUpu.js} +1 -1
- package/dist/assets/{mermaid-a3xYymTy.js → mermaid-BKXlWk4F.js} +2 -2
- package/dist/assets/{name-cell-input-BgEBmqyL.js → name-cell-input-DXW68gRW.js} +1 -1
- package/dist/assets/numbers-CsZVw3Dc.js +1 -0
- package/dist/assets/{objects-snlMn4yk.js → objects-rLPlQ3X_.js} +1 -1
- package/dist/assets/{once-Haz_uxEL.js → once-6KNTRW0u.js} +1 -1
- package/dist/assets/{outline-panel-DCXQ3_F6.js → outline-panel-DPxJhJ_A.js} +1 -1
- package/dist/assets/{package-data-dv4FBHxR.js → package-data-CKPmBDtg.js} +1 -1
- package/dist/assets/packages-panel-gBE2FWQr.js +1 -0
- package/dist/assets/{panel-accordion-state-C1sdPp0m.js → panel-accordion-state-CCF5Gxnc.js} +1 -1
- package/dist/assets/panels-Dr6qMCvU.js +105 -0
- package/dist/assets/precisionRound-BxlUs8G4.js +1 -0
- package/dist/assets/process-output-Cw9IDcKQ.js +1 -0
- package/dist/assets/{quadrantDiagram-AXDQQJYC-yBhCDI7E.js → quadrantDiagram-AXDQQJYC-D9KH5Zge.js} +1 -1
- package/dist/assets/react-vega-BTNeboR2.js +189 -0
- package/dist/assets/{readonly-code-display-Do50PHI8.js → readonly-code-display-DYcZQ28T.js} +1 -1
- package/dist/assets/{readonly-python-code-DCSMIsTX.js → readonly-python-code-RFuQP50v.js} +1 -1
- package/dist/assets/{renderShortcut-BkVJQ_Zh.js → renderShortcut-rUwGqKgC.js} +1 -1
- package/dist/assets/{requests-lt0JK8Jt.js → requests-BIFR-h4M.js} +1 -1
- package/dist/assets/requests-DuLJN9Tf.js +1 -0
- package/dist/assets/{reveal-component-ltaepAqw.js → reveal-component-yRrDmCQz.js} +37 -37
- package/dist/assets/run-page-B69M4-zE.js +1 -0
- package/dist/assets/{runs-BLp5jezv.js → runs-C49hleBy.js} +1 -1
- package/dist/assets/{runtime-details-state-CSPobEdR.js → runtime-details-state-pobtu6TO.js} +1 -1
- package/dist/assets/{save-worker-BbUSwZRG.js → save-worker-pCkSHhuz.js} +1 -1
- package/dist/assets/{schemas-Dv42wLFq.js → schemas-ChRqMOTL.js} +1 -1
- package/dist/assets/scratchpad-panel-H44_pvb_.js +1 -0
- package/dist/assets/{scroll-to-bottom-button-1FyowpWV.js → scroll-to-bottom-button-CIkON2WJ.js} +1 -1
- package/dist/assets/{secrets-panel-Bctbtkrp.js → secrets-panel-bcfEKxRx.js} +1 -1
- package/dist/assets/{select-DTBn5eTb.js → select-3CVGlYrC.js} +1 -1
- package/dist/assets/{session-DqoWmb7X.js → session-CMLIzZKw.js} +1 -1
- package/dist/assets/session-panel-Bnd1iXkO.js +1 -0
- package/dist/assets/{snippets-panel-Bh1oTw4m.js → snippets-panel-DKApxKx9.js} +1 -1
- package/dist/assets/{spec-BfSBcO5B.js → spec-uCpVvaAR.js} +1 -1
- package/dist/assets/{state-uwRvJLb8.js → state-3mcyTS9q.js} +1 -1
- package/dist/assets/state-B_MCKzBL.js +1 -0
- package/dist/assets/state-Bl9BiY_s.js +3 -0
- package/dist/assets/{state-C3oDoyFe.js → state-C5WAeuTu.js} +1 -1
- package/dist/assets/{state-DxQnC_1I.js → state-Cv2JW3l9.js} +1 -1
- package/dist/assets/{state-XsPO8hNi.js → state-Dv059B3A.js} +1 -1
- package/dist/assets/{strings-B2vv-ENv.js → strings-C25fhMR_.js} +1 -1
- package/dist/assets/{swiper-component-a07domrZ.js → swiper-component-CRGRy5_O.js} +1 -1
- package/dist/assets/{switch-CTaiAjrz.js → switch-DYjBfpNJ.js} +1 -1
- package/dist/assets/{tabs-BuQlZFbt.js → tabs-CY8E4r9U.js} +1 -1
- package/dist/assets/{terminal-Ck_vK-34.js → terminal-Ca-kubKb.js} +1 -1
- package/dist/assets/{time-MgToa8VM.js → time-DswSXBDk.js} +1 -1
- package/dist/assets/{toast-BGzLGnvw.js → toast-Gzxi-le_.js} +1 -1
- package/dist/assets/tooltip-Brya4Ghn.js +61 -0
- package/dist/assets/{tooltip-C9TuY18o.js → tooltip-CkGm8X7m.js} +1 -1
- package/dist/assets/tracing-Clwy4SlW.js +1 -0
- package/dist/assets/tracing-panel-BwjLG_aC.js +2 -0
- package/dist/assets/{tree-actions-GM5E_bUs.js → tree-actions-BZNTQ12N.js} +1 -1
- package/dist/assets/{use-restore-focus-BxEGwIbk.js → use-restore-focus-DdS7Tl0F.js} +1 -1
- package/dist/assets/{useAddCell-GR7eEQrT.js → useAddCell-Cjuqk2YR.js} +1 -1
- package/dist/assets/useAsyncData-qvoPYHtx.js +1 -0
- package/dist/assets/useBoolean-Dd2nWXFJ.js +1 -0
- package/dist/assets/useCellActionButton-MoWLvuGe.js +1 -0
- package/dist/assets/useDebounce-DwTQ_1Pu.js +1 -0
- package/dist/assets/{useDeepCompareMemoize-DFIVN9dn.js → useDeepCompareMemoize-B2DVK2De.js} +1 -1
- package/dist/assets/useDelayElapsed-BlsDT4TV.js +1 -0
- package/dist/assets/{useDeleteCell-2_bMClHd.js → useDeleteCell-BC-MW7d1.js} +1 -1
- package/dist/assets/{useDependencyPanelTab-k3C3M18S.js → useDependencyPanelTab-CZU7i-B3.js} +1 -1
- package/dist/assets/{useEvent-Dfcbgjhg.js → useEvent-BDjgaBtz.js} +1 -1
- package/dist/assets/{useEventListener-D9cftcHj.js → useEventListener-CjDeLqFC.js} +1 -1
- package/dist/assets/{useIframeCapabilities-CwTkczVN.js → useIframeCapabilities-Czr9e4uG.js} +1 -1
- package/dist/assets/{useInstallPackage-iX1eufdl.js → useInstallPackage-wcDq9hYT.js} +1 -1
- package/dist/assets/{useInterval--x3s1VpI.js → useInterval-DJdQmXnq.js} +1 -1
- package/dist/assets/useNotebookActions-wFxVdRXQ.js +1 -0
- package/dist/assets/{useRunCells-B2vUhREg.js → useRunCells-ByaWxoIt.js} +1 -1
- package/dist/assets/{useSplitCell-DEb03htp.js → useSplitCell-YJIystwv.js} +1 -1
- package/dist/assets/useStateForKey-CGMJQT8x.js +1 -0
- package/dist/assets/{useTheme-COhSHkCj.js → useTheme-BAA27lh7.js} +1 -1
- package/dist/assets/{utils-CaQYvazl.js → utils-DfElfBpz.js} +1 -1
- package/dist/assets/vega-component-BeyxAJad.js +1 -0
- package/dist/assets/{vega-embed-container-DJPNkHPb.js → vega-embed-container-DtArSJz1.js} +1 -1
- package/dist/assets/vega-loader.browser-Bu25TKax.js +6 -0
- package/dist/assets/{worker-DTQ7oH2A.js → worker-bSCjCvwz.js} +1 -1
- package/dist/assets/{write-secret-modal-DzKAInL2.js → write-secret-modal-BEx-EUlh.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-KbGzG6-u.js → xychartDiagram-S5SC5T6Z-CeRnBS5e.js} +1 -1
- package/dist/index.html +80 -79
- package/package.json +8 -5
- package/src/__tests__/fixtures/{pair-preview.ts → pair-config.ts} +3 -2
- package/src/__tests__/host-imports.test.ts +101 -0
- package/src/__tests__/mount.test.ts +8 -8
- package/src/components/app-config/ai-config.tsx +7 -2
- package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
- package/src/components/chat/acp/__tests__/state.test.ts +2 -2
- package/src/components/chat/acp/blocks.tsx +2 -2
- package/src/components/chat/chat-components.tsx +2 -0
- package/src/components/chat/chat-panel.tsx +9 -8
- package/src/components/chat/chat-utils.ts +4 -8
- package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
- package/src/components/data-table/__tests__/columns.test.tsx +105 -0
- package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
- package/src/components/data-table/__tests__/context-menu.test.ts +176 -0
- package/src/components/data-table/__tests__/date-filter-inputs.test.tsx +24 -1
- package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
- package/src/components/data-table/__tests__/export-actions.test.tsx +434 -6
- package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
- package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
- package/src/components/data-table/cell-selection/feature.ts +2 -2
- package/src/components/data-table/cell-selection/types.ts +2 -2
- package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
- package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
- package/src/components/data-table/charts/charts.tsx +35 -25
- package/src/components/data-table/charts/storage.ts +16 -5
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
- package/src/components/data-table/column-summary/column-summary.tsx +2 -4
- package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
- package/src/components/data-table/columns.tsx +45 -46
- package/src/components/data-table/context-menu.tsx +161 -46
- package/src/components/data-table/data-table.tsx +7 -1
- package/src/components/data-table/date-filter-inputs.tsx +15 -42
- package/src/components/data-table/date-popover.tsx +6 -4
- package/src/components/data-table/export-actions.tsx +267 -163
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +2 -2
- package/src/components/data-table/schemas.ts +14 -36
- package/src/components/data-table/search-highlight.tsx +79 -0
- package/src/components/data-table/types.ts +1 -0
- package/src/components/data-table/url-detector.tsx +49 -9
- package/src/components/data-table/utils.ts +18 -0
- package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
- package/src/components/datasources/__tests__/column-preview.test.tsx +63 -2
- package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
- package/src/components/datasources/column-preview.tsx +8 -2
- package/src/components/datasources/datasources.tsx +47 -35
- package/src/components/debugger/debugger-code.tsx +5 -0
- package/src/components/dependency-graph/panels.tsx +2 -1
- package/src/components/editor/Output.tsx +9 -2
- package/src/components/editor/SortableCell.tsx +1 -3
- package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
- package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +80 -252
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +210 -34
- package/src/components/editor/actions/pair-with-agent-commands.ts +42 -51
- package/src/components/editor/actions/pair-with-agent-modal.tsx +100 -37
- package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
- package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
- package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
- package/src/components/editor/cell/CreateCellButton.tsx +8 -10
- package/src/components/editor/cell/DeleteButton.tsx +1 -0
- package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
- package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
- package/src/components/editor/cell/code/cell-editor.tsx +1 -1
- package/src/components/editor/cell/code/language-toggle.tsx +8 -7
- package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +30 -1
- package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/error-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
- package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +366 -0
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
- package/src/components/editor/chrome/wrapper/footer-item.tsx +32 -24
- package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +237 -0
- package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
- package/src/components/editor/chrome/wrapper/footer.tsx +2 -0
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
- package/src/components/editor/chrome/wrapper/storage.ts +1 -1
- package/src/components/editor/connections/components.tsx +1 -1
- package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
- package/src/components/editor/controls/command-palette.tsx +22 -10
- package/src/components/editor/dynamic-favicon.tsx +21 -40
- package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +537 -0
- package/src/components/editor/errors/send-error-report-button.tsx +69 -0
- package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
- package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
- package/src/components/editor/file-tree/file-explorer.tsx +10 -5
- package/src/components/editor/file-tree/file-viewer.tsx +4 -2
- package/src/components/editor/file-tree/use-file-search.ts +35 -21
- package/src/components/editor/notebook-banner.tsx +1 -0
- package/src/components/editor/output/MarimoErrorOutput.tsx +21 -5
- package/src/components/editor/output/MarimoTracebackOutput.tsx +37 -22
- package/src/components/editor/output/__tests__/ansi-reduce.test.ts +18 -0
- package/src/components/editor/output/ansi-reduce.ts +12 -0
- package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
- package/src/components/editor/package-alert.tsx +6 -4
- package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
- package/src/components/home/components.tsx +17 -31
- package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
- package/src/components/icons/large-spinner.tsx +3 -14
- package/src/components/icons/spinner.tsx +1 -1
- package/src/components/mcp/mcp-status-indicator.tsx +1 -1
- package/src/components/pages/__tests__/home-page.test.tsx +116 -0
- package/src/components/pages/home-page.tsx +164 -91
- package/src/components/scratchpad/scratchpad.tsx +2 -2
- package/src/components/slides/reveal-component.tsx +4 -2
- package/src/components/slides/slide-cell-view.tsx +1 -1
- package/src/components/slides/slide-form.tsx +1 -0
- package/src/components/tracing/tracing.tsx +2 -2
- package/src/components/ui/alert-dialog.tsx +1 -1
- package/src/core/ai/context/providers/datasource.ts +6 -2
- package/src/core/attachments/__tests__/toast.test.tsx +58 -0
- package/src/core/attachments/state.ts +18 -0
- package/src/core/attachments/toast.ts +15 -0
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -0
- package/src/core/cells/__tests__/cell.test.ts +39 -0
- package/src/core/cells/__tests__/cells.test.ts +55 -1
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
- package/src/core/cells/__tests__/error-report.test.ts +139 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
- package/src/core/cells/__tests__/session.test.ts +50 -1
- package/src/core/cells/cell.ts +14 -3
- package/src/core/cells/cells.ts +3 -1
- package/src/core/cells/error-report.ts +63 -0
- package/src/core/cells/pending-delete-service.ts +2 -6
- package/src/core/cells/session.ts +29 -2
- package/src/core/cells/types.ts +10 -1
- package/src/core/codemirror/__tests__/setup.test.ts +1 -1
- package/src/core/codemirror/keymaps/vim.ts +2 -6
- package/src/core/codemirror/language/languages/markdown.ts +1 -1
- package/src/core/codemirror/language/languages/python.ts +3 -3
- package/src/core/codemirror/language/panel/panel.tsx +1 -0
- package/src/core/config/pair.ts +5 -3
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +4 -4
- package/src/core/datasets/data-source-discovery.ts +4 -6
- package/src/core/document/__tests__/draft.test.ts +322 -0
- package/src/core/document/__tests__/fixtures.ts +92 -0
- package/src/core/document/__tests__/model.test.ts +483 -0
- package/src/core/document/__tests__/state.test.ts +446 -0
- package/src/core/document/__tests__/submission.test.ts +346 -0
- package/src/core/document/draft.ts +472 -0
- package/src/core/document/index.ts +10 -0
- package/src/core/document/model.ts +53 -0
- package/src/core/document/state.ts +401 -0
- package/src/core/document/sync.ts +359 -0
- package/src/core/edit-app.tsx +2 -2
- package/src/core/host/AGENTS.md +16 -0
- package/src/core/host/__tests__/attachments.test.ts +56 -0
- package/src/core/host/__tests__/document.test.ts +126 -0
- package/src/core/host/__tests__/fixtures.ts +41 -0
- package/src/core/host/__tests__/notebook-client.test.ts +570 -0
- package/src/core/host/connection.ts +42 -0
- package/src/core/host/notebook-client.ts +297 -0
- package/src/core/host/resources/attachments.ts +22 -0
- package/src/core/host/resources/document.ts +101 -0
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
- package/src/core/network/connection.ts +4 -2
- package/src/core/network/useConnectionNotice.ts +8 -2
- package/src/core/run-app.tsx +2 -2
- package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
- package/src/core/runtime/__tests__/runtime.test.ts +18 -17
- package/src/core/runtime/runtime.ts +26 -30
- package/src/core/state/__tests__/jotai.test.tsx +108 -0
- package/src/core/state/jotai.ts +1 -1
- package/src/core/static/files.ts +2 -0
- package/src/core/wasm/bridge.ts +2 -10
- package/src/core/wasm/store.ts +3 -3
- package/src/core/wasm/worker/bootstrap.ts +1 -1
- package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.test.ts → connection-state.test.ts} +15 -29
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +223 -0
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.hook.test.tsx → useNotebookSession.hook.test.tsx} +194 -184
- package/src/core/websocket/connection-state.ts +60 -0
- package/src/core/websocket/state.ts +7 -0
- package/src/core/websocket/transports/__tests__/notebook.test.ts +502 -0
- package/src/core/websocket/transports/notebook.ts +213 -0
- package/src/core/websocket/types.ts +9 -39
- package/src/core/websocket/useNotebookClient.ts +89 -0
- package/src/core/websocket/{useMarimoKernelConnection.tsx → useNotebookSession.tsx} +53 -224
- package/src/css/globals.css +5 -0
- package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
- package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
- package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
- package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
- package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
- package/src/hooks/__tests__/useScript.test.tsx +77 -0
- package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
- package/src/hooks/useAsyncData.ts +3 -3
- package/src/hooks/useDataSourceDiscovery.ts +6 -4
- package/src/hooks/useDebounce.ts +5 -8
- package/src/hooks/useDeepCompareMemoize.ts +1 -1
- package/src/hooks/useDelayElapsed.ts +14 -10
- package/src/hooks/useElapsedTime.ts +3 -3
- package/src/hooks/useInputHistory.ts +4 -7
- package/src/hooks/useInternalStateWithSync.ts +6 -6
- package/src/hooks/useResizeObserver.ts +4 -7
- package/src/hooks/useScript.ts +67 -70
- package/src/hooks/useStateForKey.ts +93 -0
- package/src/mount.tsx +3 -3
- package/src/plugins/core/registerReactComponent.tsx +1 -1
- package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
- package/src/plugins/impl/DataTablePlugin.tsx +14 -15
- package/src/plugins/impl/DropdownPlugin.tsx +2 -6
- package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
- package/src/plugins/impl/FormPlugin.tsx +1 -1
- package/src/plugins/impl/RangeSliderPlugin.tsx +0 -1
- package/src/plugins/impl/RefreshPlugin.tsx +1 -0
- package/src/plugins/impl/SliderPlugin.tsx +6 -8
- package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +201 -1
- package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
- package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
- package/src/plugins/impl/anywidget/__tests__/registry.test.ts +2 -0
- package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
- package/src/plugins/impl/anywidget/runtime.ts +21 -9
- package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
- package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
- package/src/plugins/impl/chat/chat-ui.tsx +12 -10
- package/src/plugins/impl/code/any-language-editor.tsx +2 -2
- package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
- package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
- package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
- package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +0 -1
- package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
- package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
- package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
- package/src/plugins/impl/panel/utils.ts +17 -0
- package/src/plugins/impl/vega/make-selectable.ts +4 -7
- package/src/plugins/layout/RoutesPlugin.tsx +1 -1
- package/src/stories/__tests__/editor-story.test.tsx +33 -0
- package/src/stories/button.stories.tsx +1 -0
- package/src/stories/editor.stories.tsx +24 -17
- package/src/stories/form-wrapper.stories.tsx +2 -2
- package/src/stories/select.stories.tsx +2 -2
- package/src/stories/switchable-multi-select.stories.tsx +1 -1
- package/src/utils/__tests__/arrays.test.ts +35 -0
- package/src/utils/__tests__/batch-requests.test.ts +3 -3
- package/src/utils/__tests__/dates.test.ts +116 -0
- package/src/utils/__tests__/numbers.test.ts +48 -1
- package/src/utils/__tests__/objects.test.ts +21 -0
- package/src/utils/arrays.ts +10 -0
- package/src/utils/blob.ts +1 -1
- package/src/utils/dates.ts +94 -0
- package/src/utils/numbers.ts +28 -17
- package/src/utils/objects.ts +3 -7
- package/src/utils/once.ts +19 -19
- package/src/utils/zod-utils.ts +1 -3
- package/dist/assets/CellStatus-BP2mavAq.js +0 -1
- package/dist/assets/JsonOutput-D6HIIsCb.js +0 -11
- package/dist/assets/MarimoErrorOutput-D60XkCny.js +0 -6
- package/dist/assets/RunButton-CK3LhnP5.js +0 -1
- package/dist/assets/__vite-browser-external-CYO_P3S8.js +0 -1
- package/dist/assets/__vite-browser-external-FeDVGZU8.js +0 -1
- package/dist/assets/ai-model-dropdown-B0z6-zhp.js +0 -5
- package/dist/assets/any-language-editor-BLCAD3yx.js +0 -1
- package/dist/assets/api-BeC_VSGv.js +0 -1
- package/dist/assets/arrays-BqUx5USx.js +0 -1
- package/dist/assets/cell-editor-ADVfycpN.js +0 -21
- package/dist/assets/cell-link-LSth_8hT.js +0 -1
- package/dist/assets/chat-panel-DQ6HkWEF.js +0 -4
- package/dist/assets/chat-ui-Df8Vcj6n.js +0 -4
- package/dist/assets/circle-play-CYIb0qT6.js +0 -1
- package/dist/assets/code-visibility-B-_GvwR5.js +0 -1
- package/dist/assets/coerce-CpE6kUdX.js +0 -1
- package/dist/assets/column-preview-Cm2D6vyX.js +0 -1
- package/dist/assets/command-palette-DTSQ7gOC.js +0 -1
- package/dist/assets/components-CXfO-F47.js +0 -1
- package/dist/assets/config-BOKzA3tF.js +0 -1
- package/dist/assets/config-DX8Y2WbJ.js +0 -1
- package/dist/assets/config-VPSq73n8.js +0 -1
- package/dist/assets/edit-page-ChcSgpke.js +0 -9
- package/dist/assets/feedback-button-B2gKC5cn.js +0 -1
- package/dist/assets/file-explorer-panel-BEEK5lcl.js +0 -1
- package/dist/assets/home-page-DMHnsRxm.js +0 -4
- package/dist/assets/index-Bcdzex-3.css +0 -2
- package/dist/assets/index-s-M1OXjs.js +0 -29
- package/dist/assets/kiosk-mode-BZECfg9k.js +0 -1
- package/dist/assets/layout-DmcNEu3P.js +0 -9
- package/dist/assets/linear-0eij_aAG.js +0 -1
- package/dist/assets/link-NuFVR7G9.js +0 -1
- package/dist/assets/links-DkkL9DVa.js +0 -1
- package/dist/assets/numbers-Mk3-CcoU.js +0 -1
- package/dist/assets/packages-panel-BMGOmZkR.js +0 -1
- package/dist/assets/pair-CaQyK6En.js +0 -1
- package/dist/assets/panels-CxVG8-v2.js +0 -4
- package/dist/assets/precisionRound-Bq_nmf5u.js +0 -1
- package/dist/assets/process-output-D0KGq04R.js +0 -1
- package/dist/assets/react-vega-C3rYGtP6.js +0 -189
- package/dist/assets/requests-CgSY1X4a.js +0 -1
- package/dist/assets/run-page-DF3c5cDk.js +0 -1
- package/dist/assets/scratchpad-panel-Dwd6W5PE.js +0 -1
- package/dist/assets/session-panel-VdDhEBa-.js +0 -1
- package/dist/assets/state-BAJYRhmO.js +0 -1
- package/dist/assets/state-_Qai_QyX.js +0 -3
- package/dist/assets/tooltip-mT3CGest.js +0 -61
- package/dist/assets/tracing-Di6pUmX8.js +0 -1
- package/dist/assets/tracing-panel-PeRXHD8_.js +0 -2
- package/dist/assets/useAsyncData-C7aJJz0Y.js +0 -1
- package/dist/assets/useBoolean-BDD6_xQQ.js +0 -1
- package/dist/assets/useCellActionButton-B-9eG5z_.js +0 -1
- package/dist/assets/useDebounce-B_ccBZTp.js +0 -1
- package/dist/assets/useNotebookActions-NHN6A-cN.js +0 -1
- package/dist/assets/vega-component-CnadTgoE.js +0 -1
- package/dist/assets/vega-loader.browser-CLRkNgm7.js +0 -6
- package/dist/assets/ws-BXWY541V.js +0 -22
- package/src/core/state/__tests__/jotai.test.ts +0 -25
- package/src/core/websocket/__tests__/useWebSocket.test.ts +0 -49
- package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
- package/src/core/websocket/transports/__tests__/sse.test.ts +0 -338
- package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
- package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
- package/src/core/websocket/transports/basic.ts +0 -102
- package/src/core/websocket/transports/sse.ts +0 -308
- package/src/core/websocket/transports/transport.ts +0 -61
- package/src/core/websocket/transports/ws.ts +0 -98
- package/src/core/websocket/useWebSocket.tsx +0 -88
|
@@ -21,14 +21,9 @@ import {
|
|
|
21
21
|
vi,
|
|
22
22
|
} from "vitest";
|
|
23
23
|
|
|
24
|
-
vi.mock("
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return {
|
|
28
|
-
...actual,
|
|
29
|
-
useConnectionTransport: vi.fn(),
|
|
30
|
-
};
|
|
31
|
-
});
|
|
24
|
+
vi.mock("../transports/notebook", () => ({
|
|
25
|
+
createNotebookTransport: vi.fn(),
|
|
26
|
+
}));
|
|
32
27
|
|
|
33
28
|
vi.mock("@/core/runtime/config", async () => {
|
|
34
29
|
const actual = await vi.importActual<typeof import("@/core/runtime/config")>(
|
|
@@ -41,6 +36,7 @@ vi.mock("@/core/runtime/config", async () => {
|
|
|
41
36
|
});
|
|
42
37
|
|
|
43
38
|
import { MockNotebook } from "@/__mocks__/notebook";
|
|
39
|
+
import { Deferred } from "@/utils/Deferred";
|
|
44
40
|
import { cellId } from "@/__tests__/branded";
|
|
45
41
|
import { alertAtom, getPackageAlert } from "@/core/alerts/state";
|
|
46
42
|
import { notebookAtom } from "@/core/cells/cells";
|
|
@@ -51,44 +47,96 @@ import type { NotificationPayload } from "@/core/kernel/messages";
|
|
|
51
47
|
import { useRuntimeManager } from "@/core/runtime/config";
|
|
52
48
|
import { initialRunCompletedAtom } from "../../kernel/state";
|
|
53
49
|
import { connectionAtom, startupProgressAtom } from "../../network/connection";
|
|
54
|
-
import
|
|
50
|
+
import { generateSessionId } from "../../kernel/session";
|
|
51
|
+
import { RuntimeManager } from "../../runtime/runtime";
|
|
55
52
|
import { WebSocketClosedReason, ConnectionState } from "../types";
|
|
56
|
-
import
|
|
57
|
-
import {
|
|
58
|
-
import {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
53
|
+
import { classifyCloseEvent } from "../connection-state";
|
|
54
|
+
import { createNotebookTransport } from "../transports/notebook";
|
|
55
|
+
import { useNotebookSession } from "../useNotebookSession";
|
|
56
|
+
import { type NotebookTransport, StreamStopped } from "@marimo-team/client";
|
|
57
|
+
|
|
58
|
+
const SESSION_ID = generateSessionId();
|
|
59
|
+
|
|
60
|
+
/** One connection the fake transport opened. */
|
|
61
|
+
interface Attempt {
|
|
62
|
+
open(): void;
|
|
63
|
+
receive(message: unknown): void;
|
|
64
|
+
drop(): void;
|
|
65
|
+
stop(error: StreamStopped): void;
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
/** A transport the test drives, one connection at a time. */
|
|
69
|
+
function makeTransport() {
|
|
70
|
+
const attempts: Attempt[] = [];
|
|
71
|
+
const transport: NotebookTransport = ({ signal }, handlers) =>
|
|
72
|
+
new Promise((resolve, reject) => {
|
|
73
|
+
attempts.push({
|
|
74
|
+
open: handlers.open,
|
|
75
|
+
receive: handlers.message,
|
|
76
|
+
drop: resolve,
|
|
77
|
+
stop: reject,
|
|
78
|
+
});
|
|
79
|
+
signal.addEventListener("abort", () => resolve(), { once: true });
|
|
80
|
+
});
|
|
81
|
+
return { transport, attempts };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type FakeTransport = ReturnType<typeof makeTransport>;
|
|
85
|
+
|
|
86
|
+
/** Use a fake transport for the next session the hook follows. */
|
|
87
|
+
function withTransport(fake: FakeTransport = makeTransport()) {
|
|
88
|
+
vi.mocked(createNotebookTransport).mockReturnValue(fake.transport);
|
|
89
|
+
return fake;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Let the stream open its first connection. */
|
|
93
|
+
const started = () => act(() => Promise.resolve());
|
|
94
|
+
|
|
95
|
+
/** Drive the latest connection the fake transport opened. */
|
|
96
|
+
function connection(fake: FakeTransport) {
|
|
97
|
+
const current = () => {
|
|
98
|
+
const attempt = fake.attempts.at(-1);
|
|
99
|
+
if (attempt === undefined) {
|
|
100
|
+
throw new Error("No connection was opened");
|
|
101
|
+
}
|
|
102
|
+
return attempt;
|
|
103
|
+
};
|
|
72
104
|
return {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
send:
|
|
77
|
-
|
|
78
|
-
|
|
105
|
+
open: () => current().open(),
|
|
106
|
+
receive: (message: unknown) => current().receive(message),
|
|
107
|
+
/** Deliver a notification as the session routes frame it. */
|
|
108
|
+
send: (notification: unknown) =>
|
|
109
|
+
current().receive({ event: "marimo", data: { marimo: notification } }),
|
|
110
|
+
/** End the connection so the stream reconnects. */
|
|
111
|
+
drop: () => current().drop(),
|
|
112
|
+
/** Close the connection with a reason the editor treats as final. */
|
|
113
|
+
close: (reason: string) =>
|
|
114
|
+
current().stop(
|
|
115
|
+
new StreamStopped(reason, {
|
|
116
|
+
cause: classifyCloseEvent({ reason }).status,
|
|
117
|
+
}),
|
|
118
|
+
),
|
|
79
119
|
};
|
|
80
120
|
}
|
|
81
121
|
|
|
82
122
|
function makeRuntimeManager(
|
|
83
123
|
reconcileFromHealth = vi.fn<() => Promise<boolean>>().mockResolvedValue(true),
|
|
84
124
|
) {
|
|
85
|
-
|
|
125
|
+
const runtime = new RuntimeManager(
|
|
126
|
+
{ url: "http://localhost", lazy: true },
|
|
127
|
+
true,
|
|
128
|
+
);
|
|
129
|
+
vi.spyOn(runtime, "reconcileFromHealth").mockImplementation(
|
|
86
130
|
reconcileFromHealth,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
131
|
+
);
|
|
132
|
+
vi.spyOn(runtime, "probeHealth").mockResolvedValue(true);
|
|
133
|
+
vi.spyOn(runtime, "getWsURL").mockReturnValue(new URL("ws://localhost/ws"));
|
|
134
|
+
// Keep the initial connection pending; these tests exercise session retries.
|
|
135
|
+
vi.spyOn(runtime, "waitForHealthy").mockReturnValue(
|
|
136
|
+
new Deferred<void>().promise,
|
|
137
|
+
);
|
|
138
|
+
vi.spyOn(runtime, "isSameOrigin", "get").mockReturnValue(false);
|
|
139
|
+
return runtime;
|
|
92
140
|
}
|
|
93
141
|
|
|
94
142
|
function renderConnectionHook(store: ReturnType<typeof createStore>) {
|
|
@@ -99,22 +147,22 @@ function renderConnectionHook(store: ReturnType<typeof createStore>) {
|
|
|
99
147
|
);
|
|
100
148
|
return renderHook(
|
|
101
149
|
() =>
|
|
102
|
-
|
|
103
|
-
sessionId:
|
|
150
|
+
useNotebookSession({
|
|
151
|
+
sessionId: SESSION_ID,
|
|
104
152
|
autoInstantiate: false,
|
|
105
|
-
setCells: ()
|
|
153
|
+
setCells: vi.fn(),
|
|
106
154
|
}),
|
|
107
155
|
{ wrapper },
|
|
108
156
|
);
|
|
109
157
|
}
|
|
110
158
|
|
|
111
|
-
describe("
|
|
112
|
-
let
|
|
159
|
+
describe("useNotebookSession.reconnect()", () => {
|
|
160
|
+
let fake: FakeTransport;
|
|
113
161
|
let isHealthy: Mock<() => Promise<boolean>>;
|
|
114
162
|
let store: ReturnType<typeof createStore>;
|
|
115
163
|
|
|
116
164
|
beforeEach(() => {
|
|
117
|
-
|
|
165
|
+
fake = withTransport();
|
|
118
166
|
isHealthy = vi.fn<() => Promise<boolean>>().mockResolvedValue(true);
|
|
119
167
|
store = createStore();
|
|
120
168
|
store.set(connectionAtom, {
|
|
@@ -122,59 +170,53 @@ describe("useMarimoKernelConnection.reconnect()", () => {
|
|
|
122
170
|
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
123
171
|
reason: "kernel not found",
|
|
124
172
|
});
|
|
125
|
-
vi.mocked(
|
|
126
|
-
vi.mocked(useRuntimeManager).mockReturnValue(
|
|
127
|
-
makeRuntimeManager(isHealthy) as unknown as ReturnType<
|
|
128
|
-
typeof useRuntimeManager
|
|
129
|
-
>,
|
|
130
|
-
);
|
|
173
|
+
vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager(isHealthy));
|
|
131
174
|
});
|
|
132
175
|
|
|
133
|
-
function
|
|
134
|
-
|
|
176
|
+
async function renderStopped() {
|
|
177
|
+
const hook = renderConnectionHook(store);
|
|
178
|
+
await started();
|
|
179
|
+
await act(async () => connection(fake).close("MARIMO_SHUTDOWN"));
|
|
180
|
+
return hook;
|
|
135
181
|
}
|
|
136
182
|
|
|
137
|
-
it("
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
await
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
expect(isHealthy).not.toHaveBeenCalled();
|
|
154
|
-
expect(transport.reconnect).not.toHaveBeenCalled();
|
|
155
|
-
});
|
|
183
|
+
it.each(["connecting", "connected"])(
|
|
184
|
+
"is a no-op while the stream is %s",
|
|
185
|
+
async (state) => {
|
|
186
|
+
const { result } = renderConnectionHook(store);
|
|
187
|
+
await started();
|
|
188
|
+
if (state === "connected") {
|
|
189
|
+
act(() => connection(fake).open());
|
|
190
|
+
}
|
|
191
|
+
await act(async () => {
|
|
192
|
+
await result.current.reconnect();
|
|
193
|
+
});
|
|
194
|
+
expect(isHealthy).not.toHaveBeenCalled();
|
|
195
|
+
expect(fake.attempts).toHaveLength(1);
|
|
196
|
+
},
|
|
197
|
+
);
|
|
156
198
|
|
|
157
199
|
it("probes /health and reconnects when the runtime is healthy", async () => {
|
|
158
200
|
isHealthy.mockResolvedValue(true);
|
|
159
|
-
const { result } =
|
|
201
|
+
const { result } = await renderStopped();
|
|
160
202
|
await act(async () => {
|
|
161
203
|
await result.current.reconnect();
|
|
162
204
|
});
|
|
163
205
|
expect(isHealthy).toHaveBeenCalledOnce();
|
|
164
|
-
expect(
|
|
206
|
+
expect(fake.attempts).toHaveLength(2);
|
|
165
207
|
expect(store.get(connectionAtom)).toEqual({
|
|
166
208
|
state: ConnectionState.CONNECTING,
|
|
167
209
|
});
|
|
168
210
|
});
|
|
169
211
|
|
|
170
|
-
it("transitions to CLOSED and does not
|
|
212
|
+
it("transitions to CLOSED and does not reconnect when the probe fails", async () => {
|
|
171
213
|
isHealthy.mockResolvedValue(false);
|
|
172
|
-
const { result } =
|
|
214
|
+
const { result } = await renderStopped();
|
|
173
215
|
await act(async () => {
|
|
174
216
|
await result.current.reconnect();
|
|
175
217
|
});
|
|
176
218
|
expect(isHealthy).toHaveBeenCalledOnce();
|
|
177
|
-
expect(
|
|
219
|
+
expect(fake.attempts).toHaveLength(1);
|
|
178
220
|
expect(store.get(connectionAtom)).toEqual({
|
|
179
221
|
state: ConnectionState.CLOSED,
|
|
180
222
|
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
@@ -183,30 +225,31 @@ describe("useMarimoKernelConnection.reconnect()", () => {
|
|
|
183
225
|
});
|
|
184
226
|
});
|
|
185
227
|
|
|
186
|
-
describe("
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
);
|
|
193
|
-
vi.mocked(useRuntimeManager).mockReturnValue(
|
|
194
|
-
makeRuntimeManager() as unknown as ReturnType<typeof useRuntimeManager>,
|
|
195
|
-
);
|
|
228
|
+
describe("useNotebookSession messages", () => {
|
|
229
|
+
let store: ReturnType<typeof createStore>;
|
|
230
|
+
let fake: FakeTransport;
|
|
231
|
+
|
|
232
|
+
beforeEach(async () => {
|
|
233
|
+
store = createStore();
|
|
234
|
+
fake = withTransport();
|
|
235
|
+
vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
|
|
196
236
|
renderConnectionHook(store);
|
|
237
|
+
await started();
|
|
238
|
+
});
|
|
197
239
|
|
|
198
|
-
|
|
240
|
+
function receive(payload: unknown) {
|
|
241
|
+
act(() => connection(fake).receive(payload));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
it("records completion of the initial run", () => {
|
|
245
|
+
const notification = {
|
|
246
|
+
op: "completed-run",
|
|
247
|
+
run_id: null,
|
|
248
|
+
outcome: "succeeded",
|
|
249
|
+
error: null,
|
|
250
|
+
} satisfies NotificationPayload["data"];
|
|
199
251
|
expect(store.get(initialRunCompletedAtom)).toBe(false);
|
|
200
|
-
|
|
201
|
-
options?.onMessage(
|
|
202
|
-
new MessageEvent("message", {
|
|
203
|
-
data: JSON.stringify({
|
|
204
|
-
op: "completed-run",
|
|
205
|
-
data: { op: "completed-run", run_id: null },
|
|
206
|
-
}),
|
|
207
|
-
}),
|
|
208
|
-
);
|
|
209
|
-
});
|
|
252
|
+
receive({ id: "42", event: "marimo", data: { marimo: notification } });
|
|
210
253
|
expect(store.get(initialRunCompletedAtom)).toBe(true);
|
|
211
254
|
});
|
|
212
255
|
});
|
|
@@ -216,47 +259,34 @@ it.each(["kernel-ready", "reconnected"])(
|
|
|
216
259
|
async (op) => {
|
|
217
260
|
const store = createStore();
|
|
218
261
|
store.set(connectionAtom, { state: ConnectionState.CONNECTING });
|
|
219
|
-
|
|
220
|
-
vi.mocked(
|
|
221
|
-
makeTransport(WebSocket.OPEN),
|
|
222
|
-
);
|
|
223
|
-
vi.mocked(useRuntimeManager).mockReturnValue(
|
|
224
|
-
makeRuntimeManager() as unknown as ReturnType<typeof useRuntimeManager>,
|
|
225
|
-
);
|
|
262
|
+
const fake = withTransport();
|
|
263
|
+
vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
|
|
226
264
|
renderConnectionHook(store);
|
|
227
|
-
|
|
265
|
+
await started();
|
|
266
|
+
const conn = connection(fake);
|
|
228
267
|
|
|
229
|
-
await act(async () =>
|
|
230
|
-
await options.onOpen(new Event("open"));
|
|
231
|
-
});
|
|
268
|
+
await act(async () => conn.open());
|
|
232
269
|
expect(store.get(connectionAtom).state).toBe(ConnectionState.CONNECTING);
|
|
233
270
|
|
|
234
|
-
act(() =>
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
auto_instantiated: false,
|
|
254
|
-
consumer_capabilities: { edit: true, interact: true },
|
|
255
|
-
},
|
|
256
|
-
}),
|
|
257
|
-
}),
|
|
258
|
-
);
|
|
259
|
-
});
|
|
271
|
+
act(() =>
|
|
272
|
+
conn.send({
|
|
273
|
+
op,
|
|
274
|
+
cell_ids: [],
|
|
275
|
+
codes: [],
|
|
276
|
+
names: [],
|
|
277
|
+
configs: [],
|
|
278
|
+
layout: null,
|
|
279
|
+
resumed: true,
|
|
280
|
+
ui_values: {},
|
|
281
|
+
last_executed_code: {},
|
|
282
|
+
last_execution_time: {},
|
|
283
|
+
app_config: { width: "normal" },
|
|
284
|
+
kiosk: false,
|
|
285
|
+
capabilities: { terminal: false },
|
|
286
|
+
auto_instantiated: false,
|
|
287
|
+
consumer_capabilities: { edit: true, interact: true },
|
|
288
|
+
}),
|
|
289
|
+
);
|
|
260
290
|
expect(store.get(connectionAtom).state).toBe(ConnectionState.OPEN);
|
|
261
291
|
},
|
|
262
292
|
);
|
|
@@ -265,19 +295,16 @@ describe("connection notice", () => {
|
|
|
265
295
|
beforeEach(() => vi.useFakeTimers());
|
|
266
296
|
afterEach(() => vi.useRealTimers());
|
|
267
297
|
|
|
268
|
-
function renderNotice() {
|
|
298
|
+
async function renderNotice() {
|
|
269
299
|
const store = createStore();
|
|
270
300
|
store.set(connectionAtom, { state: ConnectionState.CONNECTING });
|
|
271
|
-
const
|
|
272
|
-
vi.mocked(
|
|
273
|
-
vi.mocked(useRuntimeManager).mockReturnValue(
|
|
274
|
-
makeRuntimeManager() as unknown as ReturnType<typeof useRuntimeManager>,
|
|
275
|
-
);
|
|
301
|
+
const fake = withTransport();
|
|
302
|
+
vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
|
|
276
303
|
const Connection = () => {
|
|
277
|
-
const { reconnect } =
|
|
278
|
-
sessionId:
|
|
304
|
+
const { reconnect } = useNotebookSession({
|
|
305
|
+
sessionId: SESSION_ID,
|
|
279
306
|
autoInstantiate: false,
|
|
280
|
-
setCells: ()
|
|
307
|
+
setCells: vi.fn(),
|
|
281
308
|
});
|
|
282
309
|
return (
|
|
283
310
|
<ConnectionNotice
|
|
@@ -293,20 +320,17 @@ describe("connection notice", () => {
|
|
|
293
320
|
</ErrorBoundary>
|
|
294
321
|
</JotaiProvider>,
|
|
295
322
|
);
|
|
296
|
-
|
|
323
|
+
await started();
|
|
324
|
+
const conn = connection(fake);
|
|
325
|
+
// Messages arrive on an open connection.
|
|
326
|
+
act(() => conn.open());
|
|
297
327
|
const send = (data: NotificationPayload["data"]) =>
|
|
298
|
-
act(() =>
|
|
299
|
-
|
|
300
|
-
new MessageEvent("message", {
|
|
301
|
-
data: JSON.stringify({ op: data.op, data }),
|
|
302
|
-
}),
|
|
303
|
-
);
|
|
304
|
-
});
|
|
305
|
-
return { store, transport, options, send };
|
|
328
|
+
act(() => conn.send(data));
|
|
329
|
+
return { store, fake, conn, send };
|
|
306
330
|
}
|
|
307
331
|
|
|
308
|
-
it("keeps elapsed time across startup phases and leaves reconnection to the footer once cells are available", () => {
|
|
309
|
-
const { store,
|
|
332
|
+
it("keeps elapsed time across startup phases and leaves reconnection to the footer once cells are available", async () => {
|
|
333
|
+
const { store, conn, send } = await renderNotice();
|
|
310
334
|
send({
|
|
311
335
|
op: "startup-progress",
|
|
312
336
|
phase: "preparing-environment",
|
|
@@ -346,7 +370,7 @@ describe("connection notice", () => {
|
|
|
346
370
|
expect(
|
|
347
371
|
screen.queryByRole("region", { name: "Notebook startup" }),
|
|
348
372
|
).not.toBeInTheDocument();
|
|
349
|
-
act(() =>
|
|
373
|
+
await act(async () => conn.drop());
|
|
350
374
|
act(() => vi.advanceTimersByTime(500));
|
|
351
375
|
expect(store.get(connectionAtom)).toEqual({
|
|
352
376
|
state: ConnectionState.CONNECTING,
|
|
@@ -357,8 +381,8 @@ describe("connection notice", () => {
|
|
|
357
381
|
).not.toBeInTheDocument();
|
|
358
382
|
});
|
|
359
383
|
|
|
360
|
-
it("restores startup output before appending live chunks and resets it for a new attempt", () => {
|
|
361
|
-
const { store, send } = renderNotice();
|
|
384
|
+
it("restores startup output before appending live chunks and resets it for a new attempt", async () => {
|
|
385
|
+
const { store, send } = await renderNotice();
|
|
362
386
|
const snapshot = {
|
|
363
387
|
op: "startup-progress",
|
|
364
388
|
phase: "starting-kernel",
|
|
@@ -384,7 +408,7 @@ describe("connection notice", () => {
|
|
|
384
408
|
});
|
|
385
409
|
|
|
386
410
|
it("restores completed startup output without putting a connected kernel back into startup", async () => {
|
|
387
|
-
const { store,
|
|
411
|
+
const { store, conn, send } = await renderNotice();
|
|
388
412
|
send({ op: "reconnected" });
|
|
389
413
|
send({
|
|
390
414
|
op: "startup-progress",
|
|
@@ -402,13 +426,15 @@ describe("connection notice", () => {
|
|
|
402
426
|
screen.queryByRole("region", { name: "Notebook startup" }),
|
|
403
427
|
).not.toBeInTheDocument();
|
|
404
428
|
|
|
405
|
-
// A new
|
|
406
|
-
await act(async () =>
|
|
429
|
+
// A new connection starts from the next session's authoritative snapshot.
|
|
430
|
+
await act(async () => conn.drop());
|
|
431
|
+
await act(async () => vi.advanceTimersByTime(2000));
|
|
432
|
+
await act(async () => conn.open());
|
|
407
433
|
expect(store.get(startupProgressAtom)).toBeNull();
|
|
408
434
|
});
|
|
409
435
|
|
|
410
|
-
it("does not flash a notice when startup finishes within the delay", () => {
|
|
411
|
-
const { send } = renderNotice();
|
|
436
|
+
it("does not flash a notice when startup finishes within the delay", async () => {
|
|
437
|
+
const { send } = await renderNotice();
|
|
412
438
|
send({
|
|
413
439
|
op: "startup-progress",
|
|
414
440
|
phase: "preparing-environment",
|
|
@@ -436,16 +462,11 @@ describe("connection notice", () => {
|
|
|
436
462
|
it.each(["preparing-environment", "starting-kernel"] as const)(
|
|
437
463
|
"keeps a %s failure available until the user retries",
|
|
438
464
|
async (phase) => {
|
|
439
|
-
const { store,
|
|
465
|
+
const { store, fake, conn, send } = await renderNotice();
|
|
440
466
|
send({ op: "startup-progress", phase, logs: "", log_mode: "replace" });
|
|
441
467
|
const error = "A full diagnostic\nwith <stderr> details";
|
|
442
468
|
send({ op: "kernel-startup-error", error });
|
|
443
|
-
|
|
444
|
-
act(() =>
|
|
445
|
-
options.onClose(
|
|
446
|
-
new CloseEvent("close", { reason: "MARIMO_KERNEL_STARTUP_ERROR" }),
|
|
447
|
-
),
|
|
448
|
-
);
|
|
469
|
+
await act(async () => conn.close("MARIMO_KERNEL_STARTUP_ERROR"));
|
|
449
470
|
expect(screen.getByRole("status")).toHaveTextContent(
|
|
450
471
|
"Kernel failed to start",
|
|
451
472
|
);
|
|
@@ -456,11 +477,11 @@ describe("connection notice", () => {
|
|
|
456
477
|
expect(screen.getByLabelText("Error details")).toHaveTextContent(error, {
|
|
457
478
|
normalizeWhitespace: false,
|
|
458
479
|
});
|
|
459
|
-
expect(
|
|
480
|
+
expect(fake.attempts).toHaveLength(1);
|
|
460
481
|
await act(async () =>
|
|
461
482
|
fireEvent.click(screen.getByRole("button", { name: "Try again" })),
|
|
462
483
|
);
|
|
463
|
-
expect(
|
|
484
|
+
expect(fake.attempts).toHaveLength(2);
|
|
464
485
|
expect(store.get(kernelStartupErrorAtom)).toBeNull();
|
|
465
486
|
expect(
|
|
466
487
|
screen.queryByRole("button", { name: "Try again" }),
|
|
@@ -480,25 +501,14 @@ describe("connection notice", () => {
|
|
|
480
501
|
);
|
|
481
502
|
});
|
|
482
503
|
|
|
483
|
-
it("replaces environment state from snapshots, then continues live progress", () => {
|
|
504
|
+
it("replaces environment state from snapshots, then continues live progress", async () => {
|
|
484
505
|
const store = createStore();
|
|
485
|
-
|
|
486
|
-
vi.mocked(
|
|
487
|
-
makeTransport(WebSocket.OPEN),
|
|
488
|
-
);
|
|
489
|
-
vi.mocked(useRuntimeManager).mockReturnValue(
|
|
490
|
-
makeRuntimeManager() as unknown as ReturnType<typeof useRuntimeManager>,
|
|
491
|
-
);
|
|
506
|
+
const fake = withTransport();
|
|
507
|
+
vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
|
|
492
508
|
renderConnectionHook(store);
|
|
493
|
-
|
|
509
|
+
await started();
|
|
494
510
|
function receive(data: NotificationPayload["data"]) {
|
|
495
|
-
act(() =>
|
|
496
|
-
options?.onMessage(
|
|
497
|
-
new MessageEvent("message", {
|
|
498
|
-
data: JSON.stringify({ op: data.op, data }),
|
|
499
|
-
}),
|
|
500
|
-
),
|
|
501
|
-
);
|
|
511
|
+
act(() => connection(fake).send(data));
|
|
502
512
|
}
|
|
503
513
|
receive({
|
|
504
514
|
op: "environment-operation",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { CloseDecision } from "../host/connection";
|
|
4
|
+
import { Logger } from "@/utils/Logger";
|
|
5
|
+
import { ConnectionState, WebSocketClosedReason } from "./types";
|
|
6
|
+
|
|
7
|
+
// Keep server reasons in sync with ws_endpoint.py and ws/*.py.
|
|
8
|
+
// SSE carries the same reasons in close events. Unclassified reasons retry.
|
|
9
|
+
export function classifyCloseEvent(event: { reason?: string }): CloseDecision {
|
|
10
|
+
switch (event.reason) {
|
|
11
|
+
case "MARIMO_NO_FILE_KEY":
|
|
12
|
+
case "MARIMO_NO_SESSION_ID":
|
|
13
|
+
case "MARIMO_NO_SESSION":
|
|
14
|
+
case "MARIMO_SHUTDOWN":
|
|
15
|
+
return {
|
|
16
|
+
kind: "terminal",
|
|
17
|
+
status: {
|
|
18
|
+
state: ConnectionState.CLOSED,
|
|
19
|
+
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
20
|
+
reason: "kernel not found",
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
case "MARIMO_UNAUTHORIZED":
|
|
24
|
+
return {
|
|
25
|
+
kind: "terminal",
|
|
26
|
+
status: {
|
|
27
|
+
state: ConnectionState.CLOSED,
|
|
28
|
+
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
29
|
+
reason: "not authorized",
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
case "MARIMO_KIOSK_NOT_ALLOWED":
|
|
33
|
+
return {
|
|
34
|
+
kind: "terminal",
|
|
35
|
+
status: {
|
|
36
|
+
state: ConnectionState.CLOSED,
|
|
37
|
+
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
38
|
+
reason: "kiosk mode is not available for this session",
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
case "MARIMO_KERNEL_STARTUP_ERROR":
|
|
42
|
+
return {
|
|
43
|
+
kind: "terminal",
|
|
44
|
+
status: {
|
|
45
|
+
state: ConnectionState.CLOSED,
|
|
46
|
+
code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
|
|
47
|
+
reason: "Failed to start kernel sandbox",
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
default:
|
|
51
|
+
if (event.reason) {
|
|
52
|
+
Logger.warn("Unrecognized connection close reason", event.reason);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
kind: "retry",
|
|
58
|
+
status: { state: ConnectionState.CONNECTING },
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { atom } from "jotai";
|
|
4
|
+
import type { NotebookClient } from "../host/notebook-client";
|
|
5
|
+
|
|
6
|
+
/** The client owned by the mounted notebook session. */
|
|
7
|
+
export const notebookClientAtom = atom<NotebookClient | null>(null);
|