@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
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { renderHook } from "@testing-library/react";
|
|
4
|
+
import { getDefaultStore } from "jotai";
|
|
5
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { CellId } from "@/core/cells/ids";
|
|
7
|
+
import { updateEditorCodeFromPython } from "../../codemirror/language/utils";
|
|
8
|
+
import {
|
|
9
|
+
stagedAICellsAtom,
|
|
10
|
+
useStagedCells,
|
|
11
|
+
visibleForTesting,
|
|
12
|
+
} from "../staged-cells";
|
|
13
|
+
|
|
14
|
+
const { createActions, reducer, initialState } = visibleForTesting;
|
|
15
|
+
|
|
16
|
+
// Mock the dependencies
|
|
17
|
+
const mockCreateNewCell = vi.fn();
|
|
18
|
+
const mockUpdateCellEditor = vi.fn();
|
|
19
|
+
const mockDeleteCellCallback = vi.fn();
|
|
20
|
+
|
|
21
|
+
// Mock cell handle with editor view
|
|
22
|
+
const mockCellHandle = {
|
|
23
|
+
current: {
|
|
24
|
+
editorViewOrNull: {
|
|
25
|
+
dispatch: vi.fn(),
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
vi.mock("../../cells/cells", () => ({
|
|
31
|
+
useCellActions: () => ({
|
|
32
|
+
createNewCell: mockCreateNewCell,
|
|
33
|
+
updateCellEditor: mockUpdateCellEditor,
|
|
34
|
+
}),
|
|
35
|
+
cellHandleAtom: vi.fn(() => ({
|
|
36
|
+
read: vi.fn(() => mockCellHandle),
|
|
37
|
+
})),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
vi.mock("@/components/editor/cell/useDeleteCell", () => ({
|
|
41
|
+
useDeleteCellCallback: () => mockDeleteCellCallback,
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
vi.mock("../../codemirror/language/utils", () => ({
|
|
45
|
+
updateEditorCodeFromPython: vi.fn(),
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
// Mock CellId.create
|
|
49
|
+
vi.mock("@/core/cells/ids", () => ({
|
|
50
|
+
CellId: {
|
|
51
|
+
create: vi.fn(),
|
|
52
|
+
},
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
describe("staged-cells", () => {
|
|
56
|
+
let store: ReturnType<typeof getDefaultStore>;
|
|
57
|
+
let cellId1: CellId;
|
|
58
|
+
let cellId2: CellId;
|
|
59
|
+
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
store = getDefaultStore();
|
|
62
|
+
cellId1 = "cell-1" as CellId;
|
|
63
|
+
cellId2 = "cell-2" as CellId;
|
|
64
|
+
|
|
65
|
+
// Reset mocks
|
|
66
|
+
vi.clearAllMocks();
|
|
67
|
+
|
|
68
|
+
// Reset the atom state
|
|
69
|
+
store.set(stagedAICellsAtom, new Set<CellId>());
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("reducer and actions", () => {
|
|
73
|
+
it("should initialize with empty map", () => {
|
|
74
|
+
const state = initialState();
|
|
75
|
+
expect(state).toEqual(new Set());
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should add cell IDs", () => {
|
|
79
|
+
let state = initialState();
|
|
80
|
+
state = reducer(state, {
|
|
81
|
+
type: "addStagedCell",
|
|
82
|
+
payload: { cellId: cellId1 },
|
|
83
|
+
});
|
|
84
|
+
state = reducer(state, {
|
|
85
|
+
type: "addStagedCell",
|
|
86
|
+
payload: { cellId: cellId2 },
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(state.has(cellId1)).toBe(true);
|
|
90
|
+
expect(state.has(cellId2)).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should remove cell IDs", () => {
|
|
94
|
+
const state = new Set([cellId1, cellId2]);
|
|
95
|
+
const newState = reducer(state, {
|
|
96
|
+
type: "removeStagedCell",
|
|
97
|
+
payload: cellId1,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(newState.has(cellId1)).toBe(false);
|
|
101
|
+
expect(newState.has(cellId2)).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should clear all cell IDs", () => {
|
|
105
|
+
const state = new Set([cellId1, cellId2]);
|
|
106
|
+
const newState = reducer(state, {
|
|
107
|
+
type: "clearStagedCells",
|
|
108
|
+
payload: undefined,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(newState).toEqual(new Set());
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("should not mutate original state", () => {
|
|
115
|
+
const state = new Set([cellId1]);
|
|
116
|
+
const originalSize = state.size;
|
|
117
|
+
|
|
118
|
+
reducer(state, {
|
|
119
|
+
type: "addStagedCell",
|
|
120
|
+
payload: { cellId: cellId2 },
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(state.size).toBe(originalSize);
|
|
124
|
+
expect(state.has(cellId1)).toBe(true);
|
|
125
|
+
expect(state.has(cellId2)).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should create action functions", () => {
|
|
129
|
+
const mockDispatch = vi.fn();
|
|
130
|
+
const actions = createActions(mockDispatch);
|
|
131
|
+
|
|
132
|
+
expect(typeof actions.addStagedCell).toBe("function");
|
|
133
|
+
expect(typeof actions.removeStagedCell).toBe("function");
|
|
134
|
+
expect(typeof actions.clearStagedCells).toBe("function");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should initialize atom with empty map", () => {
|
|
138
|
+
const state = store.get(stagedAICellsAtom);
|
|
139
|
+
expect(state).toEqual(new Set());
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe("useStagedCells hook", () => {
|
|
144
|
+
it("should create a staged cell with code", () => {
|
|
145
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
146
|
+
const testCode = "print('hello world')";
|
|
147
|
+
|
|
148
|
+
// Mock CellId.create to return a predictable ID
|
|
149
|
+
const mockCellId = "mock-cell-id" as CellId;
|
|
150
|
+
vi.mocked(CellId.create).mockReturnValue(mockCellId);
|
|
151
|
+
|
|
152
|
+
const returnedCellId = result.current.createStagedCell(testCode);
|
|
153
|
+
|
|
154
|
+
expect(returnedCellId).toBe(mockCellId);
|
|
155
|
+
expect(mockCreateNewCell).toHaveBeenCalledWith({
|
|
156
|
+
cellId: "__end__",
|
|
157
|
+
code: testCode,
|
|
158
|
+
before: false,
|
|
159
|
+
newCellId: mockCellId,
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("should delete a staged cell", () => {
|
|
164
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
165
|
+
const testCellId = "test-cell-id" as CellId;
|
|
166
|
+
|
|
167
|
+
result.current.deleteStagedCell(testCellId);
|
|
168
|
+
|
|
169
|
+
expect(mockDeleteCellCallback).toHaveBeenCalledWith({
|
|
170
|
+
cellId: testCellId,
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("should delete all staged cells when none exist", () => {
|
|
175
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
176
|
+
|
|
177
|
+
// Should not throw when no cells exist
|
|
178
|
+
expect(() => result.current.deleteAllStagedCells()).not.toThrow();
|
|
179
|
+
expect(mockDeleteCellCallback).not.toHaveBeenCalled();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should delete all staged cells when cells exist", () => {
|
|
183
|
+
// First set the atom state before rendering the hook
|
|
184
|
+
store.set(stagedAICellsAtom, new Set([cellId1, cellId2]));
|
|
185
|
+
|
|
186
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
187
|
+
result.current.deleteAllStagedCells();
|
|
188
|
+
|
|
189
|
+
expect(mockDeleteCellCallback).toHaveBeenCalledTimes(2);
|
|
190
|
+
expect(mockDeleteCellCallback).toHaveBeenCalledWith({ cellId: cellId1 });
|
|
191
|
+
expect(mockDeleteCellCallback).toHaveBeenCalledWith({ cellId: cellId2 });
|
|
192
|
+
|
|
193
|
+
// Verify cells were cleared from the atom
|
|
194
|
+
const state = store.get(stagedAICellsAtom);
|
|
195
|
+
expect(state).toEqual(new Set());
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("should add staged cell", () => {
|
|
200
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
201
|
+
|
|
202
|
+
result.current.addStagedCell({ cellId: cellId1 });
|
|
203
|
+
|
|
204
|
+
// Check that the cell was added to the atom
|
|
205
|
+
const state = store.get(stagedAICellsAtom);
|
|
206
|
+
expect(state.has(cellId1)).toBe(true);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("should remove staged cell", () => {
|
|
210
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
211
|
+
|
|
212
|
+
// First add cells
|
|
213
|
+
result.current.addStagedCell({ cellId: cellId1 });
|
|
214
|
+
result.current.addStagedCell({ cellId: cellId2 });
|
|
215
|
+
|
|
216
|
+
// Then remove one
|
|
217
|
+
result.current.removeStagedCell(cellId1);
|
|
218
|
+
|
|
219
|
+
// Check that only the remaining cell is in the map
|
|
220
|
+
const state = store.get(stagedAICellsAtom);
|
|
221
|
+
expect(state.has(cellId1)).toBe(false);
|
|
222
|
+
expect(state.has(cellId2)).toBe(true);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should clear all staged cells", () => {
|
|
226
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
227
|
+
|
|
228
|
+
// First add some cells
|
|
229
|
+
result.current.addStagedCell({ cellId: cellId1 });
|
|
230
|
+
result.current.addStagedCell({ cellId: cellId2 });
|
|
231
|
+
|
|
232
|
+
// Then clear all
|
|
233
|
+
result.current.clearStagedCells();
|
|
234
|
+
|
|
235
|
+
// Check that no cells remain
|
|
236
|
+
const state = store.get(stagedAICellsAtom);
|
|
237
|
+
expect(state).toEqual(new Set());
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("should handle multiple operations correctly", () => {
|
|
241
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
242
|
+
|
|
243
|
+
// Create a staged cell
|
|
244
|
+
const mockCellId = "mock-cell-id" as CellId;
|
|
245
|
+
vi.mocked(CellId.create).mockReturnValue(mockCellId);
|
|
246
|
+
|
|
247
|
+
const createdCellId = result.current.createStagedCell("test code");
|
|
248
|
+
|
|
249
|
+
// Verify it was created and added
|
|
250
|
+
expect(createdCellId).toBe(mockCellId);
|
|
251
|
+
expect(mockCreateNewCell).toHaveBeenCalled();
|
|
252
|
+
|
|
253
|
+
let state = store.get(stagedAICellsAtom);
|
|
254
|
+
expect(state.has(mockCellId)).toBe(true);
|
|
255
|
+
|
|
256
|
+
// Delete the staged cell
|
|
257
|
+
result.current.deleteStagedCell(mockCellId);
|
|
258
|
+
expect(mockDeleteCellCallback).toHaveBeenCalledWith({
|
|
259
|
+
cellId: mockCellId,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Verify it was removed from staged cells
|
|
263
|
+
state = store.get(stagedAICellsAtom);
|
|
264
|
+
expect(state.has(mockCellId)).toBe(false);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
describe("onStream", () => {
|
|
269
|
+
let store: ReturnType<typeof getDefaultStore>;
|
|
270
|
+
beforeEach(() => {
|
|
271
|
+
store = getDefaultStore();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it("should create a cell creation stream", () => {
|
|
275
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
276
|
+
result.current.onStream({ type: "text-start", id: "test-id" });
|
|
277
|
+
|
|
278
|
+
// No cell or cell update should have been called
|
|
279
|
+
expect(mockCreateNewCell).not.toHaveBeenCalled();
|
|
280
|
+
expect(mockUpdateCellEditor).not.toHaveBeenCalled();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it("should not create cells when text-delta is received and no stream has been created", () => {
|
|
284
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
285
|
+
result.current.onStream({
|
|
286
|
+
type: "text-delta",
|
|
287
|
+
id: "test-id",
|
|
288
|
+
delta: "test-delta",
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// No cell or cell update should have been called
|
|
292
|
+
expect(mockCreateNewCell).not.toHaveBeenCalled();
|
|
293
|
+
expect(mockUpdateCellEditor).not.toHaveBeenCalled();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it("should create cells when text-delta is received and a stream has been created", () => {
|
|
297
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
298
|
+
result.current.onStream({ type: "text-start", id: "test-id" });
|
|
299
|
+
|
|
300
|
+
// Mock CellId.create to return a predictable ID
|
|
301
|
+
const mockCellId = "mock-cell-id" as CellId;
|
|
302
|
+
vi.mocked(CellId.create).mockReturnValue(mockCellId);
|
|
303
|
+
|
|
304
|
+
result.current.onStream({
|
|
305
|
+
type: "text-delta",
|
|
306
|
+
id: "test-id",
|
|
307
|
+
delta: "some code",
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
expect(mockCreateNewCell).toHaveBeenCalledWith({
|
|
311
|
+
cellId: "__end__",
|
|
312
|
+
code: "some code",
|
|
313
|
+
before: false,
|
|
314
|
+
newCellId: "mock-cell-id",
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it("should handle delta chunks", () => {
|
|
319
|
+
const { result } = renderHook(() => useStagedCells(store));
|
|
320
|
+
result.current.onStream({ type: "text-start", id: "test-id" });
|
|
321
|
+
|
|
322
|
+
const mockCellId = "mock-cell-id" as CellId;
|
|
323
|
+
vi.mocked(CellId.create).mockReturnValue(mockCellId);
|
|
324
|
+
|
|
325
|
+
result.current.onStream({
|
|
326
|
+
type: "text-delta",
|
|
327
|
+
id: "test-id",
|
|
328
|
+
delta: "``",
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
expect(mockCreateNewCell).toHaveBeenCalledWith({
|
|
332
|
+
cellId: "__end__",
|
|
333
|
+
code: "``",
|
|
334
|
+
before: false,
|
|
335
|
+
newCellId: "mock-cell-id",
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
result.current.onStream({
|
|
339
|
+
type: "text-delta",
|
|
340
|
+
id: "test-id",
|
|
341
|
+
delta: "```python\nsome code",
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Now the cell is recognized and only some code is seen
|
|
345
|
+
expect(vi.mocked(updateEditorCodeFromPython)).toHaveBeenCalledWith(
|
|
346
|
+
mockCellHandle.current.editorViewOrNull,
|
|
347
|
+
"some code",
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
result.current.onStream({
|
|
351
|
+
type: "text-delta",
|
|
352
|
+
id: "test-id",
|
|
353
|
+
delta: "\n```",
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
});
|
|
@@ -101,11 +101,13 @@ class AttachmentContextProvider extends AIContextProvider<MockContextItem> {
|
|
|
101
101
|
readonly mentionPrefix = "@";
|
|
102
102
|
readonly contextType = "attachment";
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
) {
|
|
104
|
+
private items: MockContextItem[];
|
|
105
|
+
private attachments: FileUIPart[];
|
|
106
|
+
|
|
107
|
+
constructor(items: MockContextItem[] = [], attachments: FileUIPart[] = []) {
|
|
108
108
|
super();
|
|
109
|
+
this.items = items;
|
|
110
|
+
this.attachments = attachments;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
getItems(): MockContextItem[] {
|
|
@@ -86,9 +86,10 @@ export class CellOutputContextProvider extends AIContextProvider<CellOutputConte
|
|
|
86
86
|
readonly title = "Cell Outputs";
|
|
87
87
|
readonly mentionPrefix = "@";
|
|
88
88
|
readonly contextType = "cell-output";
|
|
89
|
-
|
|
90
|
-
constructor(
|
|
89
|
+
private store: JotaiStore;
|
|
90
|
+
constructor(store: JotaiStore) {
|
|
91
91
|
super();
|
|
92
|
+
this.store = store;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
getItems(): CellOutputContextItem[] {
|
|
@@ -64,9 +64,11 @@ export class ErrorContextProvider extends AIContextProvider<ErrorContextItem> {
|
|
|
64
64
|
readonly title = "Errors";
|
|
65
65
|
readonly mentionPrefix = "@";
|
|
66
66
|
readonly contextType = "error";
|
|
67
|
+
private store: JotaiStore;
|
|
67
68
|
|
|
68
|
-
constructor(
|
|
69
|
+
constructor(store: JotaiStore) {
|
|
69
70
|
super();
|
|
71
|
+
this.store = store;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
getItems(): ErrorContextItem[] {
|
|
@@ -43,11 +43,16 @@ export class FileContextProvider extends AIContextProvider<FileContextItem> {
|
|
|
43
43
|
readonly mentionPrefix = "#";
|
|
44
44
|
readonly contextType = "file";
|
|
45
45
|
|
|
46
|
+
private apiRequests: EditRequests & RunRequests;
|
|
47
|
+
private config: FileSearchConfig;
|
|
48
|
+
|
|
46
49
|
constructor(
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
apiRequests: EditRequests & RunRequests,
|
|
51
|
+
config: FileSearchConfig = DEFAULT_FILE_SEARCH_CONFIG,
|
|
49
52
|
) {
|
|
50
53
|
super();
|
|
54
|
+
this.apiRequests = apiRequests;
|
|
55
|
+
this.config = config;
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
/**
|
|
@@ -17,9 +17,10 @@ export class TableContextProvider extends AIContextProvider<TableContextItem> {
|
|
|
17
17
|
readonly title = "Tables";
|
|
18
18
|
readonly mentionPrefix = "@";
|
|
19
19
|
readonly contextType = "data";
|
|
20
|
-
|
|
21
|
-
constructor(
|
|
20
|
+
private tablesMap: DatasetTablesMap;
|
|
21
|
+
constructor(tablesMap: DatasetTablesMap) {
|
|
22
22
|
super();
|
|
23
|
+
this.tablesMap = tablesMap;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
getItems(): TableContextItem[] {
|
|
@@ -20,11 +20,13 @@ export class VariableContextProvider extends AIContextProvider<VariableContextIt
|
|
|
20
20
|
readonly mentionPrefix = "@";
|
|
21
21
|
readonly contextType = "variable";
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
) {
|
|
23
|
+
private variables: Variables;
|
|
24
|
+
private tablesMap: DatasetTablesMap;
|
|
25
|
+
|
|
26
|
+
constructor(variables: Variables, tablesMap: DatasetTablesMap) {
|
|
27
27
|
super();
|
|
28
|
+
this.variables = variables;
|
|
29
|
+
this.tablesMap = tablesMap;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
getItems(): VariableContextItem[] {
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { UIMessageChunk } from "ai";
|
|
4
|
+
import { useRef } from "react";
|
|
5
|
+
import {
|
|
6
|
+
type AiCompletion,
|
|
7
|
+
codeToCells,
|
|
8
|
+
} from "@/components/editor/ai/completion-utils";
|
|
9
|
+
import { useDeleteCellCallback } from "@/components/editor/cell/useDeleteCell";
|
|
10
|
+
import { CellId } from "@/core/cells/ids";
|
|
11
|
+
import { createReducerAndAtoms } from "@/utils/createReducer";
|
|
12
|
+
import { Logger } from "@/utils/Logger";
|
|
13
|
+
import { cellHandleAtom, useCellActions } from "../cells/cells";
|
|
14
|
+
import type { LanguageAdapterType } from "../codemirror/language/types";
|
|
15
|
+
import { updateEditorCodeFromPython } from "../codemirror/language/utils";
|
|
16
|
+
import type { JotaiStore } from "../state/jotai";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Cells that are staged for AI completion
|
|
20
|
+
* They function similarly to cells in the notebook, but they can be deleted or accepted by the user.
|
|
21
|
+
* We only track one set of staged cells at a time.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const initialState = (): Set<CellId> => {
|
|
25
|
+
return new Set();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
valueAtom: stagedAICellsAtom,
|
|
30
|
+
useActions: useStagedAICellsActions,
|
|
31
|
+
createActions,
|
|
32
|
+
reducer,
|
|
33
|
+
} = createReducerAndAtoms(initialState, {
|
|
34
|
+
addStagedCell: (state, action: { cellId: CellId }) => {
|
|
35
|
+
const { cellId } = action;
|
|
36
|
+
return new Set([...state, cellId]);
|
|
37
|
+
},
|
|
38
|
+
removeStagedCell: (state, cellId: CellId) => {
|
|
39
|
+
return new Set([...state].filter((id) => id !== cellId));
|
|
40
|
+
},
|
|
41
|
+
clearStagedCells: () => {
|
|
42
|
+
return initialState();
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
interface UpdateStagedCellAction {
|
|
47
|
+
cellId: CellId;
|
|
48
|
+
code: string;
|
|
49
|
+
language?: LanguageAdapterType;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Helper functions to create and delete staged cells.
|
|
54
|
+
*/
|
|
55
|
+
export function useStagedCells(store: JotaiStore) {
|
|
56
|
+
const { addStagedCell, removeStagedCell, clearStagedCells } =
|
|
57
|
+
useStagedAICellsActions();
|
|
58
|
+
const { createNewCell } = useCellActions();
|
|
59
|
+
const deleteCellCallback = useDeleteCellCallback();
|
|
60
|
+
|
|
61
|
+
const cellCreationStream = useRef<CellCreationStream | null>(null);
|
|
62
|
+
|
|
63
|
+
const createStagedCell = (code: string): CellId => {
|
|
64
|
+
const newCellId = CellId.create();
|
|
65
|
+
addStagedCell({ cellId: newCellId });
|
|
66
|
+
createNewCell({
|
|
67
|
+
cellId: "__end__",
|
|
68
|
+
code,
|
|
69
|
+
before: false,
|
|
70
|
+
newCellId: newCellId,
|
|
71
|
+
});
|
|
72
|
+
return newCellId;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const updateStagedCell = (opts: UpdateStagedCellAction) => {
|
|
76
|
+
const { cellId, code } = opts;
|
|
77
|
+
const stagedAICells = store.get(stagedAICellsAtom);
|
|
78
|
+
|
|
79
|
+
if (!stagedAICells.has(cellId)) {
|
|
80
|
+
Logger.error("Staged cell not found", { cellId });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const cellHandle = store.get(cellHandleAtom(cellId));
|
|
85
|
+
const editorView = cellHandle?.current?.editorViewOrNull;
|
|
86
|
+
if (!editorView) {
|
|
87
|
+
Logger.error("Editor for this cell not found", { cellId });
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// TODO: Update the language
|
|
91
|
+
updateEditorCodeFromPython(editorView, code);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Delete a staged cell and the corresponding cell in the notebook.
|
|
95
|
+
const deleteStagedCell = (cellId: CellId) => {
|
|
96
|
+
removeStagedCell(cellId);
|
|
97
|
+
deleteCellCallback({ cellId });
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Delete all staged cells and the corresponding cells in the notebook.
|
|
101
|
+
const deleteAllStagedCells = () => {
|
|
102
|
+
const stagedAICells = store.get(stagedAICellsAtom);
|
|
103
|
+
for (const cellId of stagedAICells) {
|
|
104
|
+
deleteCellCallback({ cellId });
|
|
105
|
+
}
|
|
106
|
+
clearStagedCells();
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const onStream = (chunk: UIMessageChunk) => {
|
|
110
|
+
switch (chunk.type) {
|
|
111
|
+
case "text-start":
|
|
112
|
+
// Create stream
|
|
113
|
+
cellCreationStream.current = new CellCreationStream(
|
|
114
|
+
createStagedCell,
|
|
115
|
+
updateStagedCell,
|
|
116
|
+
);
|
|
117
|
+
break;
|
|
118
|
+
case "text-delta":
|
|
119
|
+
if (!cellCreationStream.current) {
|
|
120
|
+
Logger.error("Cell creation stream not found");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
cellCreationStream.current.stream(chunk);
|
|
124
|
+
break;
|
|
125
|
+
case "text-end":
|
|
126
|
+
case "finish":
|
|
127
|
+
if (!cellCreationStream.current) {
|
|
128
|
+
Logger.error("Cell creation stream not found");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
cellCreationStream.current.stop();
|
|
132
|
+
break;
|
|
133
|
+
default:
|
|
134
|
+
Logger.error("Unknown chunk type", { chunk });
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
createStagedCell,
|
|
140
|
+
updateStagedCell,
|
|
141
|
+
addStagedCell,
|
|
142
|
+
removeStagedCell,
|
|
143
|
+
clearStagedCells,
|
|
144
|
+
deleteStagedCell,
|
|
145
|
+
deleteAllStagedCells,
|
|
146
|
+
onStream,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export { stagedAICellsAtom };
|
|
151
|
+
export const visibleForTesting = {
|
|
152
|
+
createActions,
|
|
153
|
+
reducer,
|
|
154
|
+
initialState,
|
|
155
|
+
useStagedAICellsActions,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
type TextDeltaChunk = Extract<UIMessageChunk, { type: "text-delta" }>;
|
|
159
|
+
|
|
160
|
+
interface CreatedCell {
|
|
161
|
+
cellId: CellId;
|
|
162
|
+
cell: AiCompletion;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
class CellCreationStream {
|
|
166
|
+
private createdCells: CreatedCell[] = [];
|
|
167
|
+
private buffer = "";
|
|
168
|
+
|
|
169
|
+
private onCreateCell: (code: string) => CellId;
|
|
170
|
+
private onUpdateCell: (opts: UpdateStagedCellAction) => void;
|
|
171
|
+
|
|
172
|
+
constructor(
|
|
173
|
+
onCreateCell: (code: string) => CellId,
|
|
174
|
+
onUpdateCell: (opts: UpdateStagedCellAction) => void,
|
|
175
|
+
) {
|
|
176
|
+
this.onCreateCell = onCreateCell;
|
|
177
|
+
this.onUpdateCell = onUpdateCell;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
stream(chunk: TextDeltaChunk) {
|
|
181
|
+
const delta = chunk.delta;
|
|
182
|
+
this.buffer += delta;
|
|
183
|
+
const completionCells = codeToCells(this.buffer);
|
|
184
|
+
|
|
185
|
+
// As incoming chunks are appended to the buffer,
|
|
186
|
+
// we parse the buffer into cells and determine which parts correspond to which cell.
|
|
187
|
+
// For each parsed cell, we either update an existing staged cell or create a new one.
|
|
188
|
+
for (const [idx, cell] of completionCells.entries()) {
|
|
189
|
+
if (idx < this.createdCells.length) {
|
|
190
|
+
const existingCell = this.createdCells[idx];
|
|
191
|
+
this.createdCells[idx] = { ...existingCell, cell };
|
|
192
|
+
this.onUpdateCell({
|
|
193
|
+
cellId: existingCell.cellId,
|
|
194
|
+
code: cell.code,
|
|
195
|
+
language: cell.language,
|
|
196
|
+
});
|
|
197
|
+
} else {
|
|
198
|
+
const newCellId = this.onCreateCell(cell.code);
|
|
199
|
+
this.createdCells.push({ cellId: newCellId, cell });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
stop() {
|
|
205
|
+
// Clear all state
|
|
206
|
+
this.buffer = "";
|
|
207
|
+
}
|
|
208
|
+
}
|
package/src/core/cells/cells.ts
CHANGED
|
@@ -1623,7 +1623,7 @@ const cellDataAtom = atomFamily((cellId: CellId) =>
|
|
|
1623
1623
|
const cellRuntimeAtom = atomFamily((cellId: CellId) =>
|
|
1624
1624
|
atom((get) => get(notebookAtom).cellRuntime[cellId]),
|
|
1625
1625
|
);
|
|
1626
|
-
const cellHandleAtom = atomFamily((cellId: CellId) =>
|
|
1626
|
+
export const cellHandleAtom = atomFamily((cellId: CellId) =>
|
|
1627
1627
|
atom((get) => get(notebookAtom).cellHandles[cellId]),
|
|
1628
1628
|
);
|
|
1629
1629
|
/**
|
package/src/core/cells/logs.ts
CHANGED
|
@@ -102,7 +102,7 @@ export function formatLogTimestamp(timestamp: number): string {
|
|
|
102
102
|
try {
|
|
103
103
|
// parse from UTC
|
|
104
104
|
const date = fromUnixTime(timestamp);
|
|
105
|
-
return date.toLocaleTimeString(
|
|
105
|
+
return date.toLocaleTimeString(undefined, {
|
|
106
106
|
hour12: true,
|
|
107
107
|
hour: "numeric",
|
|
108
108
|
minute: "numeric",
|
|
@@ -91,8 +91,10 @@ const HighlightMargin = 250;
|
|
|
91
91
|
export const searchHighlighter = ViewPlugin.fromClass(
|
|
92
92
|
class {
|
|
93
93
|
decorations: DecorationSet;
|
|
94
|
+
readonly view: EditorView;
|
|
94
95
|
|
|
95
|
-
constructor(
|
|
96
|
+
constructor(view: EditorView) {
|
|
97
|
+
this.view = view;
|
|
96
98
|
this.decorations = this.highlight(view.state.field(searchState));
|
|
97
99
|
}
|
|
98
100
|
|