@marimo-team/frontend 0.15.5 → 0.16.0-dev96986
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/ConnectedDataExplorerComponent-CNLoZkWr.js +19 -0
- package/dist/assets/{ImageComparisonComponent-CEXMKKA4.js → ImageComparisonComponent-SX7fDaTK.js} +1 -1
- package/dist/assets/{VegaLite-Bt14Ds9k.js → VegaLite-MJUW3b7C.js} +6 -6
- package/dist/assets/_baseEach-9_logFrf.js +1 -0
- package/dist/assets/_baseMap-NzEbKt5c.js +1 -0
- package/dist/assets/_baseUniq-C5LFcyNC.js +1 -0
- package/dist/assets/_createAggregator-ZRm2b6Zm.js +1 -0
- package/dist/assets/agent-panel-BBd11wNX.js +287 -0
- package/dist/assets/agent-panel-D92Mfy1i.css +1 -0
- package/dist/assets/{any-language-editor-DiwNT6zp.js → any-language-editor-DwAaEQfS.js} +1 -1
- package/dist/assets/architectureDiagram-W76B3OCA-BJmVXUoW.js +36 -0
- package/dist/assets/{between-horizontal-start-FyewyCGn.js → between-horizontal-start-KiwU-a3C.js} +1 -1
- package/dist/assets/{blockDiagram-QIGZ2CNN-BrOkAf_c.js → blockDiagram-QIGZ2CNN-DzxZjE7B.js} +1 -1
- package/dist/assets/{c4Diagram-FPNF74CW-BHPzDxE2.js → c4Diagram-FPNF74CW-DjmldG_J.js} +5 -5
- package/dist/assets/channel-DHcKBVM4.js +1 -0
- package/dist/assets/chat-panel-DgJZr0eS.js +3 -0
- package/dist/assets/{chunk-4BX2VUAB-DLxaCNYh.js → chunk-4BX2VUAB-EUTQThiZ.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-DdzvO3HR.js → chunk-55IACEB6-DZAiDJxy.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-R5o-nSiG.js → chunk-FMBD7UC4-Bd0Czs-J.js} +1 -1
- package/dist/assets/{chunk-K7UQS3LO-DxaMrGgG.js → chunk-K7UQS3LO-DEKMIknX.js} +1 -1
- package/dist/assets/{chunk-QN33PNHL-DqS9-FYm.js → chunk-QN33PNHL-E0jwHU_n.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-BZ-TzajS.js → chunk-QZHKN3VN-BzaIHJbq.js} +1 -1
- package/dist/assets/{chunk-TVAH2DTR-BsgP2dyv.js → chunk-TVAH2DTR-CZFYvqnm.js} +1 -1
- package/dist/assets/{chunk-TZMSLE5B-D-h3ahXI.js → chunk-TZMSLE5B-BNqnFjtv.js} +1 -1
- package/dist/assets/{circle-play-CQtRZ-rT.js → circle-play-D3J_mYrF.js} +1 -1
- package/dist/assets/classDiagram-KNZD7YFC-D-xwLnlX.js +1 -0
- package/dist/assets/classDiagram-v2-RKCZMP56-D-xwLnlX.js +1 -0
- package/dist/assets/{clear-button-BY6Z_ViL.js → clear-button-ifzRuAR3.js} +1 -1
- package/dist/assets/clone-CSxIll62.js +1 -0
- package/dist/assets/command-palette-D2fdVSET.js +1 -0
- package/dist/assets/common-Ku-cF_2J.js +1 -0
- package/dist/assets/{compile-Ct_jzdKr.js → compile-BgZlHW1c.js} +1 -1
- package/dist/assets/cose-bilkent-S5V4N54A-CVM83SqK.js +1 -0
- package/dist/assets/dagre-5GWH7T2D-ouQPkxT3.js +4 -0
- package/dist/assets/{data-grid-overlay-editor-BN_wulc3.js → data-grid-overlay-editor-B47j5GJJ.js} +1 -1
- package/dist/assets/datasources-panel-Bt41Zir-.js +1 -0
- package/dist/assets/{dependency-graph-panel-BOmSCZf7.js → dependency-graph-panel-CZC_B7pK.js} +4 -4
- package/dist/assets/diagram-N5W7TBWH-CQ817ZdR.js +24 -0
- package/dist/assets/diagram-QEK2KX5R-DOK_psUO.js +43 -0
- package/dist/assets/diagram-S2PKOQOG-CVljmOW8.js +24 -0
- package/dist/assets/{documentation-panel-BxjJO_Gw.js → documentation-panel-C7yIvGg1.js} +1 -1
- package/dist/assets/edit-page-CyTMQV2u.js +129 -0
- package/dist/assets/{ellipsis-vertical-UHbmjI2n.js → ellipsis-vertical-C7FjlUsY.js} +1 -1
- package/dist/assets/{empty-state-BIBXzY_0.js → empty-state-DIOGM_CU.js} +1 -1
- package/dist/assets/{erDiagram-AWTI2OKA-E84mAle_.js → erDiagram-AWTI2OKA-DYu8cEdc.js} +1 -1
- package/dist/assets/{error-panel-MEvQ6K7h.js → error-panel-Ddb8RkFG.js} +1 -1
- package/dist/assets/file-explorer-panel-Oy9DbyFP.js +1 -0
- package/dist/assets/{flowDiagram-PVAE7QVJ-DfbIRSAW.js → flowDiagram-PVAE7QVJ-CmvW5iTb.js} +1 -1
- package/dist/assets/{ganttDiagram-OWAHRB6G-DR4HZ1z_.js → ganttDiagram-OWAHRB6G-BaKQlCaT.js} +4 -4
- package/dist/assets/gitGraphDiagram-NY62KEGX-CWO24eP6.js +65 -0
- package/dist/assets/{glide-data-editor-nNmo1lPq.js → glide-data-editor-CNDLEJ9a.js} +11 -11
- package/dist/assets/graph-BZKTtxsc.js +1 -0
- package/dist/assets/home-page-Bvwppn9N.js +9 -0
- package/dist/assets/{index-VPWqq2Pg.js → index-0XOUPdwT.js} +1 -1
- package/dist/assets/{index-uacyUula.js → index-BH7f3aiU.js} +1 -1
- package/dist/assets/{index-Dt9UWeWn.js → index-BJVyzkx5.js} +1 -1
- package/dist/assets/{index-BAH034Ue.js → index-B_d_JZGI.js} +1 -1
- package/dist/assets/{index-CB2pnVQG.js → index-BgXbBA39.js} +1 -1
- package/dist/assets/{index-B8llrTSo.js → index-Brf2DwUM.js} +1 -1
- package/dist/assets/{index-BLu5CX6z.js → index-CXrWwFX6.js} +1 -1
- package/dist/assets/{index-DyLSuOH1.js → index-CZaurnA9.js} +1 -1
- package/dist/assets/{index-BFSnz7iM.js → index-CerjupfZ.js} +1 -1
- package/dist/assets/{index-B7yXbrLa.js → index-D-tZfElD.js} +1 -1
- package/dist/assets/{index-c6If577Q.js → index-D3PqGupX.js} +1 -1
- package/dist/assets/{index-CSgxTUzD.js → index-DCkzth56.js} +1 -1
- package/dist/assets/{index-DWOaniGT.js → index-DFrGFNW1.js} +1 -1
- package/dist/assets/{index-CPN7TRA1.js → index-DZhOPkOB.js} +1 -1
- package/dist/assets/index-DadI618h.css +1 -0
- package/dist/assets/{index-DqzMPAC8.js → index-DkntzpX4.js} +2 -2
- package/dist/assets/{index-B1_GXGaP.js → index-DmgwT3sx.js} +1 -1
- package/dist/assets/index-PmY0x4Zd.js +578 -0
- package/dist/assets/{index-Bq516OmX.js → index-WXJFkQHg.js} +1 -1
- package/dist/assets/{index-DSU75csX.js → index-qE8lHQ-N.js} +1 -1
- package/dist/assets/{index-DMomwMcN.js → index-zrSUQXha.js} +1 -1
- package/dist/assets/infoDiagram-STP46IZ2-CAuVVehw.js +2 -0
- package/dist/assets/isEmpty-D1t7Gran.js +1 -0
- package/dist/assets/{journeyDiagram-BIP6EPQ6-BBiFyygf.js → journeyDiagram-BIP6EPQ6-D4Rp6H_h.js} +1 -1
- package/dist/assets/{kanban-definition-6OIFK2YF-DhgA6Nt6.js → kanban-definition-6OIFK2YF-DFt9DftA.js} +4 -4
- package/dist/assets/layout-D8WXi2_g.js +1 -0
- package/dist/assets/linear-BwY8e5hA.js +1 -0
- package/dist/assets/links-4B6ldZ5P.js +7 -0
- package/dist/assets/{logs-panel-B9SmTZAW.js → logs-panel-Dxiyt7dO.js} +1 -1
- package/dist/assets/{agent-panel-DpQ6muj-.css → markdown-renderer-ClyzDMmG.css} +1 -1
- package/dist/assets/markdown-renderer-VDu-NBKB.js +263 -0
- package/dist/assets/mermaid-B-O-Puyi.js +1 -0
- package/dist/assets/{mermaid.core-4nVOEVX3.js → mermaid.core-BFFCqfOn.js} +41 -41
- package/dist/assets/min-DtVSfYKl.js +1 -0
- package/dist/assets/{mindmap-definition-Q6HEUPPD-CVLQNn1q.js → mindmap-definition-Q6HEUPPD-kyvIY8Dg.js} +2 -2
- package/dist/assets/{number-overlay-editor-CzRzXLcd.js → number-overlay-editor-GjLB2UK4.js} +1 -1
- package/dist/assets/outline-panel-CMJjOoN7.js +1 -0
- package/dist/assets/packages-panel-nfXB-bKW.js +1 -0
- package/dist/assets/{pieDiagram-ADFJNKIX-C5IQ5DBZ.js → pieDiagram-ADFJNKIX-D8JFQcWR.js} +3 -3
- package/dist/assets/{quadrantDiagram-LMRXKWRM-CFXFnQxx.js → quadrantDiagram-LMRXKWRM-Nf8GzxXG.js} +1 -1
- package/dist/assets/{react-plotly-mzdv02_Y.js → react-plotly-CnW9p7ZA.js} +1 -1
- package/dist/assets/{requirementDiagram-4UW4RH46-D9bPC89T.js → requirementDiagram-4UW4RH46-CCUxF8BZ.js} +1 -1
- package/dist/assets/run-page-Bl4p3AbZ.js +1 -0
- package/dist/assets/sankeyDiagram-GR3RE2ED-Sr8kDwP1.js +10 -0
- package/dist/assets/scratchpad-panel-Ja1Mu-W3.js +1 -0
- package/dist/assets/secrets-panel-B-3fcSyP.js +1 -0
- package/dist/assets/{sequenceDiagram-C3RYC4MD-6N7_hY4k.js → sequenceDiagram-C3RYC4MD-CBJ152Q3.js} +4 -4
- package/dist/assets/{slides-component-DMjQomc3.css → slides-component-C-LoGC1U.css} +1 -1
- package/dist/assets/{slides-component-EcjC8sDK.js → slides-component-DGtsVP5o.js} +1 -1
- package/dist/assets/snippets-panel-ClNnwKBM.js +1 -0
- package/dist/assets/sortBy-D47H6Vyl.js +1 -0
- package/dist/assets/state-B_RCHTH5.js +1 -0
- package/dist/assets/stateDiagram-KXAO66HF-BlBFSAZr.js +1 -0
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-DbA-iToo.js +1 -0
- package/dist/assets/storage-BNcWOH3-.js +26 -0
- package/dist/assets/terminal-CATzv5Hd.js +10 -0
- package/dist/assets/time-CsYqILfB.js +1 -0
- package/dist/assets/{timeline-definition-XQNQX7LJ-BEaynAiY.js → timeline-definition-XQNQX7LJ-CGrhjuAs.js} +1 -1
- package/dist/assets/tracing-DUbJtOyq.js +2 -0
- package/dist/assets/{tracing-panel-BmuHLPrY.js → tracing-panel-DmzqPUtc.js} +2 -2
- package/dist/assets/{trash-UBqfK4mR.js → trash-rxdjLzkf.js} +1 -1
- package/dist/assets/{tree-XiEycetl.js → tree-C2Ul1h1C.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-CnuVFbBG.js → treemap-75Q7IDZK-N9hyUpyj.js} +20 -20
- package/dist/assets/{ts-tags-CloPe9IY.js → ts-tags-DxCDHihD.js} +1 -1
- package/dist/assets/variable-panel-BbgupOdG.js +1 -0
- package/dist/assets/{vega-component-DsTH4tuX.js → vega-component-CR_MHOBT.js} +1 -1
- package/dist/assets/worker-fHbtoWvT.js +1 -0
- package/dist/assets/{xychartDiagram-6GGTOJPD-Dcz3O-A3.js → xychartDiagram-6GGTOJPD-jdLZsMb2.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +10 -5
- package/src/__tests__/mocks.ts +43 -0
- package/src/components/app-config/user-config-form.tsx +78 -1
- package/src/components/chat/acp/__tests__/__snapshots__/prompt.test.ts.snap +116 -65
- package/src/components/chat/acp/__tests__/atoms.test.ts +1 -1
- package/src/components/chat/acp/__tests__/context-utils.test.ts +222 -0
- package/src/components/chat/acp/__tests__/prompt.test.ts +1 -1
- package/src/components/chat/acp/__tests__/state.test.ts +38 -42
- package/src/components/chat/acp/agent-docs.tsx +33 -6
- package/src/components/chat/acp/agent-panel.css +0 -18
- package/src/components/chat/acp/agent-panel.tsx +394 -72
- package/src/components/chat/acp/agent-selector.tsx +7 -1
- package/src/components/chat/acp/blocks.tsx +40 -10
- package/src/components/chat/acp/common.tsx +10 -2
- package/src/components/chat/acp/context-utils.ts +127 -0
- package/src/components/chat/acp/prompt.ts +96 -53
- package/src/components/chat/acp/state.ts +1 -1
- package/src/components/chat/acp/types.ts +8 -0
- package/src/components/chat/chat-panel.tsx +28 -89
- package/src/components/chat/chat-utils.ts +127 -1
- package/src/components/chat/markdown-renderer.css +39 -0
- package/src/components/chat/markdown-renderer.tsx +12 -47
- package/src/components/chat/tool-call-accordion.tsx +148 -26
- package/src/components/data-table/SearchBar.tsx +8 -7
- package/src/components/data-table/__tests__/column_formatting.test.ts +50 -35
- package/src/components/data-table/__tests__/data-table.test.tsx +39 -1
- package/src/components/data-table/cell-hover-template/feature.ts +14 -0
- package/src/components/data-table/cell-hover-template/types.ts +11 -0
- package/src/components/data-table/charts/components/form-fields.tsx +41 -37
- package/src/components/data-table/charts/forms/common-chart.tsx +2 -2
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +5 -2
- package/src/components/data-table/column-formatting/feature.ts +62 -29
- package/src/components/data-table/column-formatting/types.ts +1 -0
- package/src/components/data-table/column-header.tsx +3 -1
- package/src/components/data-table/column-summary/chart-spec-model.tsx +24 -7
- package/src/components/data-table/column-summary/column-summary.tsx +18 -9
- package/src/components/data-table/columns.tsx +42 -18
- package/src/components/data-table/data-table.tsx +10 -2
- package/src/components/data-table/date-popover.tsx +85 -75
- package/src/components/data-table/filter-pills.tsx +14 -9
- package/src/components/data-table/header-items.tsx +5 -1
- package/src/components/data-table/pagination.tsx +20 -13
- package/src/components/data-table/renderers.tsx +28 -0
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +10 -8
- package/src/components/datasources/column-preview.tsx +6 -2
- package/src/components/datasources/datasources.tsx +8 -12
- package/src/components/editor/Cell.tsx +6 -0
- package/src/components/editor/actions/name-cell-input.tsx +6 -1
- package/src/components/editor/actions/useCellActionButton.tsx +3 -1
- package/src/components/editor/ai/__tests__/completion-utils.test.ts +178 -1
- package/src/components/editor/ai/add-cell-with-ai.tsx +68 -66
- package/src/components/editor/ai/ai-completion-editor.tsx +29 -26
- package/src/components/editor/ai/completion-handlers.tsx +44 -6
- package/src/components/editor/ai/completion-utils.ts +92 -0
- package/src/components/editor/ai/transport/chat-transport.tsx +39 -0
- package/src/components/editor/cell/CellStatus.tsx +23 -20
- package/src/components/editor/cell/CreateCellButton.tsx +3 -4
- package/src/components/editor/cell/StagedAICell.tsx +51 -0
- package/src/components/editor/cell/cell-actions.tsx +2 -1
- package/src/components/editor/cell/code/language-toggle.tsx +3 -4
- package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +39 -28
- package/src/components/editor/controls/notebook-menu-dropdown.tsx +4 -2
- package/src/components/editor/file-tree/requesting-tree.tsx +14 -8
- package/src/components/editor/renderers/CellArray.tsx +3 -4
- package/src/components/editor/renderers/slides-layout/slides-layout.tsx +3 -3
- package/src/components/editor/renderers/slides-layout/types.ts +1 -0
- package/src/components/pages/home-page.tsx +4 -1
- package/src/components/slides/slides-component.tsx +1 -1
- package/src/components/slides/slides.css +6 -0
- package/src/components/terminal/__tests__/state.test.ts +207 -0
- package/src/components/terminal/hooks.ts +41 -0
- package/src/components/terminal/state.ts +75 -0
- package/src/components/terminal/terminal.tsx +334 -13
- package/src/components/terminal/theme.tsx +57 -0
- package/src/components/tracing/tracing-spec.ts +5 -4
- package/src/components/ui/range-slider.tsx +4 -2
- package/src/components/ui/slider.tsx +3 -1
- package/src/components/variables/variables-table.tsx +3 -0
- package/src/core/MarimoApp.tsx +9 -6
- package/src/core/ai/__tests__/staged-cells.test.ts +356 -0
- package/src/core/ai/context/__tests__/registry.test.ts +6 -4
- package/src/core/ai/context/providers/cell-output.ts +3 -2
- package/src/core/ai/context/providers/error.ts +3 -1
- package/src/core/ai/context/providers/file.ts +7 -2
- package/src/core/ai/context/providers/tables.ts +3 -2
- package/src/core/ai/context/providers/variable.ts +6 -4
- package/src/core/ai/staged-cells.ts +208 -0
- package/src/core/cells/cells.ts +1 -1
- package/src/core/cells/logs.ts +1 -1
- package/src/core/codemirror/find-replace/search-highlight.ts +3 -1
- package/src/core/codemirror/language/LanguageAdapters.ts +9 -3
- package/src/core/codemirror/lsp/federated-lsp.ts +1 -1
- package/src/core/codemirror/lsp/notebook-lsp.ts +8 -2
- package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
- package/src/core/codemirror/rtc/loro/awareness.ts +52 -17
- package/src/core/codemirror/rtc/loro/sync.ts +12 -4
- package/src/core/config/config-schema.ts +1 -0
- package/src/core/config/config.ts +4 -0
- package/src/core/hotkeys/hotkeys.ts +8 -4
- package/src/core/i18n/__tests__/locale-provider.test.tsx +176 -0
- package/src/core/i18n/locale-provider.tsx +35 -0
- package/src/core/i18n/with-locale.tsx +12 -0
- package/src/core/islands/components/web-components.tsx +13 -10
- package/src/core/islands/main.ts +2 -2
- package/src/core/kernel/RuntimeState.ts +4 -1
- package/src/core/kernel/messages.ts +8 -12
- package/src/core/network/DeferredRequestRegistry.ts +16 -4
- package/src/core/runtime/runtime.ts +5 -4
- package/src/core/saving/__tests__/filename.test.ts +37 -0
- package/src/core/static/__tests__/download-html.test.ts +43 -1
- package/src/core/wasm/bridge.ts +5 -1
- package/src/core/wasm/store.ts +4 -1
- package/src/core/wasm/worker/message-buffer.ts +3 -2
- package/src/core/websocket/types.ts +22 -16
- package/src/core/websocket/useMarimoWebSocket.tsx +2 -2
- package/src/css/app/Cell.css +11 -0
- package/src/hooks/useFormatting.ts +97 -0
- package/src/hooks/useTimer.ts +8 -5
- package/src/plugins/core/RenderHTML.tsx +36 -2
- package/src/plugins/core/__test__/RenderHTML.test.ts +72 -0
- package/src/plugins/core/registerReactComponent.tsx +44 -10
- package/src/plugins/impl/DataTablePlugin.tsx +4 -0
- package/src/plugins/impl/FileBrowserPlugin.tsx +8 -2
- package/src/plugins/impl/RangeSliderPlugin.tsx +5 -3
- package/src/plugins/impl/SliderPlugin.tsx +3 -1
- package/src/plugins/impl/anywidget/model.ts +16 -5
- package/src/plugins/impl/data-editor/types.ts +7 -5
- package/src/plugins/impl/data-explorer/components/column-summary.tsx +20 -13
- package/src/plugins/impl/panel/utils.ts +6 -4
- package/src/plugins/layout/OutlinePlugin.tsx +69 -0
- package/src/plugins/layout/StatPlugin.tsx +4 -1
- package/src/plugins/plugins.ts +2 -0
- package/src/stories/cell.stories.tsx +1 -1
- package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
- package/src/utils/__tests__/cell-urls.test.ts +29 -0
- package/src/utils/__tests__/dates.test.ts +45 -24
- package/src/utils/__tests__/filenames.test.ts +18 -0
- package/src/utils/__tests__/numbers.test.ts +42 -30
- package/src/utils/__tests__/once.test.ts +187 -0
- package/src/utils/__tests__/path.test.ts +38 -0
- package/src/utils/__tests__/urls.test.ts +56 -1
- package/src/utils/dates.ts +15 -10
- package/src/utils/edit-distance.ts +8 -6
- package/src/utils/errors.ts +9 -0
- package/src/utils/id-tree.tsx +21 -10
- package/src/utils/localStorage.ts +13 -4
- package/src/utils/numbers.ts +11 -11
- package/src/utils/once.ts +32 -0
- package/src/utils/paths.ts +4 -1
- package/src/utils/pluralize.ts +12 -5
- package/src/utils/python-poet/poet.ts +30 -15
- package/src/utils/time.ts +5 -1
- package/dist/assets/ConnectedDataExplorerComponent-Cn5-l2X1.js +0 -19
- package/dist/assets/_baseEach-C1FLm7WW.js +0 -1
- package/dist/assets/_baseMap-DBVArUYD.js +0 -1
- package/dist/assets/_baseUniq-Dk7ZPJ3N.js +0 -1
- package/dist/assets/_createAggregator-Bn38fDd3.js +0 -1
- package/dist/assets/agent-panel-COUYnuIK.js +0 -475
- package/dist/assets/architectureDiagram-W76B3OCA-DBzWQKKu.js +0 -36
- package/dist/assets/channel-CjhbjOv4.js +0 -1
- package/dist/assets/chat-panel-BPXKoTnZ.js +0 -7
- package/dist/assets/chat-panel-Brrs_eeH.css +0 -1
- package/dist/assets/classDiagram-KNZD7YFC-DHs5cFzy.js +0 -1
- package/dist/assets/classDiagram-v2-RKCZMP56-DHs5cFzy.js +0 -1
- package/dist/assets/clone-DM1YNjEn.js +0 -1
- package/dist/assets/command-palette-S0bzQp7v.js +0 -1
- package/dist/assets/common-B8U9k2Ly.js +0 -1
- package/dist/assets/cose-bilkent-S5V4N54A-wz1Sfx7j.js +0 -1
- package/dist/assets/dagre-5GWH7T2D-BfpcVBgq.js +0 -4
- package/dist/assets/datasources-panel-DfuURLJw.js +0 -1
- package/dist/assets/diagram-N5W7TBWH-Bf0oqqQh.js +0 -24
- package/dist/assets/diagram-QEK2KX5R-ZTc3qikh.js +0 -43
- package/dist/assets/diagram-S2PKOQOG-tLScBy7Z.js +0 -24
- package/dist/assets/edit-page-DJ8kJZ9w.js +0 -129
- package/dist/assets/file-explorer-panel-CzNUJ63G.js +0 -1
- package/dist/assets/gitGraphDiagram-NY62KEGX-C1t6QtVa.js +0 -65
- package/dist/assets/graph-CssCVWIq.js +0 -1
- package/dist/assets/home-page-9eW6qida.js +0 -9
- package/dist/assets/index-CknhX2Vy.css +0 -1
- package/dist/assets/index-DcCIe7np.js +0 -28
- package/dist/assets/index-OC46250R.js +0 -570
- package/dist/assets/infoDiagram-STP46IZ2-CwiAoz9f.js +0 -2
- package/dist/assets/layout-DpQrxGW-.js +0 -1
- package/dist/assets/linear-NsreOeBF.js +0 -1
- package/dist/assets/links-CbvGxbsJ.js +0 -7
- package/dist/assets/mermaid-DSt0r6IQ.js +0 -1
- package/dist/assets/min-D259kI3t.js +0 -1
- package/dist/assets/outline-panel-uvsS-YEQ.js +0 -1
- package/dist/assets/packages-panel-xMz9W2hW.js +0 -1
- package/dist/assets/run-page-Bb68qdhQ.js +0 -1
- package/dist/assets/sankeyDiagram-GR3RE2ED-BSJOau8E.js +0 -10
- package/dist/assets/scratchpad-panel-BF4BO-U4.js +0 -1
- package/dist/assets/secrets-panel-CdIX44dQ.js +0 -1
- package/dist/assets/snippets-panel-Dco9h0rb.js +0 -1
- package/dist/assets/sortBy-aLGA-PGK.js +0 -1
- package/dist/assets/stateDiagram-KXAO66HF-Bd68WT3b.js +0 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-BXz_GSwb.js +0 -1
- package/dist/assets/storage-CGlP4lCF.js +0 -26
- package/dist/assets/terminal-CxkHubcu.js +0 -9
- package/dist/assets/time-D2nr1UgQ.js +0 -1
- package/dist/assets/tracing-kTqHxa7q.js +0 -2
- package/dist/assets/variable-panel-noTnH-AQ.js +0 -1
- package/dist/assets/worker-X5rxzQGQ.js +0 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { EDGE_CASE_FILENAMES } from "../../../__tests__/mocks";
|
|
4
|
+
import { Filenames } from "../../../utils/filenames";
|
|
5
|
+
import { Paths } from "../../../utils/paths";
|
|
3
6
|
import { visibleForTesting } from "../download-html";
|
|
4
7
|
|
|
5
8
|
const { updateAssetUrl } = visibleForTesting;
|
|
@@ -39,3 +42,42 @@ describe("updateAssetUrl", () => {
|
|
|
39
42
|
expect(updateAssetUrl(existingUrl, assetBaseUrl)).toBe(existingUrl);
|
|
40
43
|
});
|
|
41
44
|
});
|
|
45
|
+
|
|
46
|
+
describe("filename handling for downloads", () => {
|
|
47
|
+
it.each(EDGE_CASE_FILENAMES)(
|
|
48
|
+
"should handle edge case filenames in download operations: %s",
|
|
49
|
+
(filename) => {
|
|
50
|
+
// Test that basename extraction works correctly for downloads
|
|
51
|
+
const basename = Paths.basename(filename);
|
|
52
|
+
expect(basename).toBe(filename);
|
|
53
|
+
|
|
54
|
+
// Test filename conversion for HTML downloads
|
|
55
|
+
const htmlFilename = Filenames.toHTML(filename);
|
|
56
|
+
expect(htmlFilename).toMatch(/\.html$/);
|
|
57
|
+
expect(htmlFilename).toContain(Filenames.withoutExtension(filename));
|
|
58
|
+
|
|
59
|
+
// Ensure unicode and spaces are preserved in basename
|
|
60
|
+
const withoutExt = Filenames.withoutExtension(filename);
|
|
61
|
+
expect(withoutExt).not.toBe("");
|
|
62
|
+
expect(typeof withoutExt).toBe("string");
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
it("should handle blob download filename generation", () => {
|
|
67
|
+
// Mock URL.createObjectURL for blob testing
|
|
68
|
+
const mockCreateObjectURL = vi.fn().mockReturnValue("blob:mock-url");
|
|
69
|
+
global.URL.createObjectURL = mockCreateObjectURL;
|
|
70
|
+
|
|
71
|
+
EDGE_CASE_FILENAMES.forEach((filename) => {
|
|
72
|
+
const htmlFilename = Filenames.toHTML(filename);
|
|
73
|
+
|
|
74
|
+
// Verify blob can be created with unicode filenames
|
|
75
|
+
expect(() => new Blob(["test"], { type: "text/html" })).not.toThrow();
|
|
76
|
+
expect(htmlFilename).toMatch(/\.html$/);
|
|
77
|
+
|
|
78
|
+
// Verify filename maintains unicode characters
|
|
79
|
+
const baseName = Filenames.withoutExtension(filename);
|
|
80
|
+
expect(htmlFilename).toContain(baseName);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
package/src/core/wasm/bridge.ts
CHANGED
|
@@ -576,7 +576,11 @@ export class PyodideWebsocket implements IReconnectingWebSocket {
|
|
|
576
576
|
messageSubscriptions = new Set<(event: MessageEvent) => void>();
|
|
577
577
|
errorSubscriptions = new Set<(event: Event) => void>();
|
|
578
578
|
|
|
579
|
-
|
|
579
|
+
private bridge: Pick<PyodideBridge, "consumeMessages">;
|
|
580
|
+
|
|
581
|
+
constructor(bridge: Pick<PyodideBridge, "consumeMessages">) {
|
|
582
|
+
this.bridge = bridge;
|
|
583
|
+
}
|
|
580
584
|
|
|
581
585
|
private consumeMessages() {
|
|
582
586
|
this.bridge.consumeMessages((message) => {
|
package/src/core/wasm/store.ts
CHANGED
|
@@ -87,7 +87,10 @@ const emptyFileStore: FileStore = {
|
|
|
87
87
|
};
|
|
88
88
|
|
|
89
89
|
export class CompositeFileStore implements FileStore {
|
|
90
|
-
|
|
90
|
+
private stores: FileStore[];
|
|
91
|
+
constructor(stores: FileStore[]) {
|
|
92
|
+
this.stores = stores;
|
|
93
|
+
}
|
|
91
94
|
|
|
92
95
|
insert(index: number, store: FileStore) {
|
|
93
96
|
this.stores.splice(index, 0, store);
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
export class MessageBuffer<T> {
|
|
8
8
|
private buffer: T[];
|
|
9
9
|
private started = false;
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
10
|
+
private onMessage: (data: T) => void;
|
|
11
|
+
constructor(onMessage: (data: T) => void) {
|
|
12
|
+
this.onMessage = onMessage;
|
|
12
13
|
this.buffer = [];
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -2,22 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
import type ReconnectingWebSocket from "partysocket/ws";
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
CONNECTING
|
|
7
|
-
OPEN
|
|
8
|
-
CLOSING
|
|
9
|
-
CLOSED
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
export const WebSocketState = {
|
|
6
|
+
CONNECTING: "CONNECTING",
|
|
7
|
+
OPEN: "OPEN",
|
|
8
|
+
CLOSING: "CLOSING",
|
|
9
|
+
CLOSED: "CLOSED",
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
export type WebSocketState =
|
|
13
|
+
(typeof WebSocketState)[keyof typeof WebSocketState];
|
|
14
|
+
|
|
15
|
+
export const WebSocketClosedReason = {
|
|
16
|
+
KERNEL_DISCONNECTED: "KERNEL_DISCONNECTED",
|
|
17
|
+
ALREADY_RUNNING: "ALREADY_RUNNING",
|
|
18
|
+
MALFORMED_QUERY: "MALFORMED_QUERY",
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
export type WebSocketClosedReason =
|
|
22
|
+
(typeof WebSocketClosedReason)[keyof typeof WebSocketClosedReason];
|
|
17
23
|
|
|
18
24
|
export type ConnectionStatus =
|
|
19
25
|
| {
|
|
20
|
-
state: WebSocketState.CLOSED;
|
|
26
|
+
state: typeof WebSocketState.CLOSED;
|
|
21
27
|
code: WebSocketClosedReason;
|
|
22
28
|
/**
|
|
23
29
|
* Human-readable reason for closing the connection.
|
|
@@ -31,9 +37,9 @@ export type ConnectionStatus =
|
|
|
31
37
|
}
|
|
32
38
|
| {
|
|
33
39
|
state:
|
|
34
|
-
| WebSocketState.CONNECTING
|
|
35
|
-
| WebSocketState.OPEN
|
|
36
|
-
| WebSocketState.CLOSING;
|
|
40
|
+
| typeof WebSocketState.CONNECTING
|
|
41
|
+
| typeof WebSocketState.OPEN
|
|
42
|
+
| typeof WebSocketState.CLOSING;
|
|
37
43
|
};
|
|
38
44
|
|
|
39
45
|
type PublicInterface<T> = {
|
|
@@ -86,7 +86,7 @@ export function useMarimoWebSocket(opts: {
|
|
|
86
86
|
|
|
87
87
|
const handleMessage = (e: MessageEvent<JsonString<OperationMessage>>) => {
|
|
88
88
|
const msg = jsonParseWithSpecialChar(e.data);
|
|
89
|
-
switch (msg.op) {
|
|
89
|
+
switch (msg.data.op) {
|
|
90
90
|
case "reload":
|
|
91
91
|
reloadSafe();
|
|
92
92
|
return;
|
|
@@ -267,7 +267,7 @@ export function useMarimoWebSocket(opts: {
|
|
|
267
267
|
setCellIds({ cellIds: msg.data.cell_ids as CellId[] });
|
|
268
268
|
return;
|
|
269
269
|
default:
|
|
270
|
-
logNever(msg);
|
|
270
|
+
logNever(msg.data);
|
|
271
271
|
}
|
|
272
272
|
};
|
|
273
273
|
|
package/src/css/app/Cell.css
CHANGED
|
@@ -23,6 +23,17 @@
|
|
|
23
23
|
outline: none;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
&:has(.mo-ai-generated-cell)::before {
|
|
27
|
+
content: "";
|
|
28
|
+
position: absolute;
|
|
29
|
+
inset: 0;
|
|
30
|
+
border-radius: 10px;
|
|
31
|
+
pointer-events: none;
|
|
32
|
+
opacity: 0.5;
|
|
33
|
+
box-shadow: 0px 0px 10px 0px var(--cyan-9);
|
|
34
|
+
z-index: 1;
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
&:focus-within {
|
|
27
38
|
z-index: 20;
|
|
28
39
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { useLocale } from "react-aria";
|
|
5
|
+
import { getShortTimeZone, prettyDate, timeAgo } from "@/utils/dates";
|
|
6
|
+
import {
|
|
7
|
+
prettyEngineeringNumber,
|
|
8
|
+
prettyNumber,
|
|
9
|
+
prettyScientificNumber,
|
|
10
|
+
} from "@/utils/numbers";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Hook that provides locale-aware number formatting using the prettyNumber utility
|
|
14
|
+
*/
|
|
15
|
+
export function usePrettyNumber() {
|
|
16
|
+
const { locale } = useLocale();
|
|
17
|
+
|
|
18
|
+
return useCallback(
|
|
19
|
+
(value: unknown): string => {
|
|
20
|
+
return prettyNumber(value, locale);
|
|
21
|
+
},
|
|
22
|
+
[locale],
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Hook that provides locale-aware scientific number formatting
|
|
28
|
+
*/
|
|
29
|
+
export function usePrettyScientificNumber() {
|
|
30
|
+
const { locale } = useLocale();
|
|
31
|
+
|
|
32
|
+
return useCallback(
|
|
33
|
+
(value: number, opts: { shouldRound?: boolean } = {}): string => {
|
|
34
|
+
return prettyScientificNumber(value, { ...opts, locale });
|
|
35
|
+
},
|
|
36
|
+
[locale],
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Hook that provides locale-aware engineering number formatting
|
|
42
|
+
*/
|
|
43
|
+
export function usePrettyEngineeringNumber() {
|
|
44
|
+
const { locale } = useLocale();
|
|
45
|
+
|
|
46
|
+
return useCallback(
|
|
47
|
+
(value: number): string => {
|
|
48
|
+
return prettyEngineeringNumber(value, locale);
|
|
49
|
+
},
|
|
50
|
+
[locale],
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Hook that provides locale-aware date formatting
|
|
56
|
+
*/
|
|
57
|
+
export function usePrettyDate() {
|
|
58
|
+
const { locale } = useLocale();
|
|
59
|
+
|
|
60
|
+
return useCallback(
|
|
61
|
+
(
|
|
62
|
+
value: string | number | null | undefined,
|
|
63
|
+
type: "date" | "datetime",
|
|
64
|
+
): string => {
|
|
65
|
+
return prettyDate(value, type, locale);
|
|
66
|
+
},
|
|
67
|
+
[locale],
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Hook that provides locale-aware relative time formatting
|
|
73
|
+
*/
|
|
74
|
+
export function useTimeAgo() {
|
|
75
|
+
const { locale } = useLocale();
|
|
76
|
+
|
|
77
|
+
return useCallback(
|
|
78
|
+
(value: string | number | null | undefined): string => {
|
|
79
|
+
return timeAgo(value, locale);
|
|
80
|
+
},
|
|
81
|
+
[locale],
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Hook that provides locale-aware timezone abbreviation
|
|
87
|
+
*/
|
|
88
|
+
export function useShortTimeZone() {
|
|
89
|
+
const { locale } = useLocale();
|
|
90
|
+
|
|
91
|
+
return useCallback(
|
|
92
|
+
(timezone: string): string => {
|
|
93
|
+
return getShortTimeZone(timezone, locale);
|
|
94
|
+
},
|
|
95
|
+
[locale],
|
|
96
|
+
);
|
|
97
|
+
}
|
package/src/hooks/useTimer.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { useNumberFormatter } from "react-aria";
|
|
4
5
|
import useEvent from "react-use-event-hook";
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -11,6 +12,12 @@ export function useTimer() {
|
|
|
11
12
|
const [time, setTime] = useState(0);
|
|
12
13
|
const interval = useRef<number>(undefined);
|
|
13
14
|
|
|
15
|
+
// one decimal place, exactly
|
|
16
|
+
const numberFormatter = useNumberFormatter({
|
|
17
|
+
minimumFractionDigits: 1,
|
|
18
|
+
maximumFractionDigits: 1,
|
|
19
|
+
});
|
|
20
|
+
|
|
14
21
|
const start = useEvent(() => {
|
|
15
22
|
interval.current = window.setInterval(() => {
|
|
16
23
|
setTime((time) => time + 0.1);
|
|
@@ -36,11 +43,7 @@ export function useTimer() {
|
|
|
36
43
|
}, []);
|
|
37
44
|
|
|
38
45
|
return {
|
|
39
|
-
|
|
40
|
-
time: new Intl.NumberFormat("en-US", {
|
|
41
|
-
minimumFractionDigits: 1,
|
|
42
|
-
maximumFractionDigits: 1,
|
|
43
|
-
}).format(time),
|
|
46
|
+
time: numberFormatter.format(time),
|
|
44
47
|
start,
|
|
45
48
|
stop,
|
|
46
49
|
clear,
|
|
@@ -5,7 +5,7 @@ import parse, {
|
|
|
5
5
|
Element,
|
|
6
6
|
type HTMLReactParserOptions,
|
|
7
7
|
} from "html-react-parser";
|
|
8
|
-
import React, { type JSX, type ReactNode, useId } from "react";
|
|
8
|
+
import React, { isValidElement, type JSX, type ReactNode, useId } from "react";
|
|
9
9
|
import { CopyClipboardIcon } from "@/components/icons/copy-icon";
|
|
10
10
|
|
|
11
11
|
type ReplacementFn = NonNullable<HTMLReactParserOptions["replace"]>;
|
|
@@ -23,6 +23,36 @@ const replaceValidTags = (domNode: DOMNode) => {
|
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
const removeWrappingBodyTags: TransformFn = (
|
|
27
|
+
reactNode: ReactNode,
|
|
28
|
+
domNode: DOMNode,
|
|
29
|
+
) => {
|
|
30
|
+
// Remove body tags and just render their children
|
|
31
|
+
if (domNode instanceof Element && domNode.name === "body") {
|
|
32
|
+
if (isValidElement(reactNode) && "props" in reactNode) {
|
|
33
|
+
const props = reactNode.props as { children?: ReactNode };
|
|
34
|
+
const children = props.children;
|
|
35
|
+
return <>{children}</>; // eslint-disable-line react/jsx-no-useless-fragment
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const removeWrappingHtmlTags: TransformFn = (
|
|
42
|
+
reactNode: ReactNode,
|
|
43
|
+
domNode: DOMNode,
|
|
44
|
+
) => {
|
|
45
|
+
// Remove html tags and just render their children
|
|
46
|
+
if (domNode instanceof Element && domNode.name === "html") {
|
|
47
|
+
if (isValidElement(reactNode) && "props" in reactNode) {
|
|
48
|
+
const props = reactNode.props as { children?: ReactNode };
|
|
49
|
+
const children = props.children;
|
|
50
|
+
return <>{children}</>; // eslint-disable-line react/jsx-no-useless-fragment
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
26
56
|
const replaceValidIframes = (domNode: DOMNode) => {
|
|
27
57
|
// For iframe, we just want to use dangerouslySetInnerHTML so:
|
|
28
58
|
// 1) we can remount the iframe when the src changes
|
|
@@ -110,7 +140,11 @@ export const renderHTML = ({ html, additionalReplacements = [] }: Options) => {
|
|
|
110
140
|
...additionalReplacements,
|
|
111
141
|
];
|
|
112
142
|
|
|
113
|
-
const transformFunctions: TransformFn[] = [
|
|
143
|
+
const transformFunctions: TransformFn[] = [
|
|
144
|
+
addCopyButtonToCodehilite,
|
|
145
|
+
removeWrappingBodyTags,
|
|
146
|
+
removeWrappingHtmlTags,
|
|
147
|
+
];
|
|
114
148
|
|
|
115
149
|
return parse(html, {
|
|
116
150
|
replace: (domNode: DOMNode, index: number) => {
|
|
@@ -121,6 +121,78 @@ describe("RenderHTML", () => {
|
|
|
121
121
|
</p>
|
|
122
122
|
`);
|
|
123
123
|
});
|
|
124
|
+
|
|
125
|
+
test("removes body tags but preserves children", () => {
|
|
126
|
+
const html = "<body><h1>Hello</h1><p>World</p></body>";
|
|
127
|
+
expect(renderHTML({ html })).toMatchInlineSnapshot(`
|
|
128
|
+
<React.Fragment>
|
|
129
|
+
<h1>
|
|
130
|
+
Hello
|
|
131
|
+
</h1>
|
|
132
|
+
<p>
|
|
133
|
+
World
|
|
134
|
+
</p>
|
|
135
|
+
</React.Fragment>
|
|
136
|
+
`);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("removes nested body tags", () => {
|
|
140
|
+
const html = "<div><body><span>Content</span></body></div>";
|
|
141
|
+
expect(renderHTML({ html })).toMatchInlineSnapshot(`
|
|
142
|
+
<div>
|
|
143
|
+
<React.Fragment>
|
|
144
|
+
<span>
|
|
145
|
+
Content
|
|
146
|
+
</span>
|
|
147
|
+
</React.Fragment>
|
|
148
|
+
</div>
|
|
149
|
+
`);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("removes html tags but preserves children", () => {
|
|
153
|
+
const html =
|
|
154
|
+
"<html><head><title>Test</title></head><body><p>Content</p></body></html>";
|
|
155
|
+
expect(renderHTML({ html })).toMatchInlineSnapshot(`
|
|
156
|
+
<React.Fragment>
|
|
157
|
+
<head>
|
|
158
|
+
<title>
|
|
159
|
+
Test
|
|
160
|
+
</title>
|
|
161
|
+
</head>
|
|
162
|
+
<React.Fragment>
|
|
163
|
+
<p>
|
|
164
|
+
Content
|
|
165
|
+
</p>
|
|
166
|
+
</React.Fragment>
|
|
167
|
+
</React.Fragment>
|
|
168
|
+
`);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("removes nested html tags", () => {
|
|
172
|
+
const html = "<div><html><span>Content</span></html></div>";
|
|
173
|
+
expect(renderHTML({ html })).toMatchInlineSnapshot(`
|
|
174
|
+
<div>
|
|
175
|
+
<React.Fragment>
|
|
176
|
+
<span>
|
|
177
|
+
Content
|
|
178
|
+
</span>
|
|
179
|
+
</React.Fragment>
|
|
180
|
+
</div>
|
|
181
|
+
`);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("remove nested body in html", () => {
|
|
185
|
+
const html = "<html><body><span>Content</span></body></html>";
|
|
186
|
+
expect(renderHTML({ html })).toMatchInlineSnapshot(`
|
|
187
|
+
<React.Fragment>
|
|
188
|
+
<React.Fragment>
|
|
189
|
+
<span>
|
|
190
|
+
Content
|
|
191
|
+
</span>
|
|
192
|
+
</React.Fragment>
|
|
193
|
+
</React.Fragment>
|
|
194
|
+
`);
|
|
195
|
+
});
|
|
124
196
|
});
|
|
125
197
|
|
|
126
198
|
describe("RenderHTML with < nad >", () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
2
3
|
/* eslint-disable unicorn/prefer-spread */
|
|
3
4
|
/**
|
|
4
5
|
* WebComponent Factory for React Components
|
|
@@ -7,6 +8,7 @@
|
|
|
7
8
|
* component. The factory handles the logic of communicating UI element values
|
|
8
9
|
* to and from the rest of marimo.
|
|
9
10
|
*/
|
|
11
|
+
import { Provider } from "jotai";
|
|
10
12
|
import React, {
|
|
11
13
|
createRef,
|
|
12
14
|
type JSX,
|
|
@@ -21,16 +23,22 @@ import React, {
|
|
|
21
23
|
import ReactDOM, { type Root } from "react-dom/client";
|
|
22
24
|
import useEvent from "react-use-event-hook";
|
|
23
25
|
import type { ZodSchema } from "zod";
|
|
26
|
+
import { notebookAtom } from "@/core/cells/cells.ts";
|
|
27
|
+
import { findCellId } from "@/core/cells/ids.ts";
|
|
28
|
+
import { isUninstantiated } from "@/core/cells/utils";
|
|
24
29
|
import { createInputEvent, MarimoValueUpdateEvent } from "@/core/dom/events";
|
|
25
30
|
import { getUIElementObjectId } from "@/core/dom/ui-element";
|
|
26
31
|
import { UIElementRegistry } from "@/core/dom/uiregistry";
|
|
27
32
|
import { FUNCTIONS_REGISTRY } from "@/core/functions/FunctionRegistry";
|
|
33
|
+
import { LocaleProvider } from "@/core/i18n/locale-provider";
|
|
34
|
+
import { store } from "@/core/state/jotai";
|
|
28
35
|
import {
|
|
29
36
|
type HTMLElementNotDerivedFromRef,
|
|
30
37
|
useEventListener,
|
|
31
38
|
} from "@/hooks/useEventListener";
|
|
32
39
|
import { StyleNamespace } from "@/theme/namespace";
|
|
33
40
|
import { useTheme } from "@/theme/useTheme";
|
|
41
|
+
import { CellNotInitializedError } from "@/utils/errors.ts";
|
|
34
42
|
import { Functions } from "@/utils/functions";
|
|
35
43
|
import { shallowCompare } from "@/utils/shallow-compare";
|
|
36
44
|
import { defineCustomElement } from "../../core/dom/defineCustomElement";
|
|
@@ -78,6 +86,7 @@ interface PluginSlotProps<T> {
|
|
|
78
86
|
}
|
|
79
87
|
|
|
80
88
|
/* Handles synchronization of value on behalf of the component */
|
|
89
|
+
|
|
81
90
|
// eslint-disable-next-line react/function-component-definition
|
|
82
91
|
function PluginSlotInternal<T>(
|
|
83
92
|
{ hostElement, plugin, children, getInitialValue }: PluginSlotProps<T>,
|
|
@@ -172,6 +181,27 @@ function PluginSlotInternal<T>(
|
|
|
172
181
|
);
|
|
173
182
|
const objectId = getUIElementObjectId(hostElement);
|
|
174
183
|
invariant(objectId, "Object ID should exist");
|
|
184
|
+
|
|
185
|
+
const cellId = findCellId(hostElement);
|
|
186
|
+
invariant(cellId, "Cell ID should exist");
|
|
187
|
+
|
|
188
|
+
const notebookState = store.get(notebookAtom);
|
|
189
|
+
const cellRuntime = notebookState.cellRuntime[cellId];
|
|
190
|
+
const cellData = notebookState.cellData[cellId];
|
|
191
|
+
|
|
192
|
+
const cellNotInitialized = isUninstantiated({
|
|
193
|
+
executionTime:
|
|
194
|
+
cellRuntime.runElapsedTimeMs ?? cellData.lastExecutionTime,
|
|
195
|
+
status: cellRuntime.status,
|
|
196
|
+
errored: cellRuntime.errored,
|
|
197
|
+
interrupted: cellRuntime.interrupted,
|
|
198
|
+
stopped: cellRuntime.stopped,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
if (cellNotInitialized) {
|
|
202
|
+
throw new CellNotInitializedError();
|
|
203
|
+
}
|
|
204
|
+
|
|
175
205
|
const response = await FUNCTIONS_REGISTRY.request({
|
|
176
206
|
args: prettyParse(input, args[0]),
|
|
177
207
|
functionName: key,
|
|
@@ -335,16 +365,20 @@ export function registerReactComponent<T>(plugin: IPlugin<T, unknown>): void {
|
|
|
335
365
|
|
|
336
366
|
invariant(this.root, "Root must be defined");
|
|
337
367
|
this.root.render(
|
|
338
|
-
<
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
368
|
+
<Provider store={store}>
|
|
369
|
+
<LocaleProvider>
|
|
370
|
+
<PluginSlot
|
|
371
|
+
hostElement={this}
|
|
372
|
+
plugin={plugin}
|
|
373
|
+
ref={this.pluginRef}
|
|
374
|
+
getInitialValue={() => {
|
|
375
|
+
return parseInitialValue(this, UIElementRegistry.INSTANCE);
|
|
376
|
+
}}
|
|
377
|
+
>
|
|
378
|
+
{this.getChildren()}
|
|
379
|
+
</PluginSlot>
|
|
380
|
+
</LocaleProvider>
|
|
381
|
+
</Provider>,
|
|
348
382
|
);
|
|
349
383
|
}
|
|
350
384
|
|
|
@@ -254,6 +254,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
|
|
|
254
254
|
maxColumns: z.union([z.number(), z.literal("all")]).default("all"),
|
|
255
255
|
hasStableRowId: z.boolean().default(false),
|
|
256
256
|
cellStyles: z.record(z.record(z.object({}).passthrough())).optional(),
|
|
257
|
+
hoverTemplate: z.string().optional(),
|
|
257
258
|
// Whether to load the data lazily.
|
|
258
259
|
lazy: z.boolean().default(false),
|
|
259
260
|
// If lazy, this will preload the first page of data
|
|
@@ -385,6 +386,7 @@ interface DataTableProps<T> extends Data<T>, DataTableFunctions {
|
|
|
385
386
|
// Filters
|
|
386
387
|
enableFilters?: boolean;
|
|
387
388
|
cellStyles?: CellStyleState | null;
|
|
389
|
+
hoverTemplate?: string | null;
|
|
388
390
|
toggleDisplayHeader?: () => void;
|
|
389
391
|
host: HTMLElement;
|
|
390
392
|
cellId?: CellId | null;
|
|
@@ -707,6 +709,7 @@ const DataTableComponent = ({
|
|
|
707
709
|
totalColumns,
|
|
708
710
|
get_row_ids,
|
|
709
711
|
cellStyles,
|
|
712
|
+
hoverTemplate,
|
|
710
713
|
toggleDisplayHeader,
|
|
711
714
|
calculate_top_k_rows,
|
|
712
715
|
preview_column,
|
|
@@ -904,6 +907,7 @@ const DataTableComponent = ({
|
|
|
904
907
|
rowSelection={rowSelection}
|
|
905
908
|
cellSelection={cellSelection}
|
|
906
909
|
cellStyling={cellStyles}
|
|
910
|
+
hoverTemplate={hoverTemplate}
|
|
907
911
|
downloadAs={showDownload ? downloadAs : undefined}
|
|
908
912
|
enableSearch={enableSearch}
|
|
909
913
|
searchQuery={searchQuery}
|
|
@@ -12,7 +12,7 @@ import { Button } from "@/components/ui/button";
|
|
|
12
12
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
13
13
|
import { Label } from "@/components/ui/label";
|
|
14
14
|
import { NativeSelect } from "@/components/ui/native-select";
|
|
15
|
-
import { Table, TableCell, TableRow } from "@/components/ui/table";
|
|
15
|
+
import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table";
|
|
16
16
|
import { toast } from "@/components/ui/use-toast";
|
|
17
17
|
import { useAsyncData } from "@/hooks/useAsyncData";
|
|
18
18
|
import { useInternalStateWithSync } from "@/hooks/useInternalStateWithSync";
|
|
@@ -158,6 +158,10 @@ export const FileBrowser = ({
|
|
|
158
158
|
return null;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
if (!data && error) {
|
|
162
|
+
return <Banner kind="danger">{error.message}</Banner>;
|
|
163
|
+
}
|
|
164
|
+
|
|
161
165
|
let { files } = data || {};
|
|
162
166
|
if (files === undefined) {
|
|
163
167
|
files = [];
|
|
@@ -458,7 +462,9 @@ export const FileBrowser = ({
|
|
|
458
462
|
className="mt-3 overflow-y-auto w-full border"
|
|
459
463
|
style={{ height: "14rem" }}
|
|
460
464
|
>
|
|
461
|
-
<Table className="cursor-pointer table-fixed">
|
|
465
|
+
<Table className="cursor-pointer table-fixed">
|
|
466
|
+
<TableBody>{fileRows}</TableBody>
|
|
467
|
+
</Table>
|
|
462
468
|
</div>
|
|
463
469
|
<div className="mt-4">
|
|
464
470
|
{value.length > 0 && (
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { isEqual } from "lodash-es";
|
|
4
4
|
import { type JSX, useEffect, useId, useState } from "react";
|
|
5
|
+
import { useLocale } from "react-aria";
|
|
5
6
|
import { z } from "zod";
|
|
6
7
|
import { cn } from "@/utils/cn";
|
|
7
8
|
import { prettyScientificNumber } from "@/utils/numbers";
|
|
@@ -82,6 +83,7 @@ const RangeSliderComponent = ({
|
|
|
82
83
|
valueMap,
|
|
83
84
|
}: RangeSliderProps): JSX.Element => {
|
|
84
85
|
const id = useId();
|
|
86
|
+
const { locale } = useLocale();
|
|
85
87
|
|
|
86
88
|
// Hold internal value
|
|
87
89
|
const [internalValue, setInternalValue] = useState(value);
|
|
@@ -150,9 +152,9 @@ const RangeSliderComponent = ({
|
|
|
150
152
|
/>
|
|
151
153
|
{showValue && (
|
|
152
154
|
<div className="text-xs text-muted-foreground min-w-[16px]">
|
|
153
|
-
{`${prettyScientificNumber(
|
|
154
|
-
|
|
155
|
-
)}, ${prettyScientificNumber(valueMap(internalValue[1]))}`}
|
|
155
|
+
{`${prettyScientificNumber(valueMap(internalValue[0]), {
|
|
156
|
+
locale,
|
|
157
|
+
})}, ${prettyScientificNumber(valueMap(internalValue[1]), { locale })}`}
|
|
156
158
|
</div>
|
|
157
159
|
)}
|
|
158
160
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
import { type JSX, useEffect, useId, useState } from "react";
|
|
3
|
+
import { useLocale } from "react-aria";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
import { NumberField } from "@/components/ui/number-field";
|
|
5
6
|
import { cn } from "@/utils/cn";
|
|
@@ -85,6 +86,7 @@ const SliderComponent = ({
|
|
|
85
86
|
disabled,
|
|
86
87
|
}: SliderProps): JSX.Element => {
|
|
87
88
|
const id = useId();
|
|
89
|
+
const { locale } = useLocale();
|
|
88
90
|
|
|
89
91
|
// Hold internal value
|
|
90
92
|
const [internalValue, setInternalValue] = useState(value);
|
|
@@ -138,7 +140,7 @@ const SliderComponent = ({
|
|
|
138
140
|
/>
|
|
139
141
|
{showValue && (
|
|
140
142
|
<div className="text-xs text-muted-foreground min-w-[16px]">
|
|
141
|
-
{prettyScientificNumber(valueMap(internalValue))}
|
|
143
|
+
{prettyScientificNumber(valueMap(internalValue), { locale })}
|
|
142
144
|
</div>
|
|
143
145
|
)}
|
|
144
146
|
{includeInput && (
|