@marimo-team/frontend 0.16.1 → 0.16.3
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-2wVcyvDj.js → ConnectedDataExplorerComponent-Brtw1DxF.js} +1 -1
- package/dist/assets/{ImageComparisonComponent-D2j6i0hv.js → ImageComparisonComponent-Dxl-PbZX.js} +1 -1
- package/dist/assets/{VegaLite-BckFaf2D.js → VegaLite-BXQF0Cx_.js} +1 -1
- package/dist/assets/_baseEach-BjSm9ht3.js +1 -0
- package/dist/assets/_baseMap-CV4Ezmtf.js +1 -0
- package/dist/assets/_baseUniq-Ci9yZGxz.js +1 -0
- package/dist/assets/{_createAggregator-C5CVY-0t.js → _createAggregator-VFK9K2d9.js} +1 -1
- package/dist/assets/{agent-panel-RGLNjkYe.js → agent-panel-BoscVLCT.js} +7 -7
- package/dist/assets/{any-language-editor-DjuXwGCA.js → any-language-editor-ChaY_VUU.js} +1 -1
- package/dist/assets/{architectureDiagram-W76B3OCA-Dyj4ds_R.js → architectureDiagram-W76B3OCA-CueUUFYd.js} +1 -1
- package/dist/assets/{between-horizontal-start-Dt2aKpPf.js → between-horizontal-start-DAHqmLYT.js} +1 -1
- package/dist/assets/{blockDiagram-QIGZ2CNN-o-i7DDvN.js → blockDiagram-QIGZ2CNN-BYYygyWn.js} +1 -1
- package/dist/assets/{c4Diagram-FPNF74CW-DGHEwWrx.js → c4Diagram-FPNF74CW-DAz3xEh1.js} +1 -1
- package/dist/assets/channel-6SqQ2U_X.js +1 -0
- package/dist/assets/chat-panel-DJkOLrw9.js +3 -0
- package/dist/assets/{chunk-4BX2VUAB-BJecb-Ri.js → chunk-4BX2VUAB-8g-RyHdt.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-CAATkc4w.js → chunk-55IACEB6-iWZZ8Mt6.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-DPuNbQ-f.js → chunk-FMBD7UC4-knjss4wk.js} +1 -1
- package/dist/assets/{chunk-K7UQS3LO-C8TWVLiH.js → chunk-K7UQS3LO-DVIwPBgZ.js} +1 -1
- package/dist/assets/{chunk-QN33PNHL-DiZZ09q4.js → chunk-QN33PNHL-CBU8pN6I.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-BIUM7usu.js → chunk-QZHKN3VN-5ljElUF4.js} +1 -1
- package/dist/assets/{chunk-TVAH2DTR-vGTArPBG.js → chunk-TVAH2DTR-DkIdGINc.js} +1 -1
- package/dist/assets/{chunk-TZMSLE5B-D2KRqp_x.js → chunk-TZMSLE5B-CIFOSTqh.js} +1 -1
- package/dist/assets/{circle-play-cjeNez0N.js → circle-play-BOdsbq5u.js} +1 -1
- package/dist/assets/classDiagram-KNZD7YFC-DVqXcTYf.js +1 -0
- package/dist/assets/classDiagram-v2-RKCZMP56-DVqXcTYf.js +1 -0
- package/dist/assets/{clear-button-C97JtAez.js → clear-button-GAjXl0CQ.js} +1 -1
- package/dist/assets/clone-DSDb0xen.js +1 -0
- package/dist/assets/command-palette-BUXkqoLh.js +1 -0
- package/dist/assets/{common-Du9rSOwD.js → common-DahoYqdi.js} +1 -1
- package/dist/assets/{compile-CZXqyOxa.js → compile-Bg8uJ7vm.js} +1 -1
- package/dist/assets/{cose-bilkent-S5V4N54A-CqUN5Y9b.js → cose-bilkent-S5V4N54A-z_0gqD9K.js} +1 -1
- package/dist/assets/{dagre-5GWH7T2D-RJqTI9DM.js → dagre-5GWH7T2D-BMt7CNXL.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-DZN0q1LV.js → data-grid-overlay-editor-Ctn4XtXx.js} +1 -1
- package/dist/assets/datasources-panel-C7sqRIHs.js +1 -0
- package/dist/assets/{dependency-graph-panel-CEog_O7V.js → dependency-graph-panel-DNajptzv.js} +4 -4
- package/dist/assets/{diagram-N5W7TBWH-D-l4zZ9d.js → diagram-N5W7TBWH-BzwvLvAy.js} +1 -1
- package/dist/assets/{diagram-QEK2KX5R-CCOmBUt-.js → diagram-QEK2KX5R-DRLJ56FS.js} +1 -1
- package/dist/assets/{diagram-S2PKOQOG-C_I_9jnZ.js → diagram-S2PKOQOG-Bf8x4KTU.js} +1 -1
- package/dist/assets/{documentation-panel-C1BtMZ3M.js → documentation-panel-Dm6Ozl67.js} +1 -1
- package/dist/assets/{edit-page-B-oevUZ9.js → edit-page-CGc9EjuG.js} +53 -42
- package/dist/assets/{ellipsis-vertical-BEb-J8z6.js → ellipsis-vertical-Bj1YXvZe.js} +1 -1
- package/dist/assets/{empty-state-C99UyDE3.js → empty-state-CYev-D31.js} +1 -1
- package/dist/assets/{erDiagram-AWTI2OKA-BePOLi5M.js → erDiagram-AWTI2OKA-DmgzgN_I.js} +1 -1
- package/dist/assets/{error-panel-Bs34jXFh.js → error-panel-BYG4twCa.js} +1 -1
- package/dist/assets/{file-explorer-panel-Ck6UL861.js → file-explorer-panel-BSMiOApi.js} +1 -1
- package/dist/assets/{flowDiagram-PVAE7QVJ-BgjFu5l7.js → flowDiagram-PVAE7QVJ-BdRKkajr.js} +1 -1
- package/dist/assets/{ganttDiagram-OWAHRB6G-YOPb3XSV.js → ganttDiagram-OWAHRB6G-lfRAMnq_.js} +5 -5
- package/dist/assets/{gitGraphDiagram-NY62KEGX-CGhqaDTy.js → gitGraphDiagram-NY62KEGX-CQVTIrHF.js} +1 -1
- package/dist/assets/{glide-data-editor-9QUH6iso.js → glide-data-editor-D5A4pou7.js} +4 -4
- package/dist/assets/{graph-DQQFGrho.js → graph-CBNo279v.js} +1 -1
- package/dist/assets/{home-page-DRKpPCrF.js → home-page-CmdznBJR.js} +2 -2
- package/dist/assets/{index-SGLNXrGP.js → index-0dfGh-Gj.js} +1 -1
- package/dist/assets/{index-aE43R74q.js → index-BDYVSSzB.js} +1 -1
- package/dist/assets/{index-BJNCMUmG.js → index-B_KyDZ94.js} +1 -1
- package/dist/assets/{index-BjgnbONl.js → index-Bfy-I_lW.js} +1 -1
- package/dist/assets/{index-CUFv_thQ.js → index-Bh98Tp-z.js} +1 -1
- package/dist/assets/{index-C2MD0vgD.js → index-BhroIwBL.js} +1 -1
- package/dist/assets/{index-DdnKZNxM.js → index-BtQtesaI.js} +1 -1
- package/dist/assets/index-C0iXCvyY.css +1 -0
- package/dist/assets/index-C1SHFMCp.js +581 -0
- package/dist/assets/{index-C_tkBKNO.js → index-C6DWtSls.js} +1 -1
- package/dist/assets/{index-Aeo6WiK7.js → index-C71cdkH-.js} +1 -1
- package/dist/assets/{index-G5QZppK2.js → index-CT_FTqvK.js} +1 -1
- package/dist/assets/{index-B8jXZ12t.js → index-CU5rRr66.js} +1 -1
- package/dist/assets/{index-BAbIIxHU.js → index-Cb6duXQm.js} +1 -1
- package/dist/assets/{index-BW3k9Gss.js → index-D23e9zQj.js} +1 -1
- package/dist/assets/index-DUGecC2Z.js +68 -0
- package/dist/assets/{index-CFKO7WXI.js → index-DcGIOAQi.js} +1 -1
- package/dist/assets/{index-ClzeQrN7.js → index-PJfa9qXY.js} +1 -1
- package/dist/assets/{index-C1ez98sk.js → index-SPslPC2B.js} +1 -1
- package/dist/assets/{index-BprjMYH5.js → index-VPQlo4Uz.js} +1 -1
- package/dist/assets/{index-CfaDbEdi.js → index-qbTLKWyG.js} +1 -1
- package/dist/assets/infoDiagram-STP46IZ2-DBu8p9gd.js +2 -0
- package/dist/assets/{isEmpty-D-4c7sMv.js → isEmpty-CnOLuQIv.js} +1 -1
- package/dist/assets/{journeyDiagram-BIP6EPQ6-C94u3Mv3.js → journeyDiagram-BIP6EPQ6-6U_vHJBH.js} +1 -1
- package/dist/assets/{kanban-definition-6OIFK2YF-BEXYFzz7.js → kanban-definition-6OIFK2YF-DgnR14ys.js} +1 -1
- package/dist/assets/{layout-Bz2BJ2ru.js → layout-RHmq4fP9.js} +1 -1
- package/dist/assets/{linear-D8s7K76e.js → linear-CLdOVPGV.js} +1 -1
- package/dist/assets/links-Dd1icsEk.js +7 -0
- package/dist/assets/{logs-panel-DC7wpmPz.js → logs-panel-CjbuhBLx.js} +1 -1
- package/dist/assets/{markdown-renderer-DRdSWR9X.js → markdown-renderer-X5YJvAZq.js} +3 -3
- package/dist/assets/{mermaid-Y3x4hmD0.js → mermaid-Bl2T5oEC.js} +1 -1
- package/dist/assets/{mermaid.core-DzthE35Y.js → mermaid.core-CfukBvGI.js} +4 -4
- package/dist/assets/min-BXIes1Za.js +1 -0
- package/dist/assets/{mindmap-definition-Q6HEUPPD-DktvuLe1.js → mindmap-definition-Q6HEUPPD-BXCjP4Lu.js} +1 -1
- package/dist/assets/{number-overlay-editor-BEfwI1IT.js → number-overlay-editor-BUyqkSes.js} +1 -1
- package/dist/assets/{outline-panel-CdsnAy2w.js → outline-panel-BvGcPKdd.js} +1 -1
- package/dist/assets/{packages-panel-DiTA-d_D.js → packages-panel-BichDQWG.js} +1 -1
- package/dist/assets/{pieDiagram-ADFJNKIX-DQDNQ-de.js → pieDiagram-ADFJNKIX-CMzJFIJM.js} +1 -1
- package/dist/assets/{quadrantDiagram-LMRXKWRM-0kgIXc2-.js → quadrantDiagram-LMRXKWRM-CfGssUlO.js} +1 -1
- package/dist/assets/{react-plotly-DJqqfM7c.js → react-plotly-DR3hV0HW.js} +1 -1
- package/dist/assets/{requirementDiagram-4UW4RH46-B5rb0ypd.js → requirementDiagram-4UW4RH46-CfrFolth.js} +1 -1
- package/dist/assets/{run-page-CFmLrv1R.js → run-page-Bqd_4ePD.js} +1 -1
- package/dist/assets/{sankeyDiagram-GR3RE2ED-Dom7IlnF.js → sankeyDiagram-GR3RE2ED-D_UttKU0.js} +1 -1
- package/dist/assets/{scratchpad-panel-CuHWpHO8.js → scratchpad-panel-D5N15ji1.js} +1 -1
- package/dist/assets/secrets-panel-BpbnAO4R.js +1 -0
- package/dist/assets/{sequenceDiagram-C3RYC4MD-PNJWXQbw.js → sequenceDiagram-C3RYC4MD-MdfQQApP.js} +1 -1
- package/dist/assets/{slides-component-CJgaTRZ0.js → slides-component-C0z7rXmk.js} +1 -1
- package/dist/assets/{snippets-panel-B2EC1txM.js → snippets-panel-wlpZ_Wzx.js} +1 -1
- package/dist/assets/sortBy-BW_zNHP6.js +1 -0
- package/dist/assets/{state-CWict9RU.js → state-CDooX-dk.js} +1 -1
- package/dist/assets/{stateDiagram-KXAO66HF-BE58aJnr.js → stateDiagram-KXAO66HF-H7kfw3ot.js} +1 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-YMeb9qMR.js +1 -0
- package/dist/assets/{storage-DRaR04wR.js → storage-b1QCapTq.js} +6 -6
- package/dist/assets/{terminal-BX3Su5q7.js → terminal-CPV44BXz.js} +1 -1
- package/dist/assets/{time-hUzZfpNE.js → time-DDy3xv5Y.js} +1 -1
- package/dist/assets/{timeline-definition-XQNQX7LJ-CqQP9t51.js → timeline-definition-XQNQX7LJ-J-cPRT2_.js} +1 -1
- package/dist/assets/{tracing-B10Q1n-L.js → tracing-3eHHRUiJ.js} +2 -2
- package/dist/assets/{tracing-panel-Du8WCnno.js → tracing-panel-BMgy3D7d.js} +2 -2
- package/dist/assets/{trash-B81GTiv6.js → trash--tonOuDe.js} +1 -1
- package/dist/assets/{tree-6vW2ogkh.js → tree-ouIGEsVg.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-CdwDwwsz.js → treemap-75Q7IDZK-CzJTJ_3R.js} +20 -20
- package/dist/assets/{variable-panel-D5qgJI7k.js → variable-panel-sFTn4Oih.js} +1 -1
- package/dist/assets/{vega-component-DJaJWMJM.js → vega-component-BkPkzX9r.js} +1 -1
- package/dist/assets/{xychartDiagram-6GGTOJPD-WFtXqaM9.js → xychartDiagram-6GGTOJPD-BZ8WOb_8.js} +1 -1
- package/dist/index.html +10 -3
- package/package.json +8 -8
- package/src/__mocks__/common.ts +5 -3
- package/src/__mocks__/notebook.ts +2 -2
- package/src/__mocks__/requests.ts +1 -0
- package/src/__tests__/main.test.tsx +2 -2
- package/src/components/ai/ai-provider-icon.tsx +2 -0
- package/src/components/app-config/ai-config.tsx +32 -1
- package/src/components/app-config/common.tsx +2 -2
- package/src/components/app-config/user-config-form.tsx +26 -0
- package/src/components/audio/audio-recorder.tsx +0 -1
- package/src/components/chat/acp/blocks.tsx +2 -2
- package/src/components/chat/acp/thread.tsx +3 -5
- package/src/components/chat/acp/utils.ts +5 -5
- package/src/components/chat/chat-panel.tsx +1 -1
- package/src/components/data-table/__tests__/columns.test.tsx +38 -0
- package/src/components/data-table/__tests__/data-table.test.tsx +2 -2
- package/src/components/data-table/cell-hover-template/feature.ts +1 -1
- package/src/components/data-table/cell-hover-template/types.ts +1 -1
- package/src/components/data-table/charts/__tests__/altair-generator.test.ts +1 -1
- package/src/components/data-table/charts/chart-spec/tooltips.ts +3 -3
- package/src/components/data-table/charts/components/chart-items.tsx +1 -1
- package/src/components/data-table/charts/components/form-fields.tsx +2 -2
- package/src/components/data-table/charts/constants.ts +1 -1
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
- package/src/components/data-table/column-summary/chart-spec-model.tsx +2 -2
- package/src/components/data-table/columns.tsx +22 -3
- package/src/components/data-table/data-table.tsx +35 -3
- package/src/components/data-table/date-popover.tsx +1 -1
- package/src/components/data-table/download-actions.tsx +1 -1
- package/src/components/data-table/range-focus/__tests__/utils.test.ts +5 -5
- package/src/components/data-table/renderers.tsx +22 -13
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +1 -1
- package/src/components/data-table/schemas.ts +16 -0
- package/src/components/data-table/types.ts +4 -3
- package/src/components/datasources/column-preview.tsx +9 -6
- package/src/components/debugger/debugger-code.tsx +1 -1
- package/src/components/dependency-graph/custom-node.tsx +15 -6
- package/src/components/dependency-graph/dependency-graph-minimap.tsx +2 -2
- package/src/components/dependency-graph/dependency-graph-tree.tsx +2 -2
- package/src/components/dependency-graph/dependency-graph.tsx +1 -1
- package/src/components/dependency-graph/elements.ts +7 -7
- package/src/components/dependency-graph/utils/changes.ts +4 -4
- package/src/components/editor/Cell.tsx +7 -1
- package/src/components/editor/ai/transport/chat-transport.tsx +1 -1
- package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +1 -1
- package/src/components/editor/chrome/panels/packages-panel.tsx +1 -1
- package/src/components/editor/columns/storage.ts +1 -1
- package/src/components/editor/database/__tests__/__snapshots__/as-code.test.ts.snap +36 -0
- package/src/components/editor/database/__tests__/as-code.test.ts +30 -7
- package/src/components/editor/database/add-database-form.tsx +11 -0
- package/src/components/editor/database/as-code.ts +104 -5
- package/src/components/editor/database/schemas.ts +36 -18
- package/src/components/editor/errors/auto-fix.tsx +12 -2
- package/src/components/editor/errors/sql-validation-errors.tsx +40 -0
- package/src/components/editor/navigation/clipboard.ts +2 -2
- package/src/components/editor/output/ConsoleOutput.tsx +14 -2
- package/src/components/editor/output/JsonOutput.tsx +1 -1
- package/src/components/editor/output/MarimoErrorOutput.tsx +60 -1
- package/src/components/editor/output/MarimoTracebackOutput.tsx +17 -2
- package/src/components/editor/renderers/grid-layout/types.ts +2 -2
- package/src/components/editor/renderers/plugins.ts +1 -1
- package/src/components/editor/renderers/types.ts +1 -1
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +7 -7
- package/src/components/forms/form.tsx +5 -5
- package/src/components/ui/links.tsx +1 -0
- package/src/core/ai/__tests__/model-registry.test.ts +0 -10
- package/src/core/ai/context/providers/cell-output.ts +1 -18
- package/src/core/ai/context/providers/error.ts +2 -2
- package/src/core/ai/ids/ids.ts +1 -0
- package/src/core/ai/model-registry.ts +2 -1
- package/src/core/cells/cells.ts +5 -5
- package/src/core/cells/logs.ts +1 -1
- package/src/core/cells/types.ts +1 -1
- package/src/core/codemirror/__tests__/format.test.ts +6 -0
- package/src/core/codemirror/cells/traceback-decorations.ts +1 -1
- package/src/core/codemirror/editing/commands.ts +2 -2
- package/src/core/codemirror/find-replace/navigate.ts +1 -1
- package/src/core/codemirror/language/__tests__/extension.test.ts +24 -0
- package/src/core/codemirror/language/__tests__/sql-validation.test.ts +133 -0
- package/src/core/codemirror/language/__tests__/sql.test.ts +764 -79
- package/src/core/codemirror/language/languages/markdown.ts +4 -1
- package/src/core/codemirror/language/languages/sql/banner-validation-errors.ts +85 -0
- package/src/core/codemirror/language/languages/sql/completion-builder.ts +160 -0
- package/src/core/codemirror/language/languages/sql/completion-sources.tsx +9 -3
- package/src/core/codemirror/language/languages/sql/completion-store.ts +46 -50
- package/src/core/codemirror/language/languages/sql/renderers.tsx +485 -0
- package/src/core/codemirror/language/languages/sql/sql-mode.ts +20 -0
- package/src/core/codemirror/language/languages/sql/sql.ts +218 -4
- package/src/core/codemirror/language/languages/sql/utils.ts +4 -1
- package/src/core/codemirror/language/panel/panel.tsx +8 -2
- package/src/core/codemirror/language/panel/sql.tsx +86 -4
- package/src/core/codemirror/language/utils/ast.ts +3 -3
- package/src/core/codemirror/lsp/federated-lsp.ts +4 -4
- package/src/core/codemirror/lsp/lens.ts +4 -4
- package/src/core/codemirror/lsp/notebook-lsp.ts +1 -1
- package/src/core/codemirror/lsp/types.ts +1 -1
- package/src/core/codemirror/markdown/completions.ts +1 -1
- package/src/core/codemirror/reactive-references/analyzer.ts +2 -2
- package/src/core/codemirror/rtc/loro/awareness.ts +1 -1
- package/src/core/config/config-schema.ts +1 -0
- package/src/core/config/feature-flag.tsx +6 -2
- package/src/core/datasets/request-registry.ts +24 -1
- package/src/core/dom/events.ts +1 -1
- package/src/core/dom/outline.ts +2 -2
- package/src/core/dom/uiregistry.ts +2 -8
- package/src/core/errors/__tests__/errors.test.ts +22 -4
- package/src/core/errors/errors.ts +29 -1
- package/src/core/errors/state.ts +1 -1
- package/src/core/islands/bridge.ts +1 -0
- package/src/core/islands/main.ts +3 -2
- package/src/core/islands/parse.ts +1 -3
- package/src/core/kernel/messages.ts +2 -1
- package/src/core/network/CachingRequestRegistry.ts +74 -0
- package/src/core/network/DeferredRequestRegistry.ts +3 -1
- package/src/core/network/__tests__/CachingRequestRegistry.test.ts +73 -0
- package/src/core/network/requests-network.ts +7 -0
- package/src/core/network/requests-static.ts +1 -0
- package/src/core/network/requests-toasting.ts +1 -0
- package/src/core/network/types.ts +3 -1
- package/src/core/variables/state.ts +2 -2
- package/src/core/wasm/__tests__/state.test.ts +1 -1
- package/src/core/wasm/bridge.ts +5 -0
- package/src/core/websocket/useMarimoWebSocket.tsx +9 -2
- package/src/custom.d.ts +1 -1
- package/src/hooks/useCellRenderCount.ts +1 -0
- package/src/hooks/useResizeHandle.ts +4 -1
- package/src/plugins/core/RenderHTML.tsx +1 -2
- package/src/plugins/core/registerReactComponent.tsx +23 -19
- package/src/plugins/impl/DataTablePlugin.tsx +18 -6
- package/src/plugins/impl/FileUploadPlugin.tsx +1 -1
- package/src/plugins/impl/RefreshPlugin.tsx +1 -1
- package/src/plugins/impl/SliderPlugin.tsx +4 -0
- package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +27 -9
- package/src/plugins/impl/anywidget/__tests__/AnyWidgetPlugin.test.tsx +58 -2
- package/src/plugins/impl/anywidget/__tests__/model.test.ts +3 -4
- package/src/plugins/impl/anywidget/model.ts +2 -3
- package/src/plugins/impl/data-editor/types.ts +1 -1
- package/src/plugins/impl/data-explorer/components/query-form.tsx +1 -1
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +17 -5
- package/src/plugins/impl/data-frames/types.ts +1 -1
- package/src/plugins/impl/panel/PanelPlugin.tsx +2 -2
- package/src/plugins/impl/plotly/PlotlyPlugin.tsx +3 -3
- package/src/plugins/impl/vega/__tests__/loader.test.ts +2 -2
- package/src/plugins/impl/vega/loader.ts +1 -1
- package/src/plugins/impl/vega/vega-component.tsx +1 -1
- package/src/plugins/impl/vega/vega-loader.ts +2 -2
- package/src/plugins/layout/NavigationMenuPlugin.tsx +1 -1
- package/src/plugins/layout/RoutesPlugin.tsx +1 -2
- package/src/plugins/plugins.ts +2 -2
- package/src/stories/dataframe.stories.tsx +2 -0
- package/src/utils/Logger.ts +1 -1
- package/src/utils/__tests__/data-views.test.ts +30 -68
- package/src/utils/__tests__/dom.test.ts +167 -0
- package/src/utils/__tests__/id-tree.test.ts +49 -1
- package/src/utils/__tests__/storage.test.ts +1 -1
- package/src/utils/__tests__/traceback.test.ts +13 -2
- package/src/utils/arrays.ts +1 -1
- package/src/utils/createReducer.ts +1 -5
- package/src/utils/data-views.ts +6 -19
- package/src/utils/dom.ts +55 -0
- package/src/utils/edit-distance.ts +1 -1
- package/src/utils/fileToBase64.ts +1 -1
- package/src/utils/id-tree.tsx +20 -18
- package/src/utils/json/base64.ts +13 -0
- package/src/utils/json/json-parser.ts +2 -2
- package/src/utils/lru.ts +4 -0
- package/src/utils/mergeRefs.ts +1 -1
- package/src/utils/objects.ts +3 -3
- package/src/utils/pluralize.ts +1 -1
- package/src/utils/routes.ts +2 -2
- package/src/utils/sets.ts +1 -1
- package/src/utils/traceback.ts +45 -15
- package/src/utils/tracer.ts +11 -9
- package/dist/assets/_baseEach-CvTX9w0Y.js +0 -1
- package/dist/assets/_baseMap-CtlwA90f.js +0 -1
- package/dist/assets/_baseUniq-BKktIGQ1.js +0 -1
- package/dist/assets/channel-Co6iMgWq.js +0 -1
- package/dist/assets/chat-panel-9alr8FS4.js +0 -3
- package/dist/assets/classDiagram-KNZD7YFC-BbJ0rY3y.js +0 -1
- package/dist/assets/classDiagram-v2-RKCZMP56-BbJ0rY3y.js +0 -1
- package/dist/assets/clone-BMP0PsTa.js +0 -1
- package/dist/assets/command-palette-B93Pjcky.js +0 -1
- package/dist/assets/datasources-panel-v7H3cR0p.js +0 -1
- package/dist/assets/index-2252nrk6.js +0 -68
- package/dist/assets/index-C7CoaNFb.js +0 -578
- package/dist/assets/index-DadI618h.css +0 -1
- package/dist/assets/infoDiagram-STP46IZ2-CJLOpSAf.js +0 -2
- package/dist/assets/links-BpXlz1GG.js +0 -7
- package/dist/assets/min-BBO3-1Hg.js +0 -1
- package/dist/assets/secrets-panel-CfHc5YD0.js +0 -1
- package/dist/assets/sortBy-DZnlX29-.js +0 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-CdThjimL.js +0 -1
- package/src/__tests__/lru.test.ts +0 -74
|
@@ -80,6 +80,7 @@ import { useDeleteCellCallback } from "./cell/useDeleteCell";
|
|
|
80
80
|
import { useRunCell } from "./cell/useRunCells";
|
|
81
81
|
import { HideCodeButton } from "./code/readonly-python-code";
|
|
82
82
|
import { cellDomProps } from "./common";
|
|
83
|
+
import { SqlValidationErrorBanner } from "./errors/sql-validation-errors";
|
|
83
84
|
import { useCellNavigationProps } from "./navigation/navigation";
|
|
84
85
|
import {
|
|
85
86
|
useTemporarilyShownCode,
|
|
@@ -450,6 +451,7 @@ const EditableCellComponent = ({
|
|
|
450
451
|
});
|
|
451
452
|
const canCollapse = canCollapseOutline(cellRuntime.outline);
|
|
452
453
|
const hasOutput = !isOutputEmpty(cellRuntime.output);
|
|
454
|
+
const isStaleCell = outputIsStale(cellRuntime, cellData.edited);
|
|
453
455
|
const hasConsoleOutput = cellRuntime.consoleOutputs.length > 0;
|
|
454
456
|
const cellOutput = userConfig.display.cell_output;
|
|
455
457
|
|
|
@@ -510,7 +512,7 @@ const EditableCellComponent = ({
|
|
|
510
512
|
className="output-area"
|
|
511
513
|
cellId={cellId}
|
|
512
514
|
output={cellRuntime.output}
|
|
513
|
-
stale={
|
|
515
|
+
stale={isStaleCell}
|
|
514
516
|
loading={outputIsLoading(cellRuntime.status)}
|
|
515
517
|
/>
|
|
516
518
|
{isMarkdownCodeHidden &&
|
|
@@ -653,6 +655,10 @@ const EditableCellComponent = ({
|
|
|
653
655
|
)}
|
|
654
656
|
</div>
|
|
655
657
|
</div>
|
|
658
|
+
<SqlValidationErrorBanner
|
|
659
|
+
cellId={cellId}
|
|
660
|
+
hide={cellRuntime.errored && !isStaleCell}
|
|
661
|
+
/>
|
|
656
662
|
{cellOutput === "below" && outputArea}
|
|
657
663
|
{cellRuntime.serialization && (
|
|
658
664
|
<div className="py-1 px-2 flex items-center justify-end gap-2 last:rounded-b">
|
|
@@ -16,7 +16,7 @@ export class StreamingChunkTransport<
|
|
|
16
16
|
private onChunkReceived: (chunk: UIMessageChunk) => void;
|
|
17
17
|
|
|
18
18
|
constructor(
|
|
19
|
-
options: HttpChatTransportInitOptions<UI_MESSAGE
|
|
19
|
+
options: HttpChatTransportInitOptions<UI_MESSAGE>,
|
|
20
20
|
onChunkReceived: (chunk: UIMessageChunk) => void,
|
|
21
21
|
) {
|
|
22
22
|
super(options);
|
|
@@ -18,7 +18,7 @@ function getRootScrollableElement() {
|
|
|
18
18
|
* React hook to find the active header in the outline
|
|
19
19
|
*/
|
|
20
20
|
export function useActiveOutline(
|
|
21
|
-
headerElements:
|
|
21
|
+
headerElements: (readonly [HTMLElement, string])[],
|
|
22
22
|
) {
|
|
23
23
|
const [activeHeaderId, setActiveHeaderId] = useState<string | undefined>(
|
|
24
24
|
undefined,
|
|
@@ -300,7 +300,7 @@ const InstallPackageForm: React.FC<{
|
|
|
300
300
|
|
|
301
301
|
const PackagesList: React.FC<{
|
|
302
302
|
onSuccess: () => void;
|
|
303
|
-
packages:
|
|
303
|
+
packages: { name: string; version: string }[];
|
|
304
304
|
}> = ({ onSuccess, packages }) => {
|
|
305
305
|
if (packages.length === 0) {
|
|
306
306
|
return (
|
|
@@ -7,7 +7,7 @@ import { NotebookScopedLocalStorage } from "@/utils/localStorage";
|
|
|
7
7
|
const BASE_KEY = "marimo:notebook-col-sizes";
|
|
8
8
|
|
|
9
9
|
interface ColumnSizes {
|
|
10
|
-
widths:
|
|
10
|
+
widths: (number | "contentWidth")[];
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
function initialState(): ColumnSizes {
|
|
@@ -28,6 +28,42 @@ engine = clickhouse_connect.get_client(
|
|
|
28
28
|
)"
|
|
29
29
|
`;
|
|
30
30
|
|
|
31
|
+
exports[`generateDatabaseCode > basic connections > databricks 1`] = `
|
|
32
|
+
"import os
|
|
33
|
+
import sqlalchemy
|
|
34
|
+
|
|
35
|
+
_access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "my_access_token")
|
|
36
|
+
_server_hostname = os.environ.get("DATABRICKS_SERVER_HOSTNAME", "localhost")
|
|
37
|
+
_http_path = os.environ.get("DATABRICKS_HTTP_PATH", "http://localhost:8080")
|
|
38
|
+
DATABASE_URL = f"databricks://token:{_access_token}@{_server_hostname}?http_path={_http_path}"
|
|
39
|
+
engine = sqlalchemy.create_engine(DATABASE_URL)"
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
exports[`generateDatabaseCode > basic connections > databricks with catalog and schema 1`] = `
|
|
43
|
+
"import os
|
|
44
|
+
import sqlalchemy
|
|
45
|
+
|
|
46
|
+
_access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "my_access_token")
|
|
47
|
+
_server_hostname = os.environ.get("DATABRICKS_SERVER_HOSTNAME", "localhost")
|
|
48
|
+
_http_path = os.environ.get("DATABRICKS_HTTP_PATH", "http://localhost:8080")
|
|
49
|
+
DATABASE_URL = f"databricks://token:{_access_token}@{_server_hostname}?http_path={_http_path}&catalog=my_catalog&schema=my_schema"
|
|
50
|
+
engine = sqlalchemy.create_engine(DATABASE_URL)"
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
exports[`generateDatabaseCode > basic connections > databricks with ibis 1`] = `
|
|
54
|
+
"import ibis
|
|
55
|
+
import os
|
|
56
|
+
|
|
57
|
+
_access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "my_access_token")
|
|
58
|
+
_server_hostname = os.environ.get("DATABRICKS_SERVER_HOSTNAME", "localhost")
|
|
59
|
+
_http_path = os.environ.get("DATABRICKS_HTTP_PATH", "http://localhost:8080")
|
|
60
|
+
engine = ibis.databricks.connect(
|
|
61
|
+
server_hostname=_server_hostname,
|
|
62
|
+
http_path=_http_path,
|
|
63
|
+
access_token=_access_token
|
|
64
|
+
)"
|
|
65
|
+
`;
|
|
66
|
+
|
|
31
67
|
exports[`generateDatabaseCode > basic connections > datafusion 1`] = `
|
|
32
68
|
"from datafusion import SessionContext
|
|
33
69
|
import ibis
|
|
@@ -192,8 +192,24 @@ describe("generateDatabaseCode", () => {
|
|
|
192
192
|
},
|
|
193
193
|
};
|
|
194
194
|
|
|
195
|
+
const databricksConnection: DatabaseConnection = {
|
|
196
|
+
type: "databricks",
|
|
197
|
+
access_token: "my_access_token",
|
|
198
|
+
server_hostname: "localhost",
|
|
199
|
+
http_path: "http://localhost:8080",
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const databricksWithCatalogSchema: DatabaseConnection = {
|
|
203
|
+
type: "databricks",
|
|
204
|
+
access_token: "my_access_token",
|
|
205
|
+
server_hostname: "localhost",
|
|
206
|
+
http_path: "http://localhost:8080",
|
|
207
|
+
catalog: "my_catalog",
|
|
208
|
+
schema: "my_schema",
|
|
209
|
+
};
|
|
210
|
+
|
|
195
211
|
describe("basic connections", () => {
|
|
196
|
-
const testCases:
|
|
212
|
+
const testCases: [string, DatabaseConnection, ConnectionLibrary][] = [
|
|
197
213
|
["postgres with SQLModel", basePostgres, "sqlmodel"],
|
|
198
214
|
["postgres with SQLAlchemy", basePostgres, "sqlalchemy"],
|
|
199
215
|
["mysql with SQLModel", baseMysql, "sqlmodel"],
|
|
@@ -218,9 +234,16 @@ describe("generateDatabaseCode", () => {
|
|
|
218
234
|
["pyspark with session", pysparkConnSession, "ibis"],
|
|
219
235
|
["redshift with DB credentials", redshiftDBConnection, "redshift"],
|
|
220
236
|
["redshift with IAM credentials", redshiftIAMConnection, "redshift"],
|
|
237
|
+
["databricks", databricksConnection, "sqlalchemy"],
|
|
238
|
+
[
|
|
239
|
+
"databricks with catalog and schema",
|
|
240
|
+
databricksWithCatalogSchema,
|
|
241
|
+
"sqlalchemy",
|
|
242
|
+
],
|
|
243
|
+
["databricks with ibis", databricksConnection, "ibis"],
|
|
221
244
|
];
|
|
222
245
|
|
|
223
|
-
it.each(testCases)("%s", (
|
|
246
|
+
it.each(testCases)("%s", (_name, connection, orm) => {
|
|
224
247
|
expect(generateDatabaseCode(connection, orm)).toMatchSnapshot();
|
|
225
248
|
});
|
|
226
249
|
});
|
|
@@ -292,7 +315,7 @@ describe("generateDatabaseCode", () => {
|
|
|
292
315
|
},
|
|
293
316
|
"duckdb",
|
|
294
317
|
],
|
|
295
|
-
])("%s", (
|
|
318
|
+
])("%s", (_name, connection, orm) => {
|
|
296
319
|
expect(
|
|
297
320
|
generateDatabaseCode(connection, orm as ConnectionLibrary),
|
|
298
321
|
).toMatchSnapshot();
|
|
@@ -300,7 +323,7 @@ describe("generateDatabaseCode", () => {
|
|
|
300
323
|
});
|
|
301
324
|
|
|
302
325
|
describe("edge cases", () => {
|
|
303
|
-
const testCases:
|
|
326
|
+
const testCases: [string, DatabaseConnection, string][] = [
|
|
304
327
|
[
|
|
305
328
|
"ENV with special chars SQLModel",
|
|
306
329
|
{
|
|
@@ -504,7 +527,7 @@ describe("generateDatabaseCode", () => {
|
|
|
504
527
|
],
|
|
505
528
|
];
|
|
506
529
|
|
|
507
|
-
it.each(testCases)("%s", (
|
|
530
|
+
it.each(testCases)("%s", (_name, connection, orm) => {
|
|
508
531
|
expect(
|
|
509
532
|
generateDatabaseCode(connection, orm as ConnectionLibrary),
|
|
510
533
|
).toMatchSnapshot();
|
|
@@ -548,7 +571,7 @@ describe("generateDatabaseCode", () => {
|
|
|
548
571
|
credentials_json: '{"type": "service_account", "project_id": "test"',
|
|
549
572
|
},
|
|
550
573
|
],
|
|
551
|
-
])("%s", (
|
|
574
|
+
])("%s", (_name, connection) => {
|
|
552
575
|
expect(generateDatabaseCode(connection, "sqlmodel")).toMatchSnapshot();
|
|
553
576
|
expect(generateDatabaseCode(connection, "sqlalchemy")).toMatchSnapshot();
|
|
554
577
|
});
|
|
@@ -591,7 +614,7 @@ describe("generateDatabaseCode", () => {
|
|
|
591
614
|
"sqlmodel",
|
|
592
615
|
),
|
|
593
616
|
],
|
|
594
|
-
])("%s", (
|
|
617
|
+
])("%s", (_name, fn) => {
|
|
595
618
|
expect(fn).toThrow();
|
|
596
619
|
});
|
|
597
620
|
});
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
ChdbConnectionSchema,
|
|
40
40
|
ClickhouseConnectionSchema,
|
|
41
41
|
type DatabaseConnection,
|
|
42
|
+
DatabricksConnectionSchema,
|
|
42
43
|
DataFusionConnectionSchema,
|
|
43
44
|
DuckDBConnectionSchema,
|
|
44
45
|
IcebergConnectionSchema,
|
|
@@ -210,6 +211,16 @@ const DATABASES = [
|
|
|
210
211
|
preferred: "redshift",
|
|
211
212
|
},
|
|
212
213
|
},
|
|
214
|
+
{
|
|
215
|
+
name: "Databricks",
|
|
216
|
+
schema: DatabricksConnectionSchema,
|
|
217
|
+
color: "#c41e0c",
|
|
218
|
+
logo: "databricks",
|
|
219
|
+
connectionLibraries: {
|
|
220
|
+
libraries: ["sqlalchemy", "sqlmodel", "ibis"],
|
|
221
|
+
preferred: "sqlalchemy",
|
|
222
|
+
},
|
|
223
|
+
},
|
|
213
224
|
] satisfies ConnectionSchema[];
|
|
214
225
|
|
|
215
226
|
const DATA_CATALOGS = [
|
|
@@ -14,7 +14,8 @@ export type ConnectionLibrary =
|
|
|
14
14
|
| "pyiceberg"
|
|
15
15
|
| "ibis"
|
|
16
16
|
| "motherduck"
|
|
17
|
-
| "redshift"
|
|
17
|
+
| "redshift"
|
|
18
|
+
| "databricks";
|
|
18
19
|
|
|
19
20
|
export const ConnectionDisplayNames: Record<ConnectionLibrary, string> = {
|
|
20
21
|
sqlmodel: "SQLModel",
|
|
@@ -26,6 +27,7 @@ export const ConnectionDisplayNames: Record<ConnectionLibrary, string> = {
|
|
|
26
27
|
ibis: "Ibis",
|
|
27
28
|
motherduck: "MotherDuck",
|
|
28
29
|
redshift: "Redshift",
|
|
30
|
+
databricks: "Databricks",
|
|
29
31
|
};
|
|
30
32
|
|
|
31
33
|
abstract class CodeGenerator<T extends DatabaseConnection["type"]> {
|
|
@@ -55,6 +57,9 @@ abstract class CodeGenerator<T extends DatabaseConnection["type"]> {
|
|
|
55
57
|
case "duckdb":
|
|
56
58
|
imports.add("import duckdb");
|
|
57
59
|
break;
|
|
60
|
+
case "ibis":
|
|
61
|
+
imports.add("import ibis");
|
|
62
|
+
break;
|
|
58
63
|
}
|
|
59
64
|
return imports;
|
|
60
65
|
}
|
|
@@ -138,10 +143,38 @@ class SecretContainer {
|
|
|
138
143
|
return `{${value}}`;
|
|
139
144
|
}
|
|
140
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Generate a password variable for connection strings, supporting inline values,
|
|
148
|
+
* environment variable lookups, and f-string formatting.
|
|
149
|
+
* @param {string|undefined} password - Fallback password value.
|
|
150
|
+
* @param {string} passwordPlaceholder - Environment variable name.
|
|
151
|
+
* @param {boolean} inFString - If true, wrap for Python f-string.
|
|
152
|
+
* @param {string} [variableName] - Variable name (default: "password").
|
|
153
|
+
* @returns {string}
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* `printPassword("token123", "DATABRICKS_ACCESS_TOKEN", true, "access_token")`
|
|
157
|
+
*
|
|
158
|
+
* Returns:
|
|
159
|
+
* ```python
|
|
160
|
+
* _access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "token123")
|
|
161
|
+
* f"db://sample:{_access_token}@sample.com"
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* `printPassword("token123", "DATABRICKS_ACCESS_TOKEN", false, "access_token")`
|
|
166
|
+
*
|
|
167
|
+
* Returns:
|
|
168
|
+
* ```python
|
|
169
|
+
* access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "token123")
|
|
170
|
+
* f"db://sample:access_token@sample.com"
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
141
173
|
printPassword(
|
|
142
174
|
password: string | undefined,
|
|
143
175
|
passwordPlaceholder: string,
|
|
144
176
|
inFString: boolean,
|
|
177
|
+
variableName?: string,
|
|
145
178
|
): string {
|
|
146
179
|
// Inline passwords should use printInFString, otherwise use print
|
|
147
180
|
const printMethod = inFString
|
|
@@ -149,8 +182,8 @@ class SecretContainer {
|
|
|
149
182
|
: this.print.bind(this);
|
|
150
183
|
|
|
151
184
|
return isSecret(password)
|
|
152
|
-
? printMethod("password", password)
|
|
153
|
-
: printMethod("password", passwordPlaceholder, password);
|
|
185
|
+
? printMethod(variableName || "password", password)
|
|
186
|
+
: printMethod(variableName || "password", passwordPlaceholder, password);
|
|
154
187
|
}
|
|
155
188
|
|
|
156
189
|
getSecrets(): Record<string, string> {
|
|
@@ -557,7 +590,7 @@ class PyIcebergGenerator extends CodeGenerator<"iceberg"> {
|
|
|
557
590
|
class DataFusionGenerator extends CodeGenerator<"datafusion"> {
|
|
558
591
|
generateImports(): string[] {
|
|
559
592
|
// To trigger installation of ibis-datafusion
|
|
560
|
-
return ["
|
|
593
|
+
return ["from datafusion import SessionContext"];
|
|
561
594
|
}
|
|
562
595
|
|
|
563
596
|
generateConnectionCode(): string {
|
|
@@ -578,7 +611,7 @@ class DataFusionGenerator extends CodeGenerator<"datafusion"> {
|
|
|
578
611
|
|
|
579
612
|
class PySparkGenerator extends CodeGenerator<"pyspark"> {
|
|
580
613
|
generateImports(): string[] {
|
|
581
|
-
return ["
|
|
614
|
+
return ["from pyspark.sql import SparkSession"];
|
|
582
615
|
}
|
|
583
616
|
|
|
584
617
|
generateConnectionCode(): string {
|
|
@@ -668,6 +701,70 @@ ${formatUrlParams(params, (inner) => ` ${inner}`)},
|
|
|
668
701
|
}
|
|
669
702
|
}
|
|
670
703
|
|
|
704
|
+
class DatabricksGenerator extends CodeGenerator<"databricks"> {
|
|
705
|
+
generateImports(): string[] {
|
|
706
|
+
return [];
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
generateConnectionCode(): string {
|
|
710
|
+
const useFString = this.orm !== "ibis";
|
|
711
|
+
|
|
712
|
+
const accessToken = this.secrets.printPassword(
|
|
713
|
+
this.connection.access_token,
|
|
714
|
+
"DATABRICKS_ACCESS_TOKEN",
|
|
715
|
+
useFString,
|
|
716
|
+
"access_token",
|
|
717
|
+
);
|
|
718
|
+
|
|
719
|
+
const serverHostname = this.secrets.printPassword(
|
|
720
|
+
this.connection.server_hostname,
|
|
721
|
+
"DATABRICKS_SERVER_HOSTNAME",
|
|
722
|
+
useFString,
|
|
723
|
+
"server_hostname",
|
|
724
|
+
);
|
|
725
|
+
|
|
726
|
+
const httpPath = this.secrets.printPassword(
|
|
727
|
+
this.connection.http_path,
|
|
728
|
+
"DATABRICKS_HTTP_PATH",
|
|
729
|
+
useFString,
|
|
730
|
+
"http_path",
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
const catalog = this.connection.catalog
|
|
734
|
+
? this.secrets.printInFString("catalog", this.connection.catalog)
|
|
735
|
+
: undefined;
|
|
736
|
+
const schema = this.connection.schema
|
|
737
|
+
? this.secrets.printInFString("schema", this.connection.schema)
|
|
738
|
+
: undefined;
|
|
739
|
+
|
|
740
|
+
let BASE_URL = `databricks://token:${accessToken}@${serverHostname}?http_path=${httpPath}`;
|
|
741
|
+
if (catalog) {
|
|
742
|
+
BASE_URL += `&catalog=${catalog}`;
|
|
743
|
+
}
|
|
744
|
+
if (schema) {
|
|
745
|
+
BASE_URL += `&schema=${schema}`;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
if (this.orm === "ibis") {
|
|
749
|
+
const catalogParam = catalog ? `\n catalog=${catalog},` : "";
|
|
750
|
+
const schemaParam = schema ? `\n schema=${schema},` : "";
|
|
751
|
+
|
|
752
|
+
return dedent(`
|
|
753
|
+
engine = ibis.databricks.connect(
|
|
754
|
+
server_hostname=${serverHostname},
|
|
755
|
+
http_path=${httpPath},${catalogParam}${schemaParam}
|
|
756
|
+
access_token=${accessToken}
|
|
757
|
+
)
|
|
758
|
+
`);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
return dedent(`
|
|
762
|
+
DATABASE_URL = f"${BASE_URL}"
|
|
763
|
+
engine = ${this.orm}.create_engine(DATABASE_URL)
|
|
764
|
+
`);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
671
768
|
class CodeGeneratorFactory {
|
|
672
769
|
public secrets = new SecretContainer();
|
|
673
770
|
|
|
@@ -706,6 +803,8 @@ class CodeGeneratorFactory {
|
|
|
706
803
|
return new PySparkGenerator(connection, orm, this.secrets);
|
|
707
804
|
case "redshift":
|
|
708
805
|
return new RedshiftGenerator(connection, orm, this.secrets);
|
|
806
|
+
case "databricks":
|
|
807
|
+
return new DatabricksGenerator(connection, orm, this.secrets);
|
|
709
808
|
default:
|
|
710
809
|
assertNever(connection);
|
|
711
810
|
}
|
|
@@ -16,18 +16,16 @@ function passwordField() {
|
|
|
16
16
|
);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function tokenField() {
|
|
20
|
-
|
|
21
|
-
.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}),
|
|
30
|
-
);
|
|
19
|
+
function tokenField(label?: string, required?: boolean) {
|
|
20
|
+
const field = z.string().describe(
|
|
21
|
+
FieldOptions.of({
|
|
22
|
+
label: label || "Token",
|
|
23
|
+
inputType: "password",
|
|
24
|
+
placeholder: "token",
|
|
25
|
+
optionRegex: ".*token.*",
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
return required ? field.nonempty() : field.optional();
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
function warehouseNameField() {
|
|
@@ -43,20 +41,22 @@ function warehouseNameField() {
|
|
|
43
41
|
);
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
function uriField() {
|
|
47
|
-
|
|
44
|
+
function uriField(label?: string, required?: boolean) {
|
|
45
|
+
const field = z
|
|
48
46
|
.string()
|
|
49
|
-
.
|
|
50
|
-
|
|
47
|
+
.describe(
|
|
48
|
+
FieldOptions.of({ label: label || "URI", optionRegex: ".*uri.*" }),
|
|
49
|
+
);
|
|
50
|
+
return required ? field.nonempty() : field.optional();
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
function hostField() {
|
|
53
|
+
function hostField(label?: string) {
|
|
54
54
|
return z
|
|
55
55
|
.string()
|
|
56
56
|
.nonempty()
|
|
57
57
|
.describe(
|
|
58
58
|
FieldOptions.of({
|
|
59
|
-
label: "Host",
|
|
59
|
+
label: label || "Host",
|
|
60
60
|
placeholder: "localhost",
|
|
61
61
|
optionRegex: ".*host.*",
|
|
62
62
|
}),
|
|
@@ -464,6 +464,23 @@ export const RedshiftConnectionSchema = z
|
|
|
464
464
|
})
|
|
465
465
|
.describe(FieldOptions.of({ direction: "two-columns" }));
|
|
466
466
|
|
|
467
|
+
export const DatabricksConnectionSchema = z
|
|
468
|
+
.object({
|
|
469
|
+
type: z.literal("databricks"),
|
|
470
|
+
access_token: tokenField("Access Token", true),
|
|
471
|
+
server_hostname: hostField("Server Hostname"),
|
|
472
|
+
http_path: uriField("HTTP Path", true),
|
|
473
|
+
catalog: z
|
|
474
|
+
.string()
|
|
475
|
+
.optional()
|
|
476
|
+
.describe(FieldOptions.of({ label: "Catalog" })),
|
|
477
|
+
schema: z
|
|
478
|
+
.string()
|
|
479
|
+
.optional()
|
|
480
|
+
.describe(FieldOptions.of({ label: "Schema" })),
|
|
481
|
+
})
|
|
482
|
+
.describe(FieldOptions.of({ direction: "two-columns" }));
|
|
483
|
+
|
|
467
484
|
export const DatabaseConnectionSchema = z.discriminatedUnion("type", [
|
|
468
485
|
PostgresConnectionSchema,
|
|
469
486
|
MySQLConnectionSchema,
|
|
@@ -480,6 +497,7 @@ export const DatabaseConnectionSchema = z.discriminatedUnion("type", [
|
|
|
480
497
|
DataFusionConnectionSchema,
|
|
481
498
|
PySparkConnectionSchema,
|
|
482
499
|
RedshiftConnectionSchema,
|
|
500
|
+
DatabricksConnectionSchema,
|
|
483
501
|
]);
|
|
484
502
|
|
|
485
503
|
export type DatabaseConnection = z.infer<typeof DatabaseConnectionSchema>;
|
|
@@ -1,24 +1,33 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
+
import { useAtomValue, useSetAtom } from "jotai";
|
|
3
4
|
import { WrenchIcon } from "lucide-react";
|
|
4
5
|
import { Button } from "@/components/ui/button";
|
|
5
6
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
7
|
+
import { aiCompletionCellAtom } from "@/core/ai/state";
|
|
6
8
|
import { notebookAtom, useCellActions } from "@/core/cells/cells";
|
|
7
9
|
import type { CellId } from "@/core/cells/ids";
|
|
10
|
+
import { aiEnabledAtom } from "@/core/config/config";
|
|
8
11
|
import { getAutoFixes } from "@/core/errors/errors";
|
|
9
12
|
import type { MarimoError } from "@/core/kernel/messages";
|
|
10
13
|
import { store } from "@/core/state/jotai";
|
|
14
|
+
import { cn } from "@/utils/cn";
|
|
11
15
|
|
|
12
16
|
export const AutoFixButton = ({
|
|
13
17
|
errors,
|
|
14
18
|
cellId,
|
|
19
|
+
className,
|
|
15
20
|
}: {
|
|
16
21
|
errors: MarimoError[];
|
|
17
22
|
cellId: CellId;
|
|
18
23
|
className?: string;
|
|
19
24
|
}) => {
|
|
20
25
|
const { createNewCell } = useCellActions();
|
|
21
|
-
const
|
|
26
|
+
const aiEnabled = useAtomValue(aiEnabledAtom);
|
|
27
|
+
const autoFixes = errors.flatMap((error) =>
|
|
28
|
+
getAutoFixes(error, { aiEnabled }),
|
|
29
|
+
);
|
|
30
|
+
const setAiCompletionCell = useSetAtom(aiCompletionCellAtom);
|
|
22
31
|
|
|
23
32
|
if (autoFixes.length === 0) {
|
|
24
33
|
return null;
|
|
@@ -33,7 +42,7 @@ export const AutoFixButton = ({
|
|
|
33
42
|
<Button
|
|
34
43
|
size="xs"
|
|
35
44
|
variant="outline"
|
|
36
|
-
className="my-2 font-normal"
|
|
45
|
+
className={cn("my-2 font-normal", className)}
|
|
37
46
|
onClick={() => {
|
|
38
47
|
const editorView =
|
|
39
48
|
store.get(notebookAtom).cellHandles[cellId].current?.editorView;
|
|
@@ -48,6 +57,7 @@ export const AutoFixButton = ({
|
|
|
48
57
|
},
|
|
49
58
|
editor: editorView,
|
|
50
59
|
cellId: cellId,
|
|
60
|
+
setAiCompletionCell,
|
|
51
61
|
});
|
|
52
62
|
// Focus the editor
|
|
53
63
|
editorView?.focus();
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { AlertCircleIcon } from "lucide-react";
|
|
4
|
+
import type { CellId } from "@/core/cells/ids";
|
|
5
|
+
import { useSqlValidationErrorsForCell } from "@/core/codemirror/language/languages/sql/banner-validation-errors";
|
|
6
|
+
|
|
7
|
+
export const SqlValidationErrorBanner = ({
|
|
8
|
+
cellId,
|
|
9
|
+
hide,
|
|
10
|
+
}: {
|
|
11
|
+
cellId: CellId;
|
|
12
|
+
hide: boolean;
|
|
13
|
+
}) => {
|
|
14
|
+
const error = useSqlValidationErrorsForCell(cellId);
|
|
15
|
+
|
|
16
|
+
if (!error || hide) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className="p-3 text-sm flex flex-col text-muted-foreground gap-1.5 bg-destructive/4">
|
|
22
|
+
<div className="flex items-start gap-1.5">
|
|
23
|
+
<AlertCircleIcon size={13} className="mt-[3px] text-destructive" />
|
|
24
|
+
<p>
|
|
25
|
+
<span className="font-bold text-destructive">{error.errorType}:</span>{" "}
|
|
26
|
+
<span className="whitespace-pre-wrap">{error.errorMessage}</span>
|
|
27
|
+
</p>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
{error.codeblock && (
|
|
31
|
+
<pre
|
|
32
|
+
lang="sql"
|
|
33
|
+
className="text-xs bg-muted/80 rounded p-2 pb-0 mx-3 font-medium whitespace-pre-wrap"
|
|
34
|
+
>
|
|
35
|
+
{error.codeblock}
|
|
36
|
+
</pre>
|
|
37
|
+
)}
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
@@ -14,6 +14,7 @@ import type { OutputMessage } from "@/core/kernel/messages";
|
|
|
14
14
|
import { useSelectAllContent } from "@/hooks/useSelectAllContent";
|
|
15
15
|
import { cn } from "@/utils/cn";
|
|
16
16
|
import { copyToClipboard } from "@/utils/copy";
|
|
17
|
+
import { ansiToPlainText, parseHtmlContent } from "@/utils/dom";
|
|
17
18
|
import { invariant } from "@/utils/invariant";
|
|
18
19
|
import { Strings } from "@/utils/strings";
|
|
19
20
|
import { NameCellContentEditable } from "../actions/name-cell-input";
|
|
@@ -27,7 +28,7 @@ interface Props {
|
|
|
27
28
|
cellId: CellId;
|
|
28
29
|
cellName: string;
|
|
29
30
|
className?: string;
|
|
30
|
-
consoleOutputs:
|
|
31
|
+
consoleOutputs: WithResponse<OutputMessage>[];
|
|
31
32
|
stale: boolean;
|
|
32
33
|
debuggerActive: boolean;
|
|
33
34
|
onRefactorWithAI?: (opts: { prompt: string }) => void;
|
|
@@ -124,7 +125,18 @@ const ConsoleOutputInternal = (props: Props): React.ReactNode => {
|
|
|
124
125
|
onClick={() => {
|
|
125
126
|
const text = reversedOutputs
|
|
126
127
|
.filter((output) => output.channel !== "pdb")
|
|
127
|
-
.map((output) =>
|
|
128
|
+
.map((output) => {
|
|
129
|
+
// If starts with `<`, then assume it's HTML
|
|
130
|
+
if (
|
|
131
|
+
typeof output.data === "string" &&
|
|
132
|
+
output.data.startsWith("<")
|
|
133
|
+
) {
|
|
134
|
+
return parseHtmlContent(output.data);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Otherwise, convert the ANSI to HTML, then parse as HTML
|
|
138
|
+
return ansiToPlainText(Strings.asString(output.data));
|
|
139
|
+
})
|
|
128
140
|
.join("\n");
|
|
129
141
|
void copyToClipboard(text);
|
|
130
142
|
}}
|
|
@@ -200,7 +200,7 @@ const LEAF_RENDERERS = {
|
|
|
200
200
|
};
|
|
201
201
|
|
|
202
202
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
203
|
-
const MIME_TYPES:
|
|
203
|
+
const MIME_TYPES: DataType<any>[] = Object.entries(LEAF_RENDERERS).map(
|
|
204
204
|
([leafType, render]) => ({
|
|
205
205
|
is: (value) => typeof value === "string" && value.startsWith(leafType),
|
|
206
206
|
PostComponent: PyCopyButton,
|