@marimo-team/frontend 0.25.1-dev26 → 0.25.1-dev28
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-t9uOAztV.js → ConnectedDataExplorerComponent-CEk030Wr.js} +1 -1
- package/dist/assets/{ErrorBoundary--lnCXIFD.js → ErrorBoundary-C7U9phn8.js} +2 -2
- package/dist/assets/{LazyAnyLanguageCodeMirror-DEZJTEMG.js → LazyAnyLanguageCodeMirror-DRPEmboS.js} +2 -2
- package/dist/assets/{RunButton-CjY7aPMv.js → RunButton-DaEo2YLw.js} +8 -8
- package/dist/assets/{abnfDiagram-VCTEODGH-D3pyWyFG.js → abnfDiagram-VCTEODGH-BPICToYh.js} +1 -1
- package/dist/assets/add-cell-with-ai-Szu4h2xr.js +76 -0
- package/dist/assets/{agent-panel-41Q1bpft.js → agent-panel-DOi8FFCM.js} +4 -4
- package/dist/assets/ai-model-dropdown-8njYygAy.js +5 -0
- package/dist/assets/{any-language-editor-D6brlHXI.js → any-language-editor-BO2KQgqe.js} +1 -1
- package/dist/assets/app-config-button-DPOpo6fD.js +1 -0
- package/dist/assets/{architectureDiagram-5GKGNRK7-oTI8YQKz.js → architectureDiagram-5GKGNRK7-D0Nj4LZV.js} +1 -1
- package/dist/assets/{blockDiagram-I7D4REHJ-Cnm4oF2u.js → blockDiagram-I7D4REHJ-DGl4_x69.js} +1 -1
- package/dist/assets/{cache-panel-B4G-uWUR.js → cache-panel-PIZV9skZ.js} +1 -1
- package/dist/assets/{chat-display-Cw-iQuoj.js → chat-display-CrQhSDTe.js} +1 -1
- package/dist/assets/chat-panel-rZcx6i0J.js +4 -0
- package/dist/assets/{chat-ui-DLo9ZGZh.js → chat-ui-Cq9S1Vfd.js} +4 -4
- package/dist/assets/{chunk-IMKFNOWR-BrbWV3sF.js → chunk-IMKFNOWR-Cf41dfnh.js} +1 -1
- package/dist/assets/{chunk-SHT3W25Y-BJ_x5e71.js → chunk-SHT3W25Y-C5Pw7o8Z.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-Bt_4tS-L.js → chunk-SVP7TREG-NUl6G0sX.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-B13LvaWF.js → chunk-TICWLB2K-nULmAXZ1.js} +1 -1
- package/dist/assets/{classDiagram-ZZMXUADV-B-IjDADz.js → classDiagram-ZZMXUADV--OufHXVT.js} +1 -1
- package/dist/assets/{classDiagram-v2-VYDZK3BY-B-IjDADz.js → classDiagram-v2-VYDZK3BY--OufHXVT.js} +1 -1
- package/dist/assets/{code-visibility-CauDwSK7.js → code-visibility-Dbkqo9JU.js} +1 -1
- package/dist/assets/{command-palette-utOoq6Rp.js → command-palette-CTE4dAh0.js} +1 -1
- package/dist/assets/{common-DeBI0gTr.js → common-Br8QwTYp.js} +1 -1
- package/dist/assets/{components-Oc8eeLbJ.js → components-BazbSuIT.js} +1 -1
- package/dist/assets/{components-BK--XBj0.js → components-Dr8S9a39.js} +1 -1
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-DHZ9-quo.js → cynefinDiagram-5FMLGOSQ-BnDBzYE4.js} +1 -1
- package/dist/assets/dagre-BjMCWsBB.js +1 -0
- package/dist/assets/{dagre-GXQ25YYZ-DRb8_8NA.js → dagre-GXQ25YYZ-C6HjhdC6.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-B2hwnMJ3.js → data-grid-overlay-editor-BhYanmB4.js} +1 -1
- package/dist/assets/{dependency-graph-panel-B1jufpX0.js → dependency-graph-panel-KhePinnC.js} +3 -3
- package/dist/assets/{diagram-S7CK7UJ4-Bd-qZQpl.js → diagram-S7CK7UJ4-puXb_Rtq.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-BHN8pD4Q.js → diagram-UQ7AKVKN-BRNrAZmm.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-BbaAWkYr.js → diagram-VX7I27RA-FYgcY0ll.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-Dtpiv_xD.js → diagram-Z3DM3KII-0a9IJqv0.js} +1 -1
- package/dist/assets/{documentation-panel-DLkNDOKi.js → documentation-panel-CVIeqh1b.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-CgYHyyJc.js → ebnfDiagram-PWID7BFC-mIbU0Xap.js} +1 -1
- package/dist/assets/{edit-page-AiTNfZz6.js → edit-page-DPcMmMvJ.js} +49 -51
- package/dist/assets/{erDiagram-RLTQ6QDP-BoolGO7m.js → erDiagram-RLTQ6QDP-Cd4GM-oc.js} +1 -1
- package/dist/assets/{error-panel-CsJ0nRLJ.js → error-panel-BQh3dJvY.js} +1 -1
- package/dist/assets/{feedback-button-CHLsW9bZ.js → feedback-button-Bv9N5kfQ.js} +2 -2
- package/dist/assets/{file-explorer-panel-dsPTglvB.js → file-explorer-panel-Cw-riLBk.js} +1 -1
- package/dist/assets/file-name-input-45TcG8Ds.js +3 -0
- package/dist/assets/filename-CVTfpc8L.js +1 -0
- package/dist/assets/{flowDiagram-HODETNUW-BrmilZCm.js → flowDiagram-HODETNUW-DoAP7Em-.js} +1 -1
- package/dist/assets/{gallery-page-pLo1psd7.js → gallery-page-DF-L2Hg7.js} +1 -1
- package/dist/assets/glide-data-editor-CeEFyCyf.js +131 -0
- package/dist/assets/{graphlib-CHvuCU4R.js → graphlib-D4-sEAEu.js} +1 -1
- package/dist/assets/has-BZiXT9H1.js +1 -0
- package/dist/assets/{home-page-X2fejRNI.js → home-page-D7-nxzVU.js} +2 -2
- package/dist/assets/index-CwgxYBE_.css +2 -0
- package/dist/assets/index-DZqTrlKL.js +62 -0
- package/dist/assets/{infoDiagram-27XIBGKW-Bt0srlSq.js → infoDiagram-27XIBGKW-DisP8YlO.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-h6YlY6VO.js → ishikawaDiagram-5VMMS53U-DrZXbBhn.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-C560hBSc.js → kanban-definition-UXKFOSKX-DjYaQ7cZ.js} +1 -1
- package/dist/assets/{logs-panel-B1XeNAcA.js → logs-panel-C0JyIjb-.js} +1 -1
- package/dist/assets/{mermaid-CmWpJ3Ac.js → mermaid-Cf8lqXqK.js} +4 -4
- package/dist/assets/{mindmap-definition-YA3MSWOX-CbR4Nl2Y.js → mindmap-definition-YA3MSWOX-BfdtRUZ5.js} +1 -1
- package/dist/assets/{number-overlay-editor-72kuDgL9.js → number-overlay-editor-gJYkb7UJ.js} +1 -1
- package/dist/assets/{outline-panel-PezW3BPa.js → outline-panel-PsjDONzX.js} +1 -1
- package/dist/assets/packages-panel-B75bdIo0.js +1 -0
- package/dist/assets/{panels-KrQ_WMY1.js → panels-C4MoKhQw.js} +9 -9
- package/dist/assets/{pegDiagram-XKGWAZYB-cuz0NTuW.js → pegDiagram-XKGWAZYB-CYaHdB2n.js} +1 -1
- package/dist/assets/{pieDiagram-E7YTZNPT-DFRcYVTS.js → pieDiagram-E7YTZNPT-CVS0Hdon.js} +1 -1
- package/dist/assets/{process-output-DEyFMCxj.js → process-output-BBoXTTZf.js} +1 -1
- package/dist/assets/{railroadDiagram-O6MQD6OU-DrSdGHPf.js → railroadDiagram-O6MQD6OU-CmjNDTQ_.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-CFxQz8MA.js → requirementDiagram-BXWQKSXE-pveEaBVb.js} +1 -1
- package/dist/assets/{reveal-component-VwaMID0f.js → reveal-component-BQrEwlGW.js} +3 -3
- package/dist/assets/run-page-ByRNiVEw.js +1 -0
- package/dist/assets/{scratchpad-panel-BSc3pmsc.js → scratchpad-panel-DSo4DfEm.js} +1 -1
- package/dist/assets/{secrets-panel-CD3OcRVl.js → secrets-panel-Twujk_1B.js} +1 -1
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-BqdCj3Qv.js → sequenceDiagram-WJ2MYXX4-yG9WGeGU.js} +1 -1
- package/dist/assets/{session-panel-UkrTlFFZ.js → session-panel-Cxg1jbpz.js} +1 -1
- package/dist/assets/{SelectionIndicator-DLJBcP4e.js → shell-BSnvn9t7.js} +1 -1
- package/dist/assets/{snippets-panel-BzGbwvC_.js → snippets-panel-DOmIRweD.js} +1 -1
- package/dist/assets/{stateDiagram-D77RDMKH-C47ziFps.js → stateDiagram-D77RDMKH-HwpM4BWS.js} +1 -1
- package/dist/assets/{stateDiagram-v2-MP3YSRHH-CnMQCmnm.js → stateDiagram-v2-MP3YSRHH-Cg5o2AFK.js} +1 -1
- package/dist/assets/{swimlanes-42K2YHIH-CdVR2SfQ.js → swimlanes-42K2YHIH-vnyrUnUj.js} +1 -1
- package/dist/assets/{swimlanesDiagram-VR7AAH4N-DjL53PeL.js → swimlanesDiagram-VR7AAH4N-CDSAC7kd.js} +1 -1
- package/dist/assets/{swiper-component-CnMDaKpf.js → swiper-component-COoqfICh.js} +1 -1
- package/dist/assets/{terminal-BGeOMO4c.js → terminal-BvGa3-Zb.js} +1 -1
- package/dist/assets/{timeline-definition-24CTP7MA-BMlyCUgN.js → timeline-definition-24CTP7MA-Ci_0VG5-.js} +1 -1
- package/dist/assets/{tracing-DIQLfRSW.js → tracing-D5Z2olGj.js} +1 -1
- package/dist/assets/tracing-panel-DAEyvbPv.js +2 -0
- package/dist/assets/{useCellActionButton-CybJtMit.js → useCellActionButton-C9tGr-T8.js} +1 -1
- package/dist/assets/{vega-component-B422ZG4v.js → vega-component-F6JI94_G.js} +1 -1
- package/dist/assets/{vega-embed-container-B-t4XshS.js → vega-embed-container-D5fybnJd.js} +1 -1
- package/dist/assets/{vennDiagram-4TSXK5OY-DXc5pYYY.js → vennDiagram-4TSXK5OY-5Pnagf9w.js} +1 -1
- package/dist/assets/{wardleyDiagram-VM6X3IG4-D6TMjDMB.js → wardleyDiagram-VM6X3IG4-rIaxW9T4.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-Cp-vmWO7.js → xychartDiagram-S5SC5T6Z-78iNa87v.js} +1 -1
- package/dist/index.html +5 -4
- package/package.json +1 -1
- package/src/__mocks__/common.ts +3 -3
- package/src/__tests__/CellStatus.test.tsx +1 -1
- package/src/__tests__/setup.ts +7 -7
- package/src/components/app-config/ai-config.tsx +2 -0
- package/src/components/chat/chat-panel.tsx +19 -8
- package/src/components/data-table/column-summary/chart-spec-model.tsx +4 -4
- package/src/components/dependency-graph/elements.ts +2 -2
- package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +107 -0
- package/src/components/editor/actions/pair-with-agent.tsx +119 -0
- package/src/components/editor/actions/useNotebookActions.tsx +2 -1
- package/src/components/editor/ai/add-cell-with-ai.tsx +2 -0
- package/src/components/editor/ai/staged-cell-submission.ts +2 -2
- package/src/components/editor/ai/transport/chat-transport.tsx +1 -1
- package/src/components/editor/connections/database/as-code.ts +44 -44
- package/src/components/editor/connections/storage/as-code.ts +3 -3
- package/src/components/editor/file-tree/requesting-tree.tsx +16 -13
- package/src/components/editor/navigation/clipboard.ts +2 -2
- package/src/components/editor/output/ansi-reduce.ts +13 -13
- package/src/components/slides/__tests__/minimap-actions.test.tsx +7 -7
- package/src/components/slides/__tests__/minimap.test.ts +12 -12
- package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +8 -8
- package/src/core/ai/context/__tests__/registry.test.ts +31 -28
- package/src/core/ai/context/providers/cell-output.ts +8 -8
- package/src/core/ai/context/providers/datasource.ts +10 -7
- package/src/core/ai/context/providers/error.ts +7 -7
- package/src/core/ai/context/providers/file.ts +8 -8
- package/src/core/ai/context/providers/tables.ts +7 -7
- package/src/core/ai/context/providers/variable.ts +7 -7
- package/src/core/ai/context/registry.ts +18 -18
- package/src/core/ai/ids/ids.ts +5 -5
- package/src/core/ai/model-registry.ts +12 -9
- package/src/core/ai/staged-cells.ts +6 -6
- package/src/core/ai/tools/base.ts +6 -6
- package/src/core/ai/tools/edit-notebook-tool.ts +6 -6
- package/src/core/ai/tools/registry.ts +4 -4
- package/src/core/ai/tools/run-cells-tool.ts +7 -7
- package/src/core/ai/tools/sample-tool.ts +6 -6
- package/src/core/codemirror/cells/debugger-decorations.ts +13 -7
- package/src/core/codemirror/cells/line-timing-decorations.ts +9 -9
- package/src/core/codemirror/cells/traceback-decorations.ts +7 -4
- package/src/core/codemirror/code-lens/extension.ts +13 -13
- package/src/core/codemirror/copilot/__tests__/language-server.test.ts +6 -6
- package/src/core/codemirror/copilot/__tests__/transport.test.ts +12 -12
- package/src/core/codemirror/copilot/language-server.ts +13 -13
- package/src/core/codemirror/copilot/transport.ts +1 -1
- package/src/core/codemirror/find-replace/search-highlight.ts +5 -5
- package/src/core/codemirror/go-to-definition/underline.ts +3 -3
- package/src/core/codemirror/keymaps/vim.ts +3 -3
- package/src/core/codemirror/language/languages/markdown.ts +8 -8
- package/src/core/codemirror/language/languages/python.ts +7 -7
- package/src/core/codemirror/language/languages/sql/completion-builder.ts +5 -5
- package/src/core/codemirror/language/languages/sql/completion-store.ts +4 -4
- package/src/core/codemirror/language/languages/sql/sql.ts +21 -21
- package/src/core/codemirror/lsp/__tests__/transports.test.ts +10 -10
- package/src/core/codemirror/lsp/federated-lsp.ts +29 -27
- package/src/core/codemirror/lsp/notebook-lsp.ts +21 -21
- package/src/core/codemirror/misc/__tests__/dnd.test.ts +10 -10
- package/src/core/codemirror/misc/__tests__/paste.test.ts +7 -4
- package/src/core/codemirror/reactive-references/extension.ts +3 -3
- package/src/core/codemirror/rtc/loro/awareness.ts +12 -12
- package/src/core/codemirror/rtc/loro/sync.ts +5 -5
- package/src/core/codemirror/vim/cursor-visibility.ts +3 -3
- package/src/core/dom/ui-element.ts +5 -5
- package/src/core/dom/uiregistry.ts +10 -10
- package/src/core/hotkeys/hotkeys.ts +9 -9
- package/src/core/islands/__tests__/bridge.test.ts +4 -4
- package/src/core/islands/__tests__/test-utils.tsx +4 -4
- package/src/core/islands/bridge.ts +85 -82
- package/src/core/islands/components/web-components.tsx +7 -7
- package/src/core/islands/worker/__tests__/controller.test.ts +1 -1
- package/src/core/islands/worker/controller.ts +6 -3
- package/src/core/islands/worker-factory.ts +2 -2
- package/src/core/kernel/RuntimeState.ts +4 -4
- package/src/core/lsp/__tests__/transport.test.ts +19 -19
- package/src/core/lsp/transport.ts +5 -5
- package/src/core/network/CachingRequestRegistry.ts +2 -2
- package/src/core/network/DeferredRequestRegistry.ts +4 -4
- package/src/core/runtime/runtime.ts +25 -20
- package/src/core/static/virtual-file-tracker.ts +5 -5
- package/src/core/wasm/__tests__/bridge.test.ts +2 -2
- package/src/core/wasm/bridge.ts +130 -126
- package/src/core/wasm/router.ts +5 -5
- package/src/core/wasm/store.ts +4 -4
- package/src/core/wasm/worker/bootstrap.ts +8 -5
- package/src/core/wasm/worker/message-buffer.ts +3 -3
- package/src/core/websocket/transports/__tests__/ws.test.ts +8 -8
- package/src/core/websocket/transports/basic.ts +15 -8
- package/src/core/websocket/transports/sse.ts +7 -7
- package/src/core/websocket/transports/transport.ts +3 -3
- package/src/core/websocket/transports/ws.ts +9 -7
- package/src/hooks/__tests__/useOverflowDetection.test.tsx +5 -5
- package/src/hooks/__tests__/useResizeObserver.test.tsx +12 -12
- package/src/plugins/core/registerReactComponent.tsx +5 -5
- package/src/plugins/core/sidebar-element.tsx +2 -2
- package/src/plugins/impl/ButtonPlugin.tsx +3 -3
- package/src/plugins/impl/CheckboxPlugin.tsx +3 -3
- package/src/plugins/impl/CodeEditorPlugin.tsx +3 -3
- package/src/plugins/impl/DatePickerPlugin.tsx +3 -3
- package/src/plugins/impl/DateRangePlugin.tsx +3 -3
- package/src/plugins/impl/DateTimePickerPlugin.tsx +3 -3
- package/src/plugins/impl/DictPlugin.tsx +3 -3
- package/src/plugins/impl/DropdownPlugin.tsx +3 -3
- package/src/plugins/impl/FileUploadPlugin.tsx +3 -3
- package/src/plugins/impl/MatrixPlugin.tsx +4 -4
- package/src/plugins/impl/MicrophonePlugin.tsx +3 -3
- package/src/plugins/impl/MultiselectPlugin.tsx +3 -3
- package/src/plugins/impl/NumberPlugin.tsx +3 -3
- package/src/plugins/impl/RadioPlugin.tsx +3 -3
- package/src/plugins/impl/RangeSliderPlugin.tsx +3 -3
- package/src/plugins/impl/RefreshPlugin.tsx +3 -3
- package/src/plugins/impl/SliderPlugin.tsx +3 -3
- package/src/plugins/impl/SwitchPlugin.tsx +3 -3
- package/src/plugins/impl/TabsPlugin.tsx +3 -3
- package/src/plugins/impl/TextAreaPlugin.tsx +3 -3
- package/src/plugins/impl/TextInputPlugin.tsx +3 -3
- package/src/plugins/impl/__tests__/MatrixPlugin.test.tsx +2 -2
- package/src/plugins/impl/anywidget/model.ts +10 -10
- package/src/plugins/impl/anywidget/registry.ts +12 -9
- package/src/plugins/impl/anywidget/runtime.ts +11 -9
- package/src/plugins/impl/anywidget/widget-binding.ts +6 -6
- package/src/plugins/impl/matplotlib/MatplotlibPlugin.tsx +3 -3
- package/src/plugins/impl/matplotlib/__tests__/matplotlib-renderer.test.ts +2 -2
- package/src/plugins/impl/matplotlib/matplotlib-renderer.ts +2 -2
- package/src/plugins/impl/mpl-interactive/mpl-websocket-shim.ts +10 -10
- package/src/plugins/impl/panel/utils.ts +5 -5
- package/src/plugins/impl/plotly/PlotlyPlugin.tsx +3 -3
- package/src/plugins/impl/vega/VegaPlugin.tsx +3 -3
- package/src/plugins/impl/vega/__tests__/use-vega-container-remeasure.test.ts +7 -7
- package/src/plugins/layout/AccordionPlugin.tsx +3 -3
- package/src/plugins/layout/CalloutPlugin.tsx +3 -3
- package/src/plugins/layout/ImageComparisonPlugin.tsx +5 -3
- package/src/plugins/layout/JsonOutputPlugin.tsx +3 -3
- package/src/plugins/layout/MimeRenderPlugin.tsx +3 -3
- package/src/plugins/layout/NavigationMenuPlugin.tsx +3 -3
- package/src/plugins/layout/OutlinePlugin.tsx +3 -3
- package/src/plugins/layout/ProgressPlugin.tsx +3 -3
- package/src/plugins/layout/RoutesPlugin.tsx +3 -3
- package/src/plugins/layout/StatPlugin.tsx +3 -3
- package/src/plugins/layout/TexPlugin.tsx +3 -3
- package/src/plugins/layout/carousel/CarouselPlugin.tsx +4 -4
- package/src/plugins/layout/mermaid/MermaidPlugin.tsx +3 -3
- package/src/utils/Deferred.ts +6 -6
- package/src/utils/async-capture-tracker.ts +10 -7
- package/src/utils/errors.ts +5 -5
- package/src/utils/id-tree.tsx +83 -80
- package/src/utils/lru.ts +1 -1
- package/src/utils/multi-map.ts +14 -12
- package/src/utils/paths.ts +6 -6
- package/src/utils/pluralize.ts +3 -3
- package/src/utils/progress.ts +6 -6
- package/src/utils/python-poet/poet.ts +14 -14
- package/src/utils/routes.ts +4 -2
- package/src/utils/semaphore.ts +6 -6
- package/src/utils/storage/storage.ts +6 -6
- package/src/utils/storage/typed.ts +16 -12
- package/src/utils/time.ts +9 -9
- package/src/utils/timed-cache.ts +4 -4
- package/src/utils/tracer.ts +9 -6
- package/dist/assets/add-cell-with-ai-o7qE-POK.js +0 -76
- package/dist/assets/ai-model-dropdown-DOV_oIBK.js +0 -3
- package/dist/assets/app-config-button-D2zqcQ-F.js +0 -1
- package/dist/assets/chat-panel-D1Q3duJr.js +0 -4
- package/dist/assets/dagre-BdtjN8cC.js +0 -1
- package/dist/assets/file-name-input-B4Bgx78g.js +0 -3
- package/dist/assets/glide-data-editor-DxmImoEe.js +0 -131
- package/dist/assets/has-CIUK-df8.js +0 -1
- package/dist/assets/index-D3e7_w06.js +0 -62
- package/dist/assets/index-DWEk4MKV.css +0 -2
- package/dist/assets/packages-panel-BwGU6beY.js +0 -1
- package/dist/assets/run-page-DXrsG7am.js +0 -1
- package/dist/assets/tracing-panel-Bcvk8RXQ.js +0 -2
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { Provider } from "jotai";
|
|
5
|
+
import type React from "react";
|
|
6
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
7
|
+
import { ModalProvider } from "@/components/modal/ImperativeModal";
|
|
8
|
+
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
9
|
+
import { store } from "@/core/state/jotai";
|
|
10
|
+
import { PairWithAgentBanner, PairWithAgentButton } from "../pair-with-agent";
|
|
11
|
+
|
|
12
|
+
const mocks = vi.hoisted(() => ({
|
|
13
|
+
isWasm: vi.fn(() => false),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
vi.mock("@/core/wasm/utils", () => ({
|
|
17
|
+
isWasm: mocks.isWasm,
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
function wrapper({ children }: { children: React.ReactNode }) {
|
|
21
|
+
return (
|
|
22
|
+
<Provider store={store}>
|
|
23
|
+
<TooltipProvider>
|
|
24
|
+
<ModalProvider>{children}</ModalProvider>
|
|
25
|
+
</TooltipProvider>
|
|
26
|
+
</Provider>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function stubTokenFetch() {
|
|
31
|
+
vi.stubGlobal(
|
|
32
|
+
"fetch",
|
|
33
|
+
vi.fn().mockResolvedValue(new Response(JSON.stringify({ token: null }))),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe("PairWithAgent", () => {
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
vi.unstubAllGlobals();
|
|
40
|
+
mocks.isWasm.mockReset();
|
|
41
|
+
mocks.isWasm.mockReturnValue(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("shows local agent options", () => {
|
|
45
|
+
render(<PairWithAgentBanner />, { wrapper });
|
|
46
|
+
|
|
47
|
+
expect(
|
|
48
|
+
screen.getByRole("group", { name: "Supported agents" }),
|
|
49
|
+
).toBeVisible();
|
|
50
|
+
expect(screen.getByRole("figure", { name: "Claude Code" })).toBeVisible();
|
|
51
|
+
expect(screen.getByRole("figure", { name: "Codex" })).toBeVisible();
|
|
52
|
+
expect(screen.getByRole("figure", { name: "Cursor" })).toBeVisible();
|
|
53
|
+
expect(screen.getByRole("figure", { name: "Gemini CLI" })).toBeVisible();
|
|
54
|
+
expect(screen.getByRole("figure", { name: "OpenCode" })).toBeVisible();
|
|
55
|
+
expect(
|
|
56
|
+
screen.getByRole("figure", { name: "GitHub Copilot" }),
|
|
57
|
+
).toBeVisible();
|
|
58
|
+
expect(
|
|
59
|
+
screen.getByRole("figure", { name: "Any local agent" }),
|
|
60
|
+
).toBeVisible();
|
|
61
|
+
expect(
|
|
62
|
+
screen.getByRole("button", {
|
|
63
|
+
name: "Learn more.",
|
|
64
|
+
}),
|
|
65
|
+
).toBeVisible();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("opens the pairing dialog from the banner description", () => {
|
|
69
|
+
stubTokenFetch();
|
|
70
|
+
render(<PairWithAgentBanner />, { wrapper });
|
|
71
|
+
|
|
72
|
+
fireEvent.click(
|
|
73
|
+
screen.getByRole("button", {
|
|
74
|
+
name: "Learn more.",
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(
|
|
79
|
+
screen.getByRole("dialog", { name: "Pair with an agent" }),
|
|
80
|
+
).toBeVisible();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("opens the pairing dialog and preserves a passed click handler", () => {
|
|
84
|
+
const onClick = vi.fn();
|
|
85
|
+
stubTokenFetch();
|
|
86
|
+
render(<PairWithAgentButton onClick={onClick} />, { wrapper });
|
|
87
|
+
|
|
88
|
+
fireEvent.click(screen.getByRole("button", { name: "Connect your agent" }));
|
|
89
|
+
|
|
90
|
+
expect(onClick).toHaveBeenCalledOnce();
|
|
91
|
+
expect(
|
|
92
|
+
screen.getByRole("dialog", { name: "Pair with an agent" }),
|
|
93
|
+
).toBeVisible();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("hides pairing controls in WASM", () => {
|
|
97
|
+
mocks.isWasm.mockReturnValue(true);
|
|
98
|
+
|
|
99
|
+
const { container, rerender } = render(<PairWithAgentButton />, {
|
|
100
|
+
wrapper,
|
|
101
|
+
});
|
|
102
|
+
expect(container).toBeEmptyDOMElement();
|
|
103
|
+
|
|
104
|
+
rerender(<PairWithAgentBanner />);
|
|
105
|
+
expect(container).toBeEmptyDOMElement();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { BotIcon } from "lucide-react";
|
|
4
|
+
import React from "react";
|
|
5
|
+
import { AiProviderIcon } from "@/components/ai/ai-provider-icon";
|
|
6
|
+
import { useImperativeModal } from "@/components/modal/ImperativeModal";
|
|
7
|
+
import { Button, type ButtonProps } from "@/components/ui/button";
|
|
8
|
+
import { isWasm } from "@/core/wasm/utils";
|
|
9
|
+
import { cn } from "@/utils/cn";
|
|
10
|
+
import { PairWithAgentModal } from "./pair-with-agent-modal";
|
|
11
|
+
|
|
12
|
+
const FEATURED_AGENTS = [
|
|
13
|
+
{ id: "claude", label: "Claude Code" },
|
|
14
|
+
{ id: "codex", label: "Codex" },
|
|
15
|
+
{ id: "cursor", label: "Cursor" },
|
|
16
|
+
{ id: "gemini", label: "Gemini CLI" },
|
|
17
|
+
{ id: "opencode", label: "OpenCode" },
|
|
18
|
+
{ id: "github", label: "GitHub Copilot" },
|
|
19
|
+
{ id: "openai-compatible", label: "Any local agent" },
|
|
20
|
+
] as const satisfies ReadonlyArray<{
|
|
21
|
+
id: React.ComponentProps<typeof AiProviderIcon>["provider"];
|
|
22
|
+
label: string;
|
|
23
|
+
}>;
|
|
24
|
+
|
|
25
|
+
export const usePairWithAgentModal = () => {
|
|
26
|
+
const { openModal, closeModal } = useImperativeModal();
|
|
27
|
+
|
|
28
|
+
return React.useCallback(
|
|
29
|
+
() => openModal(<PairWithAgentModal onClose={closeModal} />),
|
|
30
|
+
[openModal, closeModal],
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const PairWithAgentButton: React.FC<
|
|
35
|
+
ButtonProps & { label?: string }
|
|
36
|
+
> = ({ className, label = "Connect your agent", onClick, ...props }) => {
|
|
37
|
+
const openPairWithAgentModal = usePairWithAgentModal();
|
|
38
|
+
|
|
39
|
+
if (isWasm()) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Button
|
|
45
|
+
type="button"
|
|
46
|
+
variant="link"
|
|
47
|
+
size="xs"
|
|
48
|
+
className={cn("h-auto gap-1 px-0", className)}
|
|
49
|
+
onClick={(event) => {
|
|
50
|
+
onClick?.(event);
|
|
51
|
+
if (!event.defaultPrevented) {
|
|
52
|
+
openPairWithAgentModal();
|
|
53
|
+
}
|
|
54
|
+
}}
|
|
55
|
+
{...props}
|
|
56
|
+
>
|
|
57
|
+
{label}
|
|
58
|
+
</Button>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const PairWithAgentBanner: React.FC<{
|
|
63
|
+
label?: string;
|
|
64
|
+
className?: string;
|
|
65
|
+
}> = ({ label = "Connect your agent", className }) => {
|
|
66
|
+
const openPairWithAgentModal = usePairWithAgentModal();
|
|
67
|
+
|
|
68
|
+
if (isWasm()) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
className={cn(
|
|
75
|
+
"rounded-lg border border-(--blue-6) bg-(--blue-2)/50 p-3",
|
|
76
|
+
className,
|
|
77
|
+
)}
|
|
78
|
+
>
|
|
79
|
+
<div className="flex items-center gap-2 text-sm font-semibold">
|
|
80
|
+
{label}
|
|
81
|
+
<fieldset
|
|
82
|
+
className="m-0 flex min-w-0 -space-x-1.5 border-0 p-0 mb-0.5"
|
|
83
|
+
aria-label="Supported agents"
|
|
84
|
+
>
|
|
85
|
+
{FEATURED_AGENTS.map(({ id, label }) => (
|
|
86
|
+
<figure
|
|
87
|
+
key={id}
|
|
88
|
+
title={label}
|
|
89
|
+
aria-label={label}
|
|
90
|
+
className="flex size-6 items-center justify-center rounded-full border bg-background shadow-xs"
|
|
91
|
+
>
|
|
92
|
+
{id === "openai-compatible" ? (
|
|
93
|
+
<BotIcon className="size-3.5" aria-hidden={true} />
|
|
94
|
+
) : (
|
|
95
|
+
<AiProviderIcon
|
|
96
|
+
provider={id}
|
|
97
|
+
className="size-3.5"
|
|
98
|
+
aria-hidden={true}
|
|
99
|
+
/>
|
|
100
|
+
)}
|
|
101
|
+
</figure>
|
|
102
|
+
))}
|
|
103
|
+
</fieldset>
|
|
104
|
+
</div>
|
|
105
|
+
<div className="mt-1 text-xs leading-relaxed">
|
|
106
|
+
<p className="inline">
|
|
107
|
+
Use your AI coding agent to pair-program on this notebook.
|
|
108
|
+
</p>
|
|
109
|
+
<button
|
|
110
|
+
type="button"
|
|
111
|
+
onClick={openPairWithAgentModal}
|
|
112
|
+
className="text-link hover:underline ml-1"
|
|
113
|
+
>
|
|
114
|
+
Learn more.
|
|
115
|
+
</button>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
@@ -297,11 +297,12 @@ export function useNotebookActions({
|
|
|
297
297
|
|
|
298
298
|
{
|
|
299
299
|
icon: <SparklesIcon size={14} strokeWidth={1.5} />,
|
|
300
|
-
label: "
|
|
300
|
+
label: "Connect your agent",
|
|
301
301
|
hidden: isWasm(),
|
|
302
302
|
handle: async () => {
|
|
303
303
|
openModal(<PairWithAgentModal onClose={closeModal} />);
|
|
304
304
|
},
|
|
305
|
+
additionalKeywords: ["connect"],
|
|
305
306
|
},
|
|
306
307
|
|
|
307
308
|
{
|
|
@@ -29,6 +29,7 @@ import useEvent from "react-use-event-hook";
|
|
|
29
29
|
import { DefaultChatTransport } from "ai";
|
|
30
30
|
import { z } from "zod";
|
|
31
31
|
import { AIModelDropdown } from "@/components/ai/ai-model-dropdown";
|
|
32
|
+
import { PairWithAgentButton } from "@/components/editor/actions/pair-with-agent";
|
|
32
33
|
import {
|
|
33
34
|
AddContextButton,
|
|
34
35
|
AttachFileButton,
|
|
@@ -301,6 +302,7 @@ export const AddCellWithAI: React.FC<{
|
|
|
301
302
|
showAddCustomModelDocs={true}
|
|
302
303
|
/>
|
|
303
304
|
{languageDropdown}
|
|
305
|
+
<PairWithAgentButton />
|
|
304
306
|
</div>
|
|
305
307
|
<div className="flex flex-row items-center">
|
|
306
308
|
{files.length > 0 && (
|
|
@@ -14,13 +14,13 @@ interface SubmissionAttempt {
|
|
|
14
14
|
export class StagedCellSubmissionController {
|
|
15
15
|
private activeAttempt: SubmissionAttempt | null = null;
|
|
16
16
|
|
|
17
|
-
cancel() {
|
|
17
|
+
public cancel() {
|
|
18
18
|
if (this.activeAttempt) {
|
|
19
19
|
this.activeAttempt.cancelled = true;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
async run<T>({ prepare, submit, onError }: SubmissionCallbacks<T>) {
|
|
23
|
+
public async run<T>({ prepare, submit, onError }: SubmissionCallbacks<T>) {
|
|
24
24
|
if (this.activeAttempt !== null) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
@@ -15,7 +15,7 @@ export class StreamingChunkTransport<
|
|
|
15
15
|
> extends DefaultChatTransport<UI_MESSAGE> {
|
|
16
16
|
private onChunkReceived: (chunk: UIMessageChunk) => void;
|
|
17
17
|
|
|
18
|
-
constructor(
|
|
18
|
+
public constructor(
|
|
19
19
|
options: HttpChatTransportInitOptions<UI_MESSAGE>,
|
|
20
20
|
onChunkReceived: (chunk: UIMessageChunk) => void,
|
|
21
21
|
) {
|
|
@@ -36,7 +36,7 @@ abstract class CodeGenerator<T extends DatabaseConnection["type"]> {
|
|
|
36
36
|
protected orm: ConnectionLibrary;
|
|
37
37
|
protected secrets: SecretContainer;
|
|
38
38
|
|
|
39
|
-
constructor(
|
|
39
|
+
public constructor(
|
|
40
40
|
connection: Extract<DatabaseConnection, { type: T }>,
|
|
41
41
|
orm: ConnectionLibrary,
|
|
42
42
|
secrets: SecretContainer,
|
|
@@ -46,7 +46,7 @@ abstract class CodeGenerator<T extends DatabaseConnection["type"]> {
|
|
|
46
46
|
this.secrets = secrets;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
get imports(): Set<string> {
|
|
49
|
+
public get imports(): Set<string> {
|
|
50
50
|
const imports = new Set<string>(this.generateImports());
|
|
51
51
|
switch (this.orm) {
|
|
52
52
|
case "sqlalchemy":
|
|
@@ -67,7 +67,7 @@ abstract class CodeGenerator<T extends DatabaseConnection["type"]> {
|
|
|
67
67
|
|
|
68
68
|
protected abstract generateImports(): string[];
|
|
69
69
|
|
|
70
|
-
abstract generateConnectionCode(): string;
|
|
70
|
+
public abstract generateConnectionCode(): string;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const makePrivate = (name: string) => `_${name}`;
|
|
@@ -75,14 +75,14 @@ const makePrivate = (name: string) => `_${name}`;
|
|
|
75
75
|
class SecretContainer {
|
|
76
76
|
private secrets: Record<string, string> = {};
|
|
77
77
|
|
|
78
|
-
get imports(): Set<string> {
|
|
78
|
+
public get imports(): Set<string> {
|
|
79
79
|
if (Object.keys(this.secrets).length === 0) {
|
|
80
80
|
return new Set<string>();
|
|
81
81
|
}
|
|
82
82
|
return new Set<string>(["import os"]);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
print(
|
|
85
|
+
public print(
|
|
86
86
|
varName: string,
|
|
87
87
|
secretKeyOrValue: string | number | boolean,
|
|
88
88
|
defaultValue?: string | undefined,
|
|
@@ -119,7 +119,7 @@ class SecretContainer {
|
|
|
119
119
|
return `"${secretKeyOrValue}"`;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
printInFString(
|
|
122
|
+
public printInFString(
|
|
123
123
|
varName: string,
|
|
124
124
|
secretKeyOrValue: string | number | undefined | boolean,
|
|
125
125
|
defaultValue?: string | undefined,
|
|
@@ -171,7 +171,7 @@ class SecretContainer {
|
|
|
171
171
|
* f"db://sample:access_token@sample.com"
|
|
172
172
|
* ```
|
|
173
173
|
*/
|
|
174
|
-
printPassword(
|
|
174
|
+
public printPassword(
|
|
175
175
|
password: string | undefined,
|
|
176
176
|
passwordPlaceholder: string,
|
|
177
177
|
inFString: boolean,
|
|
@@ -187,11 +187,11 @@ class SecretContainer {
|
|
|
187
187
|
: printMethod(variableName || "password", passwordPlaceholder, password);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
getSecrets(): Record<string, string> {
|
|
190
|
+
public getSecrets(): Record<string, string> {
|
|
191
191
|
return this.secrets;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
formatSecrets(): string {
|
|
194
|
+
public formatSecrets(): string {
|
|
195
195
|
if (Object.keys(this.secrets).length === 0) {
|
|
196
196
|
return "";
|
|
197
197
|
}
|
|
@@ -203,11 +203,11 @@ class SecretContainer {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
class PostgresGenerator extends CodeGenerator<"postgres"> {
|
|
206
|
-
generateImports(): string[] {
|
|
206
|
+
public generateImports(): string[] {
|
|
207
207
|
return [];
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
generateConnectionCode(): string {
|
|
210
|
+
public generateConnectionCode(): string {
|
|
211
211
|
const ssl = this.connection.ssl
|
|
212
212
|
? ", connect_args={'sslmode': 'require'}"
|
|
213
213
|
: "";
|
|
@@ -235,11 +235,11 @@ class PostgresGenerator extends CodeGenerator<"postgres"> {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
class MySQLGenerator extends CodeGenerator<"mysql"> {
|
|
238
|
-
generateImports(): string[] {
|
|
238
|
+
public generateImports(): string[] {
|
|
239
239
|
return [];
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
-
generateConnectionCode(): string {
|
|
242
|
+
public generateConnectionCode(): string {
|
|
243
243
|
const ssl = this.connection.ssl
|
|
244
244
|
? ", connect_args={'ssl': {'ssl-mode': 'preferred'}}"
|
|
245
245
|
: "";
|
|
@@ -267,11 +267,11 @@ class MySQLGenerator extends CodeGenerator<"mysql"> {
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
class SQLiteGenerator extends CodeGenerator<"sqlite"> {
|
|
270
|
-
generateImports(): string[] {
|
|
270
|
+
public generateImports(): string[] {
|
|
271
271
|
return [];
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
generateConnectionCode(): string {
|
|
274
|
+
public generateConnectionCode(): string {
|
|
275
275
|
const database = this.connection.database
|
|
276
276
|
? this.secrets.printInFString("database", this.connection.database)
|
|
277
277
|
: "";
|
|
@@ -289,11 +289,11 @@ class SQLiteGenerator extends CodeGenerator<"sqlite"> {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
class SnowflakeGenerator extends CodeGenerator<"snowflake"> {
|
|
292
|
-
generateImports(): string[] {
|
|
292
|
+
public generateImports(): string[] {
|
|
293
293
|
return ["from snowflake.sqlalchemy import URL"];
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
-
generateConnectionCode(): string {
|
|
296
|
+
public generateConnectionCode(): string {
|
|
297
297
|
const { authType, account, database, warehouse, schema, role } =
|
|
298
298
|
this.connection;
|
|
299
299
|
const baseParams: Record<string, string | undefined> = {
|
|
@@ -422,11 +422,11 @@ class BigQueryGenerator extends CodeGenerator<"bigquery"> {
|
|
|
422
422
|
);
|
|
423
423
|
}
|
|
424
424
|
|
|
425
|
-
generateImports(): string[] {
|
|
425
|
+
public generateImports(): string[] {
|
|
426
426
|
return this.credential.kind === "path" ? [] : ["import json"];
|
|
427
427
|
}
|
|
428
428
|
|
|
429
|
-
generateConnectionCode(): string {
|
|
429
|
+
public generateConnectionCode(): string {
|
|
430
430
|
const project = this.secrets.printInFString(
|
|
431
431
|
"project",
|
|
432
432
|
this.connection.project,
|
|
@@ -451,11 +451,11 @@ class BigQueryGenerator extends CodeGenerator<"bigquery"> {
|
|
|
451
451
|
}
|
|
452
452
|
|
|
453
453
|
class DuckDBGenerator extends CodeGenerator<"duckdb"> {
|
|
454
|
-
generateImports(): string[] {
|
|
454
|
+
public generateImports(): string[] {
|
|
455
455
|
return [];
|
|
456
456
|
}
|
|
457
457
|
|
|
458
|
-
generateConnectionCode(): string {
|
|
458
|
+
public generateConnectionCode(): string {
|
|
459
459
|
const database = this.secrets.printInFString(
|
|
460
460
|
"database",
|
|
461
461
|
this.connection.database || ":memory:",
|
|
@@ -469,11 +469,11 @@ class DuckDBGenerator extends CodeGenerator<"duckdb"> {
|
|
|
469
469
|
}
|
|
470
470
|
|
|
471
471
|
class MotherDuckGenerator extends CodeGenerator<"motherduck"> {
|
|
472
|
-
generateImports(): string[] {
|
|
472
|
+
public generateImports(): string[] {
|
|
473
473
|
return [];
|
|
474
474
|
}
|
|
475
475
|
|
|
476
|
-
generateConnectionCode(): string {
|
|
476
|
+
public generateConnectionCode(): string {
|
|
477
477
|
const database = this.secrets.printInFString(
|
|
478
478
|
"database",
|
|
479
479
|
this.connection.database,
|
|
@@ -497,11 +497,11 @@ class MotherDuckGenerator extends CodeGenerator<"motherduck"> {
|
|
|
497
497
|
}
|
|
498
498
|
|
|
499
499
|
class ClickHouseGenerator extends CodeGenerator<"clickhouse_connect"> {
|
|
500
|
-
generateImports(): string[] {
|
|
500
|
+
public generateImports(): string[] {
|
|
501
501
|
return ["import clickhouse_connect"];
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
-
generateConnectionCode(): string {
|
|
504
|
+
public generateConnectionCode(): string {
|
|
505
505
|
const password = this.secrets.printPassword(
|
|
506
506
|
this.connection.password,
|
|
507
507
|
"CLICKHOUSE_PASSWORD",
|
|
@@ -530,11 +530,11 @@ ${formatUrlParams(params, (inner) => ` ${inner}`)},
|
|
|
530
530
|
}
|
|
531
531
|
|
|
532
532
|
class TimeplusGenerator extends CodeGenerator<"timeplus"> {
|
|
533
|
-
generateImports(): string[] {
|
|
533
|
+
public generateImports(): string[] {
|
|
534
534
|
return [];
|
|
535
535
|
}
|
|
536
536
|
|
|
537
|
-
generateConnectionCode(): string {
|
|
537
|
+
public generateConnectionCode(): string {
|
|
538
538
|
const password = this.secrets.printPassword(
|
|
539
539
|
this.connection.password,
|
|
540
540
|
"TIMEPLUS_PASSWORD",
|
|
@@ -555,11 +555,11 @@ class TimeplusGenerator extends CodeGenerator<"timeplus"> {
|
|
|
555
555
|
}
|
|
556
556
|
|
|
557
557
|
class ChDBGenerator extends CodeGenerator<"chdb"> {
|
|
558
|
-
generateImports(): string[] {
|
|
558
|
+
public generateImports(): string[] {
|
|
559
559
|
return ["import chdb"];
|
|
560
560
|
}
|
|
561
561
|
|
|
562
|
-
generateConnectionCode(): string {
|
|
562
|
+
public generateConnectionCode(): string {
|
|
563
563
|
const database =
|
|
564
564
|
this.secrets.print("database", this.connection.database) || '""';
|
|
565
565
|
|
|
@@ -570,13 +570,13 @@ class ChDBGenerator extends CodeGenerator<"chdb"> {
|
|
|
570
570
|
}
|
|
571
571
|
|
|
572
572
|
class TrinoGenerator extends CodeGenerator<"trino"> {
|
|
573
|
-
generateImports(): string[] {
|
|
573
|
+
public generateImports(): string[] {
|
|
574
574
|
return this.connection.async_support
|
|
575
575
|
? ["import aiotrino"]
|
|
576
576
|
: ["import trino.sqlalchemy"];
|
|
577
577
|
}
|
|
578
578
|
|
|
579
|
-
generateConnectionCode(): string {
|
|
579
|
+
public generateConnectionCode(): string {
|
|
580
580
|
const trinoExtension = this.connection.async_support ? "aiotrino" : "trino";
|
|
581
581
|
const schema = this.connection.schema ? `/${this.connection.schema}` : "";
|
|
582
582
|
|
|
@@ -614,7 +614,7 @@ class PyIcebergGenerator extends CodeGenerator<"iceberg"> {
|
|
|
614
614
|
);
|
|
615
615
|
}
|
|
616
616
|
|
|
617
|
-
generateImports(): string[] {
|
|
617
|
+
public generateImports(): string[] {
|
|
618
618
|
if (Object.keys(this.getCatalogOptions()).length === 0) {
|
|
619
619
|
return ["from pyiceberg.catalog import load_catalog"];
|
|
620
620
|
}
|
|
@@ -635,7 +635,7 @@ class PyIcebergGenerator extends CodeGenerator<"iceberg"> {
|
|
|
635
635
|
}
|
|
636
636
|
}
|
|
637
637
|
|
|
638
|
-
generateConnectionCode(): string {
|
|
638
|
+
public generateConnectionCode(): string {
|
|
639
639
|
const name = `"${this.connection.name}"`;
|
|
640
640
|
const options = this.getCatalogOptions();
|
|
641
641
|
if (Object.keys(options).length === 0) {
|
|
@@ -705,12 +705,12 @@ class PyIcebergGenerator extends CodeGenerator<"iceberg"> {
|
|
|
705
705
|
}
|
|
706
706
|
|
|
707
707
|
class DataFusionGenerator extends CodeGenerator<"datafusion"> {
|
|
708
|
-
generateImports(): string[] {
|
|
708
|
+
public generateImports(): string[] {
|
|
709
709
|
// To trigger installation of ibis-datafusion
|
|
710
710
|
return ["from datafusion import SessionContext"];
|
|
711
711
|
}
|
|
712
712
|
|
|
713
|
-
generateConnectionCode(): string {
|
|
713
|
+
public generateConnectionCode(): string {
|
|
714
714
|
if (this.connection.sessionContext) {
|
|
715
715
|
return dedent(`
|
|
716
716
|
ctx = SessionContext()
|
|
@@ -727,11 +727,11 @@ class DataFusionGenerator extends CodeGenerator<"datafusion"> {
|
|
|
727
727
|
}
|
|
728
728
|
|
|
729
729
|
class PySparkGenerator extends CodeGenerator<"pyspark"> {
|
|
730
|
-
generateImports(): string[] {
|
|
730
|
+
public generateImports(): string[] {
|
|
731
731
|
return ["from pyspark.sql import SparkSession"];
|
|
732
732
|
}
|
|
733
733
|
|
|
734
|
-
generateConnectionCode(): string {
|
|
734
|
+
public generateConnectionCode(): string {
|
|
735
735
|
if (this.connection.host || this.connection.port) {
|
|
736
736
|
const host = this.secrets.printInFString("host", this.connection.host);
|
|
737
737
|
const port = this.secrets.printInFString("port", this.connection.port);
|
|
@@ -747,11 +747,11 @@ class PySparkGenerator extends CodeGenerator<"pyspark"> {
|
|
|
747
747
|
}
|
|
748
748
|
|
|
749
749
|
class RedshiftGenerator extends CodeGenerator<"redshift"> {
|
|
750
|
-
generateImports(): string[] {
|
|
750
|
+
public generateImports(): string[] {
|
|
751
751
|
return ["import redshift_connector"];
|
|
752
752
|
}
|
|
753
753
|
|
|
754
|
-
generateConnectionCode(): string {
|
|
754
|
+
public generateConnectionCode(): string {
|
|
755
755
|
const host = this.secrets.print("host", this.connection.host);
|
|
756
756
|
const port = this.secrets.print("port", this.connection.port);
|
|
757
757
|
const database = this.secrets.print("database", this.connection.database);
|
|
@@ -819,11 +819,11 @@ ${formatUrlParams(params, (inner) => ` ${inner}`)},
|
|
|
819
819
|
}
|
|
820
820
|
|
|
821
821
|
class DatabricksGenerator extends CodeGenerator<"databricks"> {
|
|
822
|
-
generateImports(): string[] {
|
|
822
|
+
public generateImports(): string[] {
|
|
823
823
|
return [];
|
|
824
824
|
}
|
|
825
825
|
|
|
826
|
-
generateConnectionCode(): string {
|
|
826
|
+
public generateConnectionCode(): string {
|
|
827
827
|
const useFString = this.orm !== "ibis";
|
|
828
828
|
|
|
829
829
|
const accessToken = this.secrets.printPassword(
|
|
@@ -883,14 +883,14 @@ class DatabricksGenerator extends CodeGenerator<"databricks"> {
|
|
|
883
883
|
}
|
|
884
884
|
|
|
885
885
|
class SupabaseGenerator extends CodeGenerator<"supabase"> {
|
|
886
|
-
generateImports(): string[] {
|
|
886
|
+
public generateImports(): string[] {
|
|
887
887
|
if (this.connection.disable_client_pooling) {
|
|
888
888
|
return ["from sqlalchemy.pool import NullPool"];
|
|
889
889
|
}
|
|
890
890
|
return [];
|
|
891
891
|
}
|
|
892
892
|
|
|
893
|
-
generateConnectionCode(): string {
|
|
893
|
+
public generateConnectionCode(): string {
|
|
894
894
|
const password = this.secrets.printPassword(
|
|
895
895
|
this.connection.password,
|
|
896
896
|
"SUPABASE_PASSWORD",
|
|
@@ -921,7 +921,7 @@ class SupabaseGenerator extends CodeGenerator<"supabase"> {
|
|
|
921
921
|
class CodeGeneratorFactory {
|
|
922
922
|
public secrets = new SecretContainer();
|
|
923
923
|
|
|
924
|
-
createGenerator(
|
|
924
|
+
public createGenerator(
|
|
925
925
|
connection: DatabaseConnection,
|
|
926
926
|
orm: ConnectionLibrary,
|
|
927
927
|
): CodeGenerator<DatabaseConnection["type"]> {
|
|
@@ -26,14 +26,14 @@ export const StorageLibraryDisplayNames: Record<StorageLibrary, string> = {
|
|
|
26
26
|
class SecretContainer {
|
|
27
27
|
private secrets: Record<string, string> = {};
|
|
28
28
|
|
|
29
|
-
get imports(): Set<string> {
|
|
29
|
+
public get imports(): Set<string> {
|
|
30
30
|
if (Object.keys(this.secrets).length === 0) {
|
|
31
31
|
return new Set<string>();
|
|
32
32
|
}
|
|
33
33
|
return new Set<string>(["import os"]);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
print(varName: string, value: string | undefined): string {
|
|
36
|
+
public print(varName: string, value: string | undefined): string {
|
|
37
37
|
if (value === undefined || value === "") {
|
|
38
38
|
return "";
|
|
39
39
|
}
|
|
@@ -46,7 +46,7 @@ class SecretContainer {
|
|
|
46
46
|
return `"${escapePythonString(value)}"`;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
formatSecrets(): string {
|
|
49
|
+
public formatSecrets(): string {
|
|
50
50
|
if (Object.keys(this.secrets).length === 0) {
|
|
51
51
|
return "";
|
|
52
52
|
}
|