@marimo-team/frontend 0.25.3-dev5 → 0.25.3-dev55
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-cD3S0wEA.js +1 -0
- package/dist/assets/{ConnectedDataExplorerComponent-t8fH_TNc.js → ConnectedDataExplorerComponent-D9UK8o9A.js} +1 -1
- package/dist/assets/{ErrorBoundary-B4n9EnHB.js → ErrorBoundary-DJhsFCsX.js} +2 -2
- package/dist/assets/JsonOutput-Pm6OCP3J.js +11 -0
- package/dist/assets/{LazyAnyLanguageCodeMirror-CKcCbG2G.js → LazyAnyLanguageCodeMirror-BPYE76jR.js} +2 -2
- package/dist/assets/MarimoErrorOutput-DlEjLCZ-.js +10 -0
- package/dist/assets/{RenderHTML-9bMgbYmo.js → RenderHTML-CfQ6i3QV.js} +1 -1
- package/dist/assets/RunButton-DvuvkgrG.js +1 -0
- package/dist/assets/{add-cell-with-ai-C_SruRWS.js → add-cell-with-ai-BhmuohAY.js} +7 -7
- package/dist/assets/{add-connection-dialog-CoE_PhuD.js → add-connection-dialog-D7EYSraq.js} +2 -2
- package/dist/assets/{agent-panel-0b3k4QzJ.js → agent-panel-GFhlWVub.js} +3 -3
- package/dist/assets/ai-model-dropdown-YT1HiXiK.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-iXdCWvfC.js → app-config-button-C_whRVO8.js} +1 -1
- package/dist/assets/arrays-0R2reF2y.js +1 -0
- package/dist/assets/{blob-iOBwGaP9.js → blob-e6VlOmQP.js} +1 -1
- package/dist/assets/{button-COI-NGrx.js → button-D8gVKwe-.js} +1 -1
- package/dist/assets/{cache-panel-DTY1dqvi.js → cache-panel-Byolv2ht.js} +1 -1
- package/dist/assets/{capabilities-BJvf-MD4.js → capabilities-Pq1YNPlK.js} +1 -1
- package/dist/assets/{cell-editor-CR-tZNnc.js → cell-editor-3cVIcyHK.js} +6 -6
- package/dist/assets/cell-link-DFqfW-Ym.js +1 -0
- package/dist/assets/{cells-rA_jsZCj.js → cells-T9_Y4Jlv.js} +56 -56
- package/dist/assets/{chat-display-luF7psRA.js → chat-display-BtaARI-N.js} +1 -1
- package/dist/assets/chat-panel-eT2lfQrB.js +4 -0
- package/dist/assets/chat-ui-nNFa2LdU.js +4 -0
- package/dist/assets/{circle-DXf-VWZG.js → circle-B6D_6D8w.js} +1 -1
- package/dist/assets/code-visibility-CV3S4xuf.js +1 -0
- package/dist/assets/coerce-DWjFeXOY.js +1 -0
- package/dist/assets/{column-preview-uosAAL4X.js → column-preview-C6uXRJry.js} +1 -1
- package/dist/assets/command-palette-OZPTmtR-.js +1 -0
- package/dist/assets/{common-lisZ0l6a.js → common-DeeLgjWQ.js} +1 -1
- package/dist/assets/{components-CP_UoFtT.js → components-DrU8dOzy.js} +1 -1
- package/dist/assets/{components-S7ZwOrvO.js → components-DyAF3_Nf.js} +1 -1
- package/dist/assets/{components-CXfO-F47.js → components-lDm0qi2t.js} +1 -1
- package/dist/assets/config-CjQ4WJnJ.js +1 -0
- package/dist/assets/config-DGX7JYor.js +1 -0
- package/dist/assets/config-DzdxZb17.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-HKXUbqyz.js} +1 -1
- package/dist/assets/{datasource-V0-52XOh.js → datasource-gqFgG9Qd.js} +1 -1
- package/dist/assets/{dates-CfmdTL6B.js → dates-CQMwFko2.js} +1 -1
- package/dist/assets/{dependency-graph-panel-B0uP-_id.js → dependency-graph-panel-BFFxLgR6.js} +1 -1
- package/dist/assets/{dist-iaThVDkA.js → dist-jlhMTKo_.js} +1 -1
- package/dist/assets/{documentation-panel-DVl_ebWy.js → documentation-panel-BBpGbT-f.js} +1 -1
- package/dist/assets/{download-Bx55LMki.js → download-C8Gw-D0Y.js} +1 -1
- package/dist/assets/{dropdown-menu-C1rnl-0o.js → dropdown-menu-DS6umAnH.js} +1 -1
- package/dist/assets/{edit-page-CGyjT-CQ.js → edit-page-B0lN_Rib.js} +6 -6
- package/dist/assets/{error-banner-Cd69vvyX.js → error-banner-B5kzVf_0.js} +1 -1
- package/dist/assets/{error-entries-DOWpdGvI.js → error-entries-uyqOG5tg.js} +1 -1
- package/dist/assets/{error-panel-C-uxLOHF.js → error-panel-Cli5zPWi.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-B99ThNJW.js → feedback-button-CvrwBGr7.js} +2 -2
- package/dist/assets/feedback-button-DknbRCN_.js +1 -0
- package/dist/assets/file-explorer-panel-BSU5ultY.js +1 -0
- package/dist/assets/{file-name-input-ChnBsDE_.js → file-name-input-CDrRlIiX.js} +1 -1
- package/dist/assets/{floating-outline-MYqQW4Vp.js → floating-outline-GQD9km0W.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-DSL0J4md.js → gallery-page-CxmV1JLF.js} +1 -1
- package/dist/assets/{ganttDiagram-EL5Y4UJY-2n7Ig5Jm.js → ganttDiagram-EL5Y4UJY-CYqkCfFG.js} +1 -1
- package/dist/assets/{glide-data-editor-B1MWlKeM.js → glide-data-editor-B1kpoetH.js} +2 -2
- package/dist/assets/{glide-utils-CIrAxdjv.js → glide-utils-HFqhvWHI.js} +2 -2
- package/dist/assets/{home-page-B1M3X9Yf.js → home-page-KnJyha6O.js} +3 -3
- package/dist/assets/{hooks-Bj0C0zrZ.js → hooks-w6zKs3CJ.js} +1 -1
- package/dist/assets/{html-to-image-DK9Zl1lU.js → html-to-image-D_0rd3_B.js} +1 -1
- package/dist/assets/index-Bu8_lPMx.js +30 -0
- package/dist/assets/index-evFWHKmM.css +2 -0
- package/dist/assets/{input-BoBxR50a.js → input-BZdRe7pb.js} +1 -1
- package/dist/assets/{kiosk-mode-BZECfg9k.js → kiosk-mode-BGmMSc7A.js} +1 -1
- package/dist/assets/layout-sYdHI-lW.js +9 -0
- package/dist/assets/linear-Bma8J3iM.js +1 -0
- package/dist/assets/links-CXcpNIM0.js +1 -0
- package/dist/assets/{logs-panel-y0XnfulJ.js → logs-panel-CdUc5vtA.js} +1 -1
- package/dist/assets/{markdown-renderer-Q5AhbRU3.js → markdown-renderer-pKc_bFac.js} +1 -1
- package/dist/assets/{menu-items-BrwnTgyK.js → menu-items-BgUyNUpu.js} +1 -1
- package/dist/assets/{mermaid-a3xYymTy.js → mermaid-B6mqMm5_.js} +2 -2
- package/dist/assets/{name-cell-input-BNOnF6-0.js → name-cell-input-csH3Cy54.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-Be7stWwv.js → outline-panel-DhsHYTuo.js} +1 -1
- package/dist/assets/packages-panel-lkNX6Oov.js +1 -0
- package/dist/assets/{panel-accordion-state-GeMEdCPw.js → panel-accordion-state-Bco6nsUI.js} +1 -1
- package/dist/assets/panels-B2UqDbHy.js +107 -0
- package/dist/assets/precisionRound-BxlUs8G4.js +1 -0
- package/dist/assets/process-output-B2-bT4cq.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-YULOXf4h.js → readonly-code-display-Dsp6vWPh.js} +1 -1
- package/dist/assets/{readonly-python-code-CadgXgRu.js → readonly-python-code-B81AjzXM.js} +1 -1
- package/dist/assets/{renderShortcut-BkVJQ_Zh.js → renderShortcut-H60uiHBp.js} +1 -1
- package/dist/assets/{reveal-component-B9FLjTg_.js → reveal-component-CrQRQhW4.js} +37 -37
- package/dist/assets/run-page-BGzpa3D9.js +1 -0
- package/dist/assets/{runs-BLp5jezv.js → runs-6lJxKV1w.js} +1 -1
- package/dist/assets/{runtime-details-state-DuChzsA6.js → runtime-details-state-CznIe40L.js} +1 -1
- package/dist/assets/{schemas-Dv42wLFq.js → schemas-ChRqMOTL.js} +1 -1
- package/dist/assets/{scratchpad-panel-DtB0A8xj.js → scratchpad-panel-ClLxdqdK.js} +1 -1
- 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-Dh3v7XPE.js} +1 -1
- package/dist/assets/{select-DTBn5eTb.js → select-3CVGlYrC.js} +1 -1
- package/dist/assets/{session-DqoWmb7X.js → session-B8Y-GJnS.js} +1 -1
- package/dist/assets/{session-panel-B6tA28BD.js → session-panel-C7-wmZhc.js} +1 -1
- package/dist/assets/{snippets-panel-CQ1dn3lA.js → snippets-panel-BARpOPyS.js} +1 -1
- package/dist/assets/{spec-BfSBcO5B.js → spec-uCpVvaAR.js} +1 -1
- package/dist/assets/{state-BUsmcyaT.js → state-BRYi026f.js} +3 -3
- package/dist/assets/{state-uwRvJLb8.js → state-BY4_P6ko.js} +1 -1
- package/dist/assets/{state-Bfh_2SLl.js → state-Bye6rCo4.js} +1 -1
- package/dist/assets/{state-BAJYRhmO.js → state-C0irhlOZ.js} +1 -1
- package/dist/assets/{state-DxQnC_1I.js → state-Ck7FMD5A.js} +1 -1
- package/dist/assets/{state-C3oDoyFe.js → state-DaWgt-rn.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-IoWE8PbW.js} +1 -1
- package/dist/assets/{tabs-BuQlZFbt.js → tabs-CY8E4r9U.js} +1 -1
- package/dist/assets/{terminal-Ck_vK-34.js → terminal-Bhcn_y1N.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-BW2ZVnXs.js +1 -0
- package/dist/assets/{tracing-panel-dgnr2fIN.js → tracing-panel-UKdh_YXC.js} +2 -2
- package/dist/assets/{tree-actions-DAd80MbP.js → tree-actions-Cb-nUK1F.js} +1 -1
- package/dist/assets/{use-restore-focus-BxEGwIbk.js → use-restore-focus-DdS7Tl0F.js} +1 -1
- package/dist/assets/{useAddCell-DGstJK0S.js → useAddCell-Bielffe0.js} +1 -1
- package/dist/assets/useAsyncData-DhhdOGGd.js +1 -0
- package/dist/assets/useBoolean-CMgj9hnq.js +1 -0
- package/dist/assets/{useCellActionButton-DY9RlJTb.js → useCellActionButton-Cu34Zs6x.js} +1 -1
- package/dist/assets/useDebounce-k9QTpQ9-.js +1 -0
- package/dist/assets/useDelayElapsed-BlsDT4TV.js +1 -0
- package/dist/assets/{useDeleteCell-DFBGlSQk.js → useDeleteCell-BV4VemCv.js} +1 -1
- package/dist/assets/{useDependencyPanelTab-DydxsE5d.js → useDependencyPanelTab-BEGqRiWi.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-C7neMPwh.js} +1 -1
- package/dist/assets/{useInterval--x3s1VpI.js → useInterval-DJdQmXnq.js} +1 -1
- package/dist/assets/{useNotebookActions-CupIPSlg.js → useNotebookActions-OLol05t9.js} +1 -1
- package/dist/assets/{useRunCells-BFjFX3hz.js → useRunCells-BFeZMi7f.js} +1 -1
- package/dist/assets/{useSplitCell-Tqv5pPtL.js → useSplitCell-DllkNFke.js} +1 -1
- package/dist/assets/useStateForKey-CGMJQT8x.js +1 -0
- package/dist/assets/{useTheme-COhSHkCj.js → useTheme-DLtPc-39.js} +1 -1
- package/dist/assets/{utils-CaQYvazl.js → utils-DfElfBpz.js} +1 -1
- package/dist/assets/vega-component-D7JFthDD.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/{write-secret-modal-DzKAInL2.js → write-secret-modal-7DzehGyr.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-KbGzG6-u.js → xychartDiagram-S5SC5T6Z-CeRnBS5e.js} +1 -1
- package/dist/index.html +76 -74
- package/package.json +4 -4
- package/src/__tests__/fixtures/{pair-preview.ts → pair-config.ts} +3 -2
- package/src/__tests__/host-imports.test.ts +1 -0
- package/src/__tests__/mount.test.ts +8 -8
- package/src/components/app-config/ai-config.tsx +6 -2
- package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
- package/src/components/chat/chat-panel.tsx +3 -7
- package/src/components/chat/chat-utils.ts +4 -8
- package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
- 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/charts/charts.tsx +14 -19
- package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
- package/src/components/data-table/columns.tsx +2 -1
- package/src/components/data-table/context-menu.tsx +36 -20
- 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/editor/Output.tsx +5 -1
- 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/cell/CreateCellButton.tsx +8 -10
- 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/packages-panel.tsx +4 -7
- package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +277 -78
- package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +196 -41
- 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 +139 -36
- package/src/components/editor/errors/send-error-report-button.tsx +10 -7
- 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/output/MarimoTracebackOutput.tsx +28 -22
- package/src/components/editor/output/console/ConsoleOutput.tsx +8 -18
- package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
- package/src/components/icons/large-spinner.tsx +3 -14
- package/src/components/pages/home-page.tsx +4 -4
- package/src/components/slides/slide-cell-view.tsx +1 -1
- package/src/components/tracing/tracing.tsx +2 -2
- package/src/core/attachments/__tests__/toast.test.tsx +58 -0
- package/src/core/attachments/state.ts +5 -8
- package/src/core/attachments/toast.ts +15 -0
- package/src/core/cells/__tests__/error-report.test.ts +53 -3
- package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
- package/src/core/cells/__tests__/session.test.ts +18 -3
- package/src/core/cells/cells.ts +2 -1
- package/src/core/cells/error-report.ts +14 -6
- package/src/core/cells/pending-delete-service.ts +2 -6
- package/src/core/cells/session.ts +19 -1
- 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/edit-app.tsx +2 -2
- package/src/core/host/AGENTS.md +11 -2
- 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__/events.test.ts +49 -0
- package/src/core/host/__tests__/fixtures.ts +41 -0
- package/src/core/host/__tests__/notebook-client.test.ts +496 -0
- package/src/core/host/connection.ts +81 -0
- package/src/core/host/events.ts +68 -0
- package/src/core/host/notebook-client.ts +316 -0
- package/src/core/host/resources/attachments.ts +19 -0
- package/src/core/host/resources/document.ts +101 -0
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/islands/__tests__/bootstrap.test.ts +0 -26
- package/src/core/islands/bootstrap.ts +0 -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__/runtime.test.ts +5 -12
- package/src/core/runtime/runtime.ts +5 -5
- package/src/core/static/files.ts +2 -0
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.test.ts → connection-state.test.ts} +15 -17
- package/src/core/websocket/__tests__/{useWebSocket.test.ts → createConnectionTransport.test.ts} +1 -1
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +149 -0
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.hook.test.tsx → useNotebookSession.hook.test.tsx} +168 -253
- package/src/core/websocket/connection-state.ts +70 -0
- package/src/core/websocket/state.ts +7 -0
- package/src/core/websocket/transports/__tests__/sse.test.ts +18 -4
- package/src/core/websocket/transports/create.ts +31 -0
- package/src/core/websocket/transports/sse.ts +14 -2
- package/src/core/websocket/transports/transport.ts +12 -23
- package/src/core/websocket/types.ts +9 -39
- package/src/core/websocket/useNotebookClient.ts +78 -0
- package/src/core/websocket/{useMarimoKernelConnection.tsx → useNotebookSession.tsx} +53 -233
- 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/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/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 +10 -9
- 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/mpl-interactive/MplInteractivePlugin.tsx +5 -3
- package/src/plugins/impl/panel/PanelPlugin.tsx +15 -16
- 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 +3 -6
- package/src/stories/__tests__/editor-story.test.tsx +33 -0
- package/src/stories/editor.stories.tsx +24 -17
- package/src/utils/__tests__/arrays.test.ts +35 -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/numbers.ts +28 -17
- package/src/utils/objects.ts +3 -7
- package/src/utils/once.ts +19 -19
- package/dist/assets/CellStatus-nZpuDkm7.js +0 -1
- package/dist/assets/JsonOutput-d-k8v_17.js +0 -11
- package/dist/assets/MarimoErrorOutput-CLYUxiKW.js +0 -10
- package/dist/assets/RunButton-CFQUNN5c.js +0 -1
- package/dist/assets/ai-model-dropdown-C6GHHEdR.js +0 -5
- package/dist/assets/any-language-editor-BLCAD3yx.js +0 -1
- package/dist/assets/arrays-BqUx5USx.js +0 -1
- package/dist/assets/cell-link-1CynTVGQ.js +0 -1
- package/dist/assets/chat-panel-DDDTnLvB.js +0 -4
- package/dist/assets/chat-ui-nV_m4Btr.js +0 -4
- package/dist/assets/code-visibility-B-_GvwR5.js +0 -1
- package/dist/assets/coerce-CpE6kUdX.js +0 -1
- package/dist/assets/command-palette-BZ13RKDJ.js +0 -1
- package/dist/assets/config-DX8Y2WbJ.js +0 -1
- package/dist/assets/config-FzDtjF1-.js +0 -1
- package/dist/assets/config-VPSq73n8.js +0 -1
- package/dist/assets/feedback-button-DlqZkJwz.js +0 -1
- package/dist/assets/file-explorer-panel-D3CphidS.js +0 -1
- package/dist/assets/index-CXIE-QEG.css +0 -2
- package/dist/assets/index-DnIgeCyQ.js +0 -29
- package/dist/assets/layout-DBuMeWh0.js +0 -9
- package/dist/assets/linear-0eij_aAG.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-9Qs1npCZ.js +0 -1
- package/dist/assets/panels-B9x935By.js +0 -4
- package/dist/assets/precisionRound-Bq_nmf5u.js +0 -1
- package/dist/assets/process-output-DNFKMODr.js +0 -1
- package/dist/assets/react-vega-C3rYGtP6.js +0 -189
- package/dist/assets/run-page-CjdGaic3.js +0 -1
- package/dist/assets/tooltip-mT3CGest.js +0 -61
- package/dist/assets/tracing-BARlJ_Dk.js +0 -1
- package/dist/assets/useAsyncData-C7aJJz0Y.js +0 -1
- package/dist/assets/useBoolean-BDD6_xQQ.js +0 -1
- package/dist/assets/useDebounce-B_ccBZTp.js +0 -1
- package/dist/assets/vega-component-CnadTgoE.js +0 -1
- package/dist/assets/vega-loader.browser-CLRkNgm7.js +0 -6
- package/src/core/host/__tests__/protocol.test.ts +0 -214
- package/src/core/host/protocol.ts +0 -1943
- package/src/core/websocket/useWebSocket.tsx +0 -88
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
TableIcon,
|
|
15
15
|
} from "lucide-react";
|
|
16
16
|
import React from "react";
|
|
17
|
+
import useEvent from "react-use-event-hook";
|
|
17
18
|
import { downloadSizeLimitAtom } from "./download-policy/atoms";
|
|
18
19
|
import type {
|
|
19
20
|
DownloadAsArgs,
|
|
@@ -22,6 +23,8 @@ import type {
|
|
|
22
23
|
ExportMetadata,
|
|
23
24
|
GetExportMetadata,
|
|
24
25
|
} from "./schemas";
|
|
26
|
+
import { useAsyncData } from "@/hooks/useAsyncData";
|
|
27
|
+
import { useStateForKey } from "@/hooks/useStateForKey";
|
|
25
28
|
import { logNever } from "@/utils/assertNever";
|
|
26
29
|
import { cn } from "@/utils/cn";
|
|
27
30
|
import { copyToClipboard } from "@/utils/copy";
|
|
@@ -274,19 +277,133 @@ const failureTitleForAction = (action: ExportAction): string =>
|
|
|
274
277
|
const failureDescription = (error: unknown): string =>
|
|
275
278
|
typeof error === "string" ? error : prettyError(error);
|
|
276
279
|
|
|
280
|
+
const OBSOLETE_GEOMETRY_MESSAGE =
|
|
281
|
+
"The selected geometry is no longer available. Choose another geometry to export.";
|
|
282
|
+
|
|
283
|
+
type GeographicBlocker =
|
|
284
|
+
| "format-unavailable"
|
|
285
|
+
| "geometry-required"
|
|
286
|
+
| "choose-geometry"
|
|
287
|
+
| "obsolete-geometry"
|
|
288
|
+
| "missing-crs";
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Find the first reason that a geographic export cannot start with the
|
|
292
|
+
* selected geometry. The dialog uses it to disable a format, and the retry
|
|
293
|
+
* after a package installation uses it to decide whether to export.
|
|
294
|
+
*/
|
|
295
|
+
function geographicBlocker(
|
|
296
|
+
metadata: ExportMetadata,
|
|
297
|
+
format: GeographicFormat,
|
|
298
|
+
geometryColumn: string | null,
|
|
299
|
+
): GeographicBlocker | null {
|
|
300
|
+
if (metadata.formats[format]?.available === false) {
|
|
301
|
+
return "format-unavailable";
|
|
302
|
+
}
|
|
303
|
+
const selected = metadata.geometry_columns.find(
|
|
304
|
+
(column) => column.name === geometryColumn,
|
|
305
|
+
);
|
|
306
|
+
if (geometryColumn !== null && !selected) {
|
|
307
|
+
return "obsolete-geometry";
|
|
308
|
+
}
|
|
309
|
+
if (metadata.geometry_columns.length === 0) {
|
|
310
|
+
return format === "geojson" ? "geometry-required" : null;
|
|
311
|
+
}
|
|
312
|
+
if (!selected) {
|
|
313
|
+
return "choose-geometry";
|
|
314
|
+
}
|
|
315
|
+
if (format === "geojson" && !selected.crs) {
|
|
316
|
+
return "missing-crs";
|
|
317
|
+
}
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const geometryDisplayName = (name: string | null): string | null =>
|
|
322
|
+
name === "" ? "(unnamed geometry)" : name;
|
|
323
|
+
|
|
324
|
+
function geographicBlockerReason(
|
|
325
|
+
blocker: GeographicBlocker | null,
|
|
326
|
+
formatLabel: string,
|
|
327
|
+
geometryColumn: string | null,
|
|
328
|
+
): string | null {
|
|
329
|
+
switch (blocker) {
|
|
330
|
+
case "choose-geometry":
|
|
331
|
+
return `Choose a primary geometry column to export ${formatLabel}.`;
|
|
332
|
+
case "obsolete-geometry":
|
|
333
|
+
return OBSOLETE_GEOMETRY_MESSAGE;
|
|
334
|
+
case "missing-crs":
|
|
335
|
+
return `Geometry column ${geometryDisplayName(geometryColumn)} needs a CRS for GeoJSON export. Declare its source CRS in Python before exporting.`;
|
|
336
|
+
case "format-unavailable":
|
|
337
|
+
case "geometry-required":
|
|
338
|
+
case null:
|
|
339
|
+
return null;
|
|
340
|
+
default:
|
|
341
|
+
logNever(blocker);
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* One open dialog for one table source. Closing the dialog or replacing the
|
|
348
|
+
* source creates a new context, and work started under an older context must
|
|
349
|
+
* not change the dialog or start an export.
|
|
350
|
+
*/
|
|
351
|
+
interface ExportContext {
|
|
352
|
+
source: unknown;
|
|
353
|
+
}
|
|
354
|
+
|
|
277
355
|
export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
278
356
|
const { getExportMetadata, metadataSource } = props;
|
|
279
357
|
const [exportDialogOpen, setExportDialogOpen] = React.useState(false);
|
|
280
|
-
const [failure, setFailure] = React.useState<ExportFailure | null>(null);
|
|
281
358
|
const [settings, setSettings] =
|
|
282
359
|
React.useState<ExportSettings>(DEFAULT_SETTINGS);
|
|
283
|
-
const [
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
360
|
+
const [exportContext, setExportContext] = React.useState<ExportContext>(
|
|
361
|
+
() => ({ source: metadataSource }),
|
|
362
|
+
);
|
|
363
|
+
if (exportContext.source !== metadataSource) {
|
|
364
|
+
setExportContext({ source: metadataSource });
|
|
365
|
+
}
|
|
366
|
+
const [failure, setFailure] = useStateForKey<ExportFailure | null>(
|
|
367
|
+
exportContext,
|
|
368
|
+
() => null,
|
|
369
|
+
);
|
|
370
|
+
const mounted = React.useRef(false);
|
|
371
|
+
const isCurrentContext = useEvent(
|
|
372
|
+
(context: ExportContext) => mounted.current && context === exportContext,
|
|
373
|
+
);
|
|
374
|
+
const metadataRequest = useAsyncData(async () => {
|
|
375
|
+
if (!exportDialogOpen || !getExportMetadata) {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
return { context: exportContext, metadata: await getExportMetadata({}) };
|
|
379
|
+
}, [exportDialogOpen, getExportMetadata, exportContext]);
|
|
380
|
+
// The hook keeps earlier data while it reloads and after a failure. Only a
|
|
381
|
+
// completed response for the current context can enable an export.
|
|
382
|
+
const metadata =
|
|
383
|
+
metadataRequest.status === "success" &&
|
|
384
|
+
metadataRequest.data?.context === exportContext
|
|
385
|
+
? metadataRequest.data.metadata
|
|
386
|
+
: null;
|
|
387
|
+
const metadataError =
|
|
388
|
+
metadataRequest.status === "error"
|
|
389
|
+
? failureDescription(metadataRequest.error)
|
|
390
|
+
: null;
|
|
287
391
|
const [geometryColumn, setGeometryColumn] = React.useState<string | null>(
|
|
288
392
|
null,
|
|
289
393
|
);
|
|
394
|
+
const [reconciledMetadata, setReconciledMetadata] =
|
|
395
|
+
React.useState<ExportMetadata | null>(null);
|
|
396
|
+
if (metadata !== reconciledMetadata) {
|
|
397
|
+
setReconciledMetadata(metadata);
|
|
398
|
+
if (metadata) {
|
|
399
|
+
setGeometryColumn((current) =>
|
|
400
|
+
current !== null &&
|
|
401
|
+
metadata.geometry_columns.some((column) => column.name === current)
|
|
402
|
+
? current
|
|
403
|
+
: metadata.default_geometry_column,
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
290
407
|
const hasGeometry = !!metadata?.geometry_columns.length;
|
|
291
408
|
const [expandedFormat, setExpandedFormat] = React.useState<
|
|
292
409
|
ConfigurableFormat | GeographicFormat | null
|
|
@@ -294,43 +411,16 @@ export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
|
294
411
|
const triggerRef = React.useRef<HTMLButtonElement>(null);
|
|
295
412
|
const dialogRef = React.useRef<HTMLDivElement>(null);
|
|
296
413
|
const latestActionId = React.useRef(0);
|
|
414
|
+
React.useLayoutEffect(() => {
|
|
415
|
+
mounted.current = true;
|
|
416
|
+
return () => {
|
|
417
|
+
mounted.current = false;
|
|
418
|
+
latestActionId.current += 1;
|
|
419
|
+
};
|
|
420
|
+
}, []);
|
|
297
421
|
React.useEffect(() => {
|
|
298
422
|
latestActionId.current += 1;
|
|
299
423
|
}, [metadataSource]);
|
|
300
|
-
React.useEffect(() => {
|
|
301
|
-
if (!exportDialogOpen || !getExportMetadata) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
let active = true;
|
|
305
|
-
setMetadata(null);
|
|
306
|
-
setMetadataLoading(true);
|
|
307
|
-
setMetadataError(null);
|
|
308
|
-
void getExportMetadata({}).then(
|
|
309
|
-
(result) => {
|
|
310
|
-
if (!active) {
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
setMetadata(result);
|
|
314
|
-
setGeometryColumn((current) =>
|
|
315
|
-
current !== null &&
|
|
316
|
-
result.geometry_columns.some((column) => column.name === current)
|
|
317
|
-
? current
|
|
318
|
-
: result.default_geometry_column,
|
|
319
|
-
);
|
|
320
|
-
setMetadataLoading(false);
|
|
321
|
-
},
|
|
322
|
-
(error: unknown) => {
|
|
323
|
-
if (!active) {
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
setMetadataError(failureDescription(error));
|
|
327
|
-
setMetadataLoading(false);
|
|
328
|
-
},
|
|
329
|
-
);
|
|
330
|
-
return () => {
|
|
331
|
-
active = false;
|
|
332
|
-
};
|
|
333
|
-
}, [exportDialogOpen, getExportMetadata, metadataSource, metadataRefresh]);
|
|
334
424
|
const policy = useAtomValue(downloadSizeLimitAtom);
|
|
335
425
|
const overLimit = !!(
|
|
336
426
|
policy &&
|
|
@@ -365,12 +455,10 @@ export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
|
365
455
|
setExportDialogOpen(open);
|
|
366
456
|
if (!open) {
|
|
367
457
|
latestActionId.current += 1;
|
|
368
|
-
setFailure(null);
|
|
369
458
|
setExpandedFormat(null);
|
|
370
459
|
setSettings(DEFAULT_SETTINGS);
|
|
371
|
-
setMetadata(null);
|
|
372
|
-
setMetadataError(null);
|
|
373
460
|
setGeometryColumn(null);
|
|
461
|
+
setExportContext({ source: metadataSource });
|
|
374
462
|
}
|
|
375
463
|
};
|
|
376
464
|
|
|
@@ -553,57 +641,67 @@ export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
|
553
641
|
}
|
|
554
642
|
};
|
|
555
643
|
|
|
556
|
-
|
|
557
|
-
|
|
644
|
+
// Package installation can finish after the dialog closes or the source
|
|
645
|
+
// changes, so the retry carries the context in which installation began.
|
|
646
|
+
const retryAfterInstall = useEvent(
|
|
647
|
+
async (action: ExportAction, context: ExportContext) => {
|
|
648
|
+
if (!isCurrentContext(context)) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
if (!isGeographic(action.format) || !getExportMetadata) {
|
|
652
|
+
retryAction(action);
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
558
655
|
const actionId = latestActionId.current;
|
|
656
|
+
const isCurrent = () =>
|
|
657
|
+
isCurrentContext(context) && actionId === latestActionId.current;
|
|
559
658
|
let result: ExportMetadata;
|
|
560
659
|
try {
|
|
561
660
|
result = await getExportMetadata({});
|
|
562
|
-
} catch
|
|
563
|
-
if (
|
|
564
|
-
|
|
661
|
+
} catch {
|
|
662
|
+
if (isCurrent()) {
|
|
663
|
+
metadataRequest.refetch();
|
|
565
664
|
}
|
|
566
665
|
return;
|
|
567
666
|
}
|
|
568
|
-
if (
|
|
569
|
-
return;
|
|
570
|
-
}
|
|
571
|
-
setMetadata(result);
|
|
572
|
-
setMetadataError(null);
|
|
573
|
-
if (result.formats[action.format]?.available === false) {
|
|
574
|
-
setFailure(null);
|
|
667
|
+
if (!isCurrent()) {
|
|
575
668
|
return;
|
|
576
669
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
(
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
return;
|
|
670
|
+
// Validation reads its own response, so a display refresh cannot
|
|
671
|
+
// start an export that this check rejected.
|
|
672
|
+
metadataRequest.refetch();
|
|
673
|
+
const blocker = geographicBlocker(result, action.format, geometryColumn);
|
|
674
|
+
switch (blocker) {
|
|
675
|
+
case null:
|
|
676
|
+
retryAction(action);
|
|
677
|
+
return;
|
|
678
|
+
case "obsolete-geometry":
|
|
679
|
+
setGeometryColumn(result.default_geometry_column);
|
|
680
|
+
setActionFailure(actionId, {
|
|
681
|
+
kind: "error",
|
|
682
|
+
title: failureTitleForAction(action),
|
|
683
|
+
description: OBSOLETE_GEOMETRY_MESSAGE,
|
|
684
|
+
action,
|
|
685
|
+
});
|
|
686
|
+
return;
|
|
687
|
+
case "choose-geometry":
|
|
688
|
+
return;
|
|
689
|
+
case "format-unavailable":
|
|
690
|
+
case "geometry-required":
|
|
691
|
+
case "missing-crs":
|
|
692
|
+
setFailure(null);
|
|
693
|
+
return;
|
|
694
|
+
default:
|
|
695
|
+
logNever(blocker);
|
|
604
696
|
}
|
|
605
|
-
}
|
|
606
|
-
|
|
697
|
+
},
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
const createInstallRetry = (action: ExportAction) => {
|
|
701
|
+
const context = exportContext;
|
|
702
|
+
return () => {
|
|
703
|
+
void retryAfterInstall(action, context);
|
|
704
|
+
};
|
|
607
705
|
};
|
|
608
706
|
|
|
609
707
|
const toggleExpanded = (format: ExportFormat) => {
|
|
@@ -665,14 +763,15 @@ export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
|
665
763
|
const expanded =
|
|
666
764
|
configurableFormat !== null &&
|
|
667
765
|
expandedFormat === configurableFormat;
|
|
766
|
+
const FormatHeader = configurableFormat ? "button" : "div";
|
|
668
767
|
const panelId = `export-options-${option.format}`;
|
|
768
|
+
const descriptionId = `${panelId}-description`;
|
|
769
|
+
const summaryId = `${panelId}-summary`;
|
|
669
770
|
const rowFailure =
|
|
670
771
|
failure?.action.format === option.format ? failure : null;
|
|
671
772
|
const summary =
|
|
672
773
|
isGeographic(option.format) && hasGeometry
|
|
673
|
-
? geometryColumn
|
|
674
|
-
? "(unnamed geometry)"
|
|
675
|
-
: (geometryColumn ?? "Choose geometry")
|
|
774
|
+
? (geometryDisplayName(geometryColumn) ?? "Choose geometry")
|
|
676
775
|
: settingsSummary(settings, option.format);
|
|
677
776
|
const selectedGeometryIndex =
|
|
678
777
|
metadata?.geometry_columns.findIndex(
|
|
@@ -681,20 +780,14 @@ export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
|
681
780
|
const eligibility = isGeographic(option.format)
|
|
682
781
|
? metadata?.formats[option.format]
|
|
683
782
|
: undefined;
|
|
684
|
-
const
|
|
685
|
-
metadata
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
selectedGeometry !== undefined &&
|
|
689
|
-
!selectedGeometry.crs;
|
|
783
|
+
const blocker =
|
|
784
|
+
isGeographic(option.format) && metadata
|
|
785
|
+
? geographicBlocker(metadata, option.format, geometryColumn)
|
|
786
|
+
: null;
|
|
690
787
|
const geometryReason = metadataError
|
|
691
788
|
? `Could not load geometry options: ${metadataError}`
|
|
692
789
|
: (eligibility?.reason ??
|
|
693
|
-
(
|
|
694
|
-
? `Choose a primary geometry column to export ${optionLabel}.`
|
|
695
|
-
: missingCrs
|
|
696
|
-
? `Geometry column ${geometryColumn === "" ? "(unnamed geometry)" : geometryColumn} needs a CRS for GeoJSON export. Declare its source CRS in Python before exporting.`
|
|
697
|
-
: null));
|
|
790
|
+
geographicBlockerReason(blocker, optionLabel, geometryColumn));
|
|
698
791
|
const missingPackageFailure =
|
|
699
792
|
rowFailure?.kind === "missing-packages" ? rowFailure : null;
|
|
700
793
|
const missingPackages =
|
|
@@ -704,13 +797,7 @@ export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
|
704
797
|
: []);
|
|
705
798
|
const geographicUnavailable =
|
|
706
799
|
isGeographic(option.format) &&
|
|
707
|
-
((!!getExportMetadata && !metadata) ||
|
|
708
|
-
metadataLoading ||
|
|
709
|
-
!!metadataError ||
|
|
710
|
-
eligibility?.available === false ||
|
|
711
|
-
missingCrs ||
|
|
712
|
-
(!!metadata?.geometry_columns.length &&
|
|
713
|
-
geometryColumn === null));
|
|
800
|
+
((!!getExportMetadata && !metadata) || blocker !== null);
|
|
714
801
|
const copyUnavailable =
|
|
715
802
|
isGeographic(option.format) &&
|
|
716
803
|
(geographicUnavailable || missingPackages.length > 0);
|
|
@@ -720,55 +807,78 @@ export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
|
720
807
|
data-testid={`export-row-${option.format}`}
|
|
721
808
|
className={cn(expanded && "bg-muted/40")}
|
|
722
809
|
>
|
|
723
|
-
<div className="grid
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
810
|
+
<div className="grid grid-cols-[minmax(0,1fr)_auto] items-center hover:bg-accent/50">
|
|
811
|
+
<FormatHeader
|
|
812
|
+
type={configurableFormat ? "button" : undefined}
|
|
813
|
+
className={cn(
|
|
814
|
+
"grid min-h-[60px] min-w-0 grid-cols-[28px_minmax(0,1fr)] items-center gap-x-1 py-2 pl-2.5 pr-1 text-left",
|
|
815
|
+
configurableFormat &&
|
|
816
|
+
"cursor-pointer focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring",
|
|
817
|
+
)}
|
|
818
|
+
aria-label={
|
|
819
|
+
configurableFormat ? `${optionLabel} options` : undefined
|
|
820
|
+
}
|
|
821
|
+
aria-describedby={
|
|
822
|
+
configurableFormat
|
|
823
|
+
? [descriptionId, summary && summaryId]
|
|
824
|
+
.filter(Boolean)
|
|
825
|
+
.join(" ")
|
|
826
|
+
: undefined
|
|
827
|
+
}
|
|
828
|
+
aria-expanded={configurableFormat ? expanded : undefined}
|
|
829
|
+
aria-controls={configurableFormat ? panelId : undefined}
|
|
830
|
+
onClick={
|
|
831
|
+
configurableFormat
|
|
832
|
+
? () => toggleExpanded(option.format)
|
|
833
|
+
: undefined
|
|
834
|
+
}
|
|
835
|
+
>
|
|
836
|
+
<span
|
|
837
|
+
aria-hidden={true}
|
|
838
|
+
className="inline-flex h-6 w-6 items-center justify-center"
|
|
733
839
|
>
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
840
|
+
{configurableFormat && (
|
|
841
|
+
<ChevronRightIcon
|
|
842
|
+
className={cn(
|
|
843
|
+
"h-4 w-4 text-muted-foreground transition-transform",
|
|
844
|
+
expanded && "rotate-90",
|
|
845
|
+
)}
|
|
846
|
+
/>
|
|
847
|
+
)}
|
|
848
|
+
</span>
|
|
849
|
+
<span className="flex min-w-0 items-center gap-3 pl-1">
|
|
850
|
+
<option.icon
|
|
851
|
+
aria-hidden={true}
|
|
852
|
+
data-testid={`export-format-icon-${option.format}`}
|
|
853
|
+
className="h-4 w-4 shrink-0 text-muted-foreground"
|
|
739
854
|
/>
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
<div className="flex min-w-0 items-center gap-3 pl-1">
|
|
745
|
-
<option.icon
|
|
746
|
-
aria-hidden={true}
|
|
747
|
-
data-testid={`export-format-icon-${option.format}`}
|
|
748
|
-
className="h-4 w-4 shrink-0 text-muted-foreground"
|
|
749
|
-
/>
|
|
750
|
-
<div className="grid min-w-0 gap-1">
|
|
751
|
-
<span className="flex min-w-0 items-baseline gap-x-2">
|
|
752
|
-
<span className="text-sm font-medium leading-tight">
|
|
753
|
-
{optionLabel}
|
|
754
|
-
</span>
|
|
755
|
-
{summary && (
|
|
756
|
-
<span
|
|
757
|
-
data-testid={`export-summary-${option.format}`}
|
|
758
|
-
className="min-w-0 truncate text-xs text-muted-foreground"
|
|
759
|
-
>
|
|
760
|
-
{summary}
|
|
855
|
+
<span className="grid min-w-0 gap-1">
|
|
856
|
+
<span className="flex min-w-0 items-baseline gap-x-2">
|
|
857
|
+
<span className="text-sm font-medium leading-tight">
|
|
858
|
+
{optionLabel}
|
|
761
859
|
</span>
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
860
|
+
{summary && (
|
|
861
|
+
<span
|
|
862
|
+
id={summaryId}
|
|
863
|
+
data-testid={`export-summary-${option.format}`}
|
|
864
|
+
className="min-w-0 truncate text-xs text-muted-foreground"
|
|
865
|
+
>
|
|
866
|
+
{summary}
|
|
867
|
+
</span>
|
|
868
|
+
)}
|
|
869
|
+
</span>
|
|
870
|
+
<span
|
|
871
|
+
id={descriptionId}
|
|
872
|
+
className="text-xs text-muted-foreground leading-tight"
|
|
873
|
+
>
|
|
874
|
+
{option.format === "parquet" && hasGeometry
|
|
875
|
+
? "Parquet with geometry and CRS metadata"
|
|
876
|
+
: option.description}
|
|
877
|
+
</span>
|
|
768
878
|
</span>
|
|
769
|
-
</
|
|
770
|
-
</
|
|
771
|
-
<div className="flex items-center gap-0.5">
|
|
879
|
+
</span>
|
|
880
|
+
</FormatHeader>
|
|
881
|
+
<div className="flex items-center gap-0.5 pr-2.5">
|
|
772
882
|
<Tooltip
|
|
773
883
|
content={
|
|
774
884
|
option.canDownload
|
|
@@ -888,9 +998,7 @@ export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
|
888
998
|
type="button"
|
|
889
999
|
size="xs"
|
|
890
1000
|
variant="outline"
|
|
891
|
-
onClick={
|
|
892
|
-
setMetadataRefresh((current) => current + 1)
|
|
893
|
-
}
|
|
1001
|
+
onClick={metadataRequest.refetch}
|
|
894
1002
|
>
|
|
895
1003
|
Retry
|
|
896
1004
|
</Button>
|
|
@@ -906,17 +1014,13 @@ export const ExportActions: React.FC<ExportActionProps> = (props) => {
|
|
|
906
1014
|
missingPackageFailure?.description ??
|
|
907
1015
|
eligibility?.reason
|
|
908
1016
|
}
|
|
909
|
-
onInstall={(
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
format:
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
: "parquet",
|
|
917
|
-
},
|
|
918
|
-
);
|
|
919
|
-
}}
|
|
1017
|
+
onInstall={createInstallRetry(
|
|
1018
|
+
missingPackageFailure?.action ?? {
|
|
1019
|
+
destination: "download",
|
|
1020
|
+
format:
|
|
1021
|
+
option.format === "geojson" ? "geojson" : "parquet",
|
|
1022
|
+
},
|
|
1023
|
+
)}
|
|
920
1024
|
className="items-start"
|
|
921
1025
|
/>
|
|
922
1026
|
</div>
|
|
@@ -34,6 +34,7 @@ import { DelayMount } from "@/components/utils/delay-mount";
|
|
|
34
34
|
import { useAsyncData } from "@/hooks/useAsyncData";
|
|
35
35
|
import { Banner, ErrorBanner } from "@/plugins/impl/common/error-banner";
|
|
36
36
|
import type { GetRowResult } from "@/plugins/impl/DataTablePlugin";
|
|
37
|
+
import { Objects } from "@/utils/objects";
|
|
37
38
|
import { NAMELESS_COLUMN_PREFIX, renderCellValue } from "../columns";
|
|
38
39
|
import { prettifyRowCount } from "../pagination";
|
|
39
40
|
import {
|
|
@@ -88,8 +89,7 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
|
|
|
88
89
|
handleRowSelectionChange?.((prev) => {
|
|
89
90
|
if (isRowSelected) {
|
|
90
91
|
// Remove this row from selection
|
|
91
|
-
|
|
92
|
-
return rest;
|
|
92
|
+
return Objects.filter(prev, (_, key) => key !== String(rowIdx));
|
|
93
93
|
}
|
|
94
94
|
// Add this row to selection
|
|
95
95
|
return { ...prev, [rowIdx]: true };
|
|
@@ -3,42 +3,6 @@
|
|
|
3
3
|
import z from "zod";
|
|
4
4
|
import { rpc } from "@/plugins/core/rpc";
|
|
5
5
|
|
|
6
|
-
export type DownloadFormat = "csv" | "json" | "parquet" | "tsv" | "geojson";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Per-request export options. Each field is optional. A missing field keeps
|
|
10
|
-
* the widget's default for that setting.
|
|
11
|
-
*/
|
|
12
|
-
export interface DownloadAsOptions {
|
|
13
|
-
separator?: string;
|
|
14
|
-
encoding?: string;
|
|
15
|
-
ensure_ascii?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface DownloadAsRequest {
|
|
19
|
-
format: DownloadFormat;
|
|
20
|
-
options?: DownloadAsOptions;
|
|
21
|
-
geometry_column?: string | null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export type DownloadAsArgs = (req: DownloadAsRequest) => Promise<{
|
|
25
|
-
url: string;
|
|
26
|
-
filename: string;
|
|
27
|
-
error?: string | null;
|
|
28
|
-
missing_packages?: string[] | null;
|
|
29
|
-
code?:
|
|
30
|
-
| "geometry_required"
|
|
31
|
-
| "invalid_geometry"
|
|
32
|
-
| "invalid_metadata"
|
|
33
|
-
| "unsupported_representation"
|
|
34
|
-
| "unsupported_version"
|
|
35
|
-
| "missing_packages"
|
|
36
|
-
| "missing_crs"
|
|
37
|
-
| "conversion_failed"
|
|
38
|
-
| null;
|
|
39
|
-
column?: string | null;
|
|
40
|
-
}>;
|
|
41
|
-
|
|
42
6
|
const DownloadRequestSchema = z.object({
|
|
43
7
|
geometry_column: z.string().nullish(),
|
|
44
8
|
options: z
|
|
@@ -88,6 +52,20 @@ export const DownloadGeoJSONSchema = rpc
|
|
|
88
52
|
}),
|
|
89
53
|
);
|
|
90
54
|
|
|
55
|
+
export type DownloadAsRequest =
|
|
56
|
+
| z.infer<typeof DownloadAsSchema.input>
|
|
57
|
+
| z.infer<typeof DownloadGeoJSONSchema.input>;
|
|
58
|
+
|
|
59
|
+
type DownloadResponse =
|
|
60
|
+
| z.infer<typeof DownloadAsSchema.output>
|
|
61
|
+
| z.infer<typeof DownloadGeoJSONSchema.output>;
|
|
62
|
+
|
|
63
|
+
export type DownloadFormat = DownloadAsRequest["format"];
|
|
64
|
+
export type DownloadAsOptions = NonNullable<DownloadAsRequest["options"]>;
|
|
65
|
+
export type DownloadAsArgs = (
|
|
66
|
+
req: DownloadAsRequest,
|
|
67
|
+
) => Promise<DownloadResponse>;
|
|
68
|
+
|
|
91
69
|
export type DownloadAsFunction = (
|
|
92
70
|
req: z.infer<typeof DownloadAsSchema.input>,
|
|
93
71
|
) => Promise<z.infer<typeof DownloadAsSchema.output>>;
|
|
@@ -66,7 +66,10 @@ export type OnRefactorWithAI = (opts: {
|
|
|
66
66
|
* Renders an output based on an OutputMessage.
|
|
67
67
|
*/
|
|
68
68
|
export const OutputRenderer: React.FC<{
|
|
69
|
-
message: Pick<
|
|
69
|
+
message: Pick<
|
|
70
|
+
OutputMessage,
|
|
71
|
+
"channel" | "data" | "mimetype" | "code" | "traceback_format"
|
|
72
|
+
>;
|
|
70
73
|
cellId?: CellId;
|
|
71
74
|
onRefactorWithAI?: OnRefactorWithAI;
|
|
72
75
|
wrapText?: boolean;
|
|
@@ -185,6 +188,7 @@ export const OutputRenderer: React.FC<{
|
|
|
185
188
|
<MarimoTracebackOutput
|
|
186
189
|
onRefactorWithAI={onRefactorWithAI}
|
|
187
190
|
traceback={data}
|
|
191
|
+
tracebackFormat={message.traceback_format}
|
|
188
192
|
code={message.code}
|
|
189
193
|
cellId={cellId}
|
|
190
194
|
/>
|