@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
|
@@ -5,23 +5,32 @@ import { insertTab } from "@codemirror/commands";
|
|
|
5
5
|
import { type SQLDialect, type SQLNamespace, sql } from "@codemirror/lang-sql";
|
|
6
6
|
import type { EditorState, Extension } from "@codemirror/state";
|
|
7
7
|
import { Compartment } from "@codemirror/state";
|
|
8
|
-
import {
|
|
8
|
+
import { EditorView, keymap } from "@codemirror/view";
|
|
9
9
|
import type { SyntaxNode, TreeCursor } from "@lezer/common";
|
|
10
10
|
import { parser } from "@lezer/python";
|
|
11
11
|
import {
|
|
12
12
|
defaultSqlHoverTheme,
|
|
13
13
|
NodeSqlParser,
|
|
14
|
+
type NodeSqlParserResult,
|
|
14
15
|
type SupportedDialects as ParserDialects,
|
|
16
|
+
type SqlParseError,
|
|
15
17
|
sqlExtension,
|
|
16
18
|
} from "@marimo-team/codemirror-sql";
|
|
17
19
|
import { DuckDBDialect } from "@marimo-team/codemirror-sql/dialects";
|
|
18
20
|
import dedent from "string-dedent";
|
|
21
|
+
import { cellIdState } from "@/core/codemirror/cells/state";
|
|
19
22
|
import { getFeatureFlag } from "@/core/config/feature-flag";
|
|
20
23
|
import {
|
|
21
24
|
dataSourceConnectionsAtom,
|
|
22
25
|
setLatestEngineSelected,
|
|
23
26
|
} from "@/core/datasets/data-source-connections";
|
|
24
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
type ConnectionName,
|
|
29
|
+
DUCKDB_ENGINE,
|
|
30
|
+
INTERNAL_SQL_ENGINES,
|
|
31
|
+
} from "@/core/datasets/engines";
|
|
32
|
+
import { ValidateSQL } from "@/core/datasets/request-registry";
|
|
33
|
+
import type { ValidateSQLResult } from "@/core/kernel/messages";
|
|
25
34
|
import { store } from "@/core/state/jotai";
|
|
26
35
|
import { resolvedThemeAtom } from "@/theme/useTheme";
|
|
27
36
|
import { Logger } from "@/utils/Logger";
|
|
@@ -32,11 +41,16 @@ import { parseArgsKwargs } from "../../utils/ast";
|
|
|
32
41
|
import { indentOneTab } from "../../utils/indentOneTab";
|
|
33
42
|
import type { QuotePrefixKind } from "../../utils/quotes";
|
|
34
43
|
import { MarkdownLanguageAdapter } from "../markdown";
|
|
44
|
+
import {
|
|
45
|
+
clearSqlValidationError,
|
|
46
|
+
setSqlValidationError,
|
|
47
|
+
} from "./banner-validation-errors";
|
|
35
48
|
import {
|
|
36
49
|
customKeywordCompletionSource,
|
|
37
50
|
tablesCompletionSource,
|
|
38
51
|
} from "./completion-sources";
|
|
39
52
|
import { SCHEMA_CACHE } from "./completion-store";
|
|
53
|
+
import { getSQLMode, type SQLMode } from "./sql-mode";
|
|
40
54
|
|
|
41
55
|
const DEFAULT_DIALECT = DuckDBDialect;
|
|
42
56
|
const DEFAULT_PARSER_DIALECT = "DuckDB";
|
|
@@ -64,12 +78,15 @@ export class SQLLanguageAdapter
|
|
|
64
78
|
{
|
|
65
79
|
readonly type = "sql";
|
|
66
80
|
sqlLinterEnabled: boolean;
|
|
81
|
+
sqlModeEnabled: boolean;
|
|
67
82
|
|
|
68
83
|
constructor() {
|
|
69
84
|
try {
|
|
70
85
|
this.sqlLinterEnabled = getFeatureFlag("sql_linter");
|
|
86
|
+
this.sqlModeEnabled = getFeatureFlag("sql_mode");
|
|
71
87
|
} catch {
|
|
72
88
|
this.sqlLinterEnabled = false;
|
|
89
|
+
this.sqlModeEnabled = false;
|
|
73
90
|
}
|
|
74
91
|
}
|
|
75
92
|
|
|
@@ -230,7 +247,7 @@ export class SQLLanguageAdapter
|
|
|
230
247
|
|
|
231
248
|
if (this.sqlLinterEnabled) {
|
|
232
249
|
const theme = store.get(resolvedThemeAtom);
|
|
233
|
-
const parser = new
|
|
250
|
+
const parser = new CustomSqlParser({
|
|
234
251
|
getParserOptions: (state: EditorState) => {
|
|
235
252
|
return {
|
|
236
253
|
database: guessParserDialect(state) ?? DEFAULT_PARSER_DIALECT,
|
|
@@ -262,13 +279,103 @@ export class SQLLanguageAdapter
|
|
|
262
279
|
theme: defaultSqlHoverTheme(theme),
|
|
263
280
|
},
|
|
264
281
|
}),
|
|
282
|
+
EditorView.updateListener.of((update) => {
|
|
283
|
+
if (update.focusChanged) {
|
|
284
|
+
parser.setFocusState(update.view.hasFocus);
|
|
285
|
+
}
|
|
286
|
+
}),
|
|
265
287
|
);
|
|
266
288
|
}
|
|
267
289
|
|
|
290
|
+
if (this.sqlModeEnabled) {
|
|
291
|
+
extensions.push(sqlValidationExtension());
|
|
292
|
+
}
|
|
293
|
+
|
|
268
294
|
return extensions;
|
|
269
295
|
}
|
|
270
296
|
}
|
|
271
297
|
|
|
298
|
+
class CustomSqlParser extends NodeSqlParser {
|
|
299
|
+
private validationTimeout: number | null = null;
|
|
300
|
+
private readonly VALIDATION_DELAY_MS = 300; // Wait 300ms after user stops typing
|
|
301
|
+
private isFocused = false; // Only validate if the editor is focused
|
|
302
|
+
|
|
303
|
+
setFocusState(focused: boolean) {
|
|
304
|
+
this.isFocused = focused;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private async validateWithDelay(
|
|
308
|
+
sql: string,
|
|
309
|
+
engine: string,
|
|
310
|
+
dialect: ParserDialects | null,
|
|
311
|
+
): Promise<SqlParseError[]> {
|
|
312
|
+
// Clear any existing delay call
|
|
313
|
+
if (this.validationTimeout) {
|
|
314
|
+
window.clearTimeout(this.validationTimeout);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Set up a new request to be called after the delay
|
|
318
|
+
return new Promise((resolve) => {
|
|
319
|
+
this.validationTimeout = window.setTimeout(async () => {
|
|
320
|
+
// Only validate if the editor is still focused
|
|
321
|
+
if (!this.isFocused) {
|
|
322
|
+
resolve([]);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
const sqlMode = getSQLMode();
|
|
328
|
+
const result = await validateSQL(sql, engine, dialect, sqlMode);
|
|
329
|
+
if (result.error) {
|
|
330
|
+
Logger.error("Failed to validate SQL", { error: result.error });
|
|
331
|
+
resolve([]);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
resolve(result.parse_result?.errors ?? []);
|
|
335
|
+
} catch (error) {
|
|
336
|
+
Logger.error("Failed to validate SQL", { error });
|
|
337
|
+
resolve([]);
|
|
338
|
+
}
|
|
339
|
+
}, this.VALIDATION_DELAY_MS);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
override async validateSql(
|
|
344
|
+
sql: string,
|
|
345
|
+
opts: { state: EditorState },
|
|
346
|
+
): Promise<SqlParseError[]> {
|
|
347
|
+
const metadata = getSQLMetadata(opts.state);
|
|
348
|
+
|
|
349
|
+
// Only validate if the editor is focused
|
|
350
|
+
if (!this.isFocused) {
|
|
351
|
+
return [];
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Only perform custom validation for DuckDB
|
|
355
|
+
if (!INTERNAL_SQL_ENGINES.has(metadata.engine)) {
|
|
356
|
+
return super.validateSql(sql, opts);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const dialect = guessParserDialect(opts.state);
|
|
360
|
+
return this.validateWithDelay(sql, metadata.engine, dialect);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
override async parse(
|
|
364
|
+
sql: string,
|
|
365
|
+
opts: { state: EditorState },
|
|
366
|
+
): Promise<NodeSqlParserResult> {
|
|
367
|
+
const metadata = getSQLMetadata(opts.state);
|
|
368
|
+
const engine = metadata.engine;
|
|
369
|
+
|
|
370
|
+
// For now, always return success for DuckDB
|
|
371
|
+
if (engine === DUCKDB_ENGINE) {
|
|
372
|
+
return { success: true, errors: [] };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return super.parse(sql, opts);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
272
379
|
/**
|
|
273
380
|
* Update the SQL dialect in the editor view.
|
|
274
381
|
*/
|
|
@@ -315,9 +422,14 @@ function getSchema(view: EditorView): SQLNamespace {
|
|
|
315
422
|
function guessParserDialect(state: EditorState): ParserDialects | null {
|
|
316
423
|
const metadata = getSQLMetadata(state);
|
|
317
424
|
const connectionName = metadata.engine;
|
|
425
|
+
return connectionNameToParserDialect(connectionName);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function connectionNameToParserDialect(
|
|
429
|
+
connectionName: ConnectionName,
|
|
430
|
+
): ParserDialects | null {
|
|
318
431
|
const dialect =
|
|
319
432
|
SCHEMA_CACHE.getInternalDialect(connectionName)?.toLowerCase();
|
|
320
|
-
|
|
321
433
|
switch (dialect) {
|
|
322
434
|
case "postgresql":
|
|
323
435
|
case "postgres":
|
|
@@ -543,3 +655,105 @@ function safeDedent(code: string): string {
|
|
|
543
655
|
return code;
|
|
544
656
|
}
|
|
545
657
|
}
|
|
658
|
+
|
|
659
|
+
const SQL_VALIDATION_DEBOUNCE_MS = 300;
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Custom extension to run SQL queries in EXPLAIN mode on keypress.
|
|
663
|
+
*/
|
|
664
|
+
function sqlValidationExtension(): Extension {
|
|
665
|
+
let debounceTimeout: number | undefined;
|
|
666
|
+
let lastValidationRequest: string | null = null;
|
|
667
|
+
|
|
668
|
+
return EditorView.updateListener.of((update) => {
|
|
669
|
+
// Only run validation if the document has changed
|
|
670
|
+
if (!update.docChanged) {
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Only run validation if the SQL mode is set to validate
|
|
675
|
+
const sqlMode = getSQLMode();
|
|
676
|
+
if (sqlMode !== "validate") {
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const metadata = getSQLMetadata(update.state);
|
|
681
|
+
const connectionName = metadata.engine;
|
|
682
|
+
|
|
683
|
+
// Currently only DuckDB is supported
|
|
684
|
+
if (!INTERNAL_SQL_ENGINES.has(connectionName)) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const doc = update.state.doc;
|
|
689
|
+
const sqlContent = doc.toString();
|
|
690
|
+
|
|
691
|
+
// Clear existing timeout
|
|
692
|
+
if (debounceTimeout) {
|
|
693
|
+
window.clearTimeout(debounceTimeout);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Debounce the validation call
|
|
697
|
+
debounceTimeout = window.setTimeout(async () => {
|
|
698
|
+
// Skip if content hasn't changed since last validation
|
|
699
|
+
if (lastValidationRequest === sqlContent) {
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
lastValidationRequest = sqlContent;
|
|
704
|
+
const cellId = update.view.state.facet(cellIdState);
|
|
705
|
+
|
|
706
|
+
if (sqlContent === "") {
|
|
707
|
+
clearSqlValidationError(cellId);
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
try {
|
|
712
|
+
const dialect = connectionNameToParserDialect(connectionName);
|
|
713
|
+
const sqlMode = getSQLMode();
|
|
714
|
+
const result = await validateSQL(
|
|
715
|
+
sqlContent,
|
|
716
|
+
connectionName,
|
|
717
|
+
dialect,
|
|
718
|
+
sqlMode,
|
|
719
|
+
);
|
|
720
|
+
const validateResult = result.validate_result;
|
|
721
|
+
|
|
722
|
+
if (validateResult?.error_message) {
|
|
723
|
+
setSqlValidationError({
|
|
724
|
+
cellId,
|
|
725
|
+
errorMessage: validateResult.error_message,
|
|
726
|
+
dialect,
|
|
727
|
+
});
|
|
728
|
+
} else {
|
|
729
|
+
clearSqlValidationError(cellId);
|
|
730
|
+
}
|
|
731
|
+
} catch (error) {
|
|
732
|
+
Logger.error("Failed to validate SQL", { error });
|
|
733
|
+
}
|
|
734
|
+
}, SQL_VALIDATION_DEBOUNCE_MS);
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Determine if we should only parse or validate an SQL query.
|
|
740
|
+
* The endpoint is cached, so we should use the same mode for all validation requests.
|
|
741
|
+
*/
|
|
742
|
+
async function validateSQL(
|
|
743
|
+
sql: string,
|
|
744
|
+
engine: string,
|
|
745
|
+
dialect: ParserDialects | null,
|
|
746
|
+
sqlMode: SQLMode,
|
|
747
|
+
): Promise<ValidateSQLResult> {
|
|
748
|
+
const result = await ValidateSQL.request({
|
|
749
|
+
onlyParse: sqlMode === "default",
|
|
750
|
+
engine,
|
|
751
|
+
dialect,
|
|
752
|
+
query: sql,
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
if (result.error) {
|
|
756
|
+
throw new Error(result.error);
|
|
757
|
+
}
|
|
758
|
+
return result;
|
|
759
|
+
}
|
|
@@ -18,8 +18,11 @@ import {
|
|
|
18
18
|
} from "@marimo-team/codemirror-sql/dialects";
|
|
19
19
|
import type { DataSourceConnection } from "@/core/kernel/messages";
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Guess the CodeMirror SQL dialect from the backend connection dialect.
|
|
23
|
+
*/
|
|
21
24
|
export function guessDialect(
|
|
22
|
-
connection: DataSourceConnection,
|
|
25
|
+
connection: Pick<DataSourceConnection, "dialect">,
|
|
23
26
|
): SQLDialect | undefined {
|
|
24
27
|
switch (connection.dialect) {
|
|
25
28
|
case "postgresql":
|
|
@@ -5,7 +5,8 @@ import { Button } from "@/components/ui/button";
|
|
|
5
5
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
6
6
|
import { Tooltip, TooltipProvider } from "@/components/ui/tooltip";
|
|
7
7
|
import { normalizeName } from "@/core/cells/names";
|
|
8
|
-
import
|
|
8
|
+
import { getFeatureFlag } from "@/core/config/feature-flag";
|
|
9
|
+
import { type ConnectionName, DUCKDB_ENGINE } from "@/core/datasets/engines";
|
|
9
10
|
import { useAutoGrowInputProps } from "@/hooks/useAutoGrowInputProps";
|
|
10
11
|
import { formatSQL } from "../../format";
|
|
11
12
|
import { languageAdapterState } from "../extension";
|
|
@@ -22,7 +23,7 @@ import {
|
|
|
22
23
|
import type { LanguageMetadataOf } from "../types";
|
|
23
24
|
import type { QuotePrefixKind } from "../utils/quotes";
|
|
24
25
|
import { getQuotePrefix, MarkdownQuotePrefixTooltip } from "./markdown";
|
|
25
|
-
import { SQLEngineSelect } from "./sql";
|
|
26
|
+
import { SQLEngineSelect, SQLModeSelect } from "./sql";
|
|
26
27
|
|
|
27
28
|
const Divider = () => <div className="h-4 border-r border-border" />;
|
|
28
29
|
|
|
@@ -70,6 +71,8 @@ export const LanguagePanelComponent: React.FC<{
|
|
|
70
71
|
updateSQLDialectFromConnection(view, engine);
|
|
71
72
|
};
|
|
72
73
|
|
|
74
|
+
const sqlModeEnabled = getFeatureFlag("sql_mode");
|
|
75
|
+
|
|
73
76
|
actions = (
|
|
74
77
|
<div className="flex flex-1 gap-2 items-center">
|
|
75
78
|
<label className="flex gap-2 items-center">
|
|
@@ -95,6 +98,9 @@ export const LanguagePanelComponent: React.FC<{
|
|
|
95
98
|
onChange={switchEngine}
|
|
96
99
|
/>
|
|
97
100
|
<div className="flex items-center gap-2 ml-auto">
|
|
101
|
+
{sqlModeEnabled && metadata.engine === DUCKDB_ENGINE && (
|
|
102
|
+
<SQLModeSelect />
|
|
103
|
+
)}
|
|
98
104
|
<Tooltip content="Format SQL">
|
|
99
105
|
<Button
|
|
100
106
|
variant="text"
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
+
import type { SelectTriggerProps } from "@radix-ui/react-select";
|
|
3
4
|
import { useAtomValue } from "jotai";
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
AlertCircle,
|
|
7
|
+
CircleHelpIcon,
|
|
8
|
+
DatabaseBackup,
|
|
9
|
+
SearchCheck,
|
|
10
|
+
} from "lucide-react";
|
|
5
11
|
import { transformDisplayName } from "@/components/databases/display";
|
|
6
12
|
import { DatabaseLogo } from "@/components/databases/icon";
|
|
13
|
+
import { Button } from "@/components/ui/button";
|
|
7
14
|
import {
|
|
8
15
|
Select,
|
|
9
16
|
SelectContent,
|
|
@@ -14,6 +21,7 @@ import {
|
|
|
14
21
|
SelectTrigger,
|
|
15
22
|
SelectValue,
|
|
16
23
|
} from "@/components/ui/select";
|
|
24
|
+
import { Tooltip } from "@/components/ui/tooltip";
|
|
17
25
|
import {
|
|
18
26
|
dataConnectionsMapAtom,
|
|
19
27
|
setLatestEngineSelected,
|
|
@@ -24,6 +32,8 @@ import {
|
|
|
24
32
|
} from "@/core/datasets/engines";
|
|
25
33
|
import type { DataSourceConnection } from "@/core/kernel/messages";
|
|
26
34
|
import { useNonce } from "@/hooks/useNonce";
|
|
35
|
+
import { clearAllSqlValidationErrors } from "../languages/sql/banner-validation-errors";
|
|
36
|
+
import { type SQLMode, useSQLMode } from "../languages/sql/sql-mode";
|
|
27
37
|
|
|
28
38
|
interface SelectProps {
|
|
29
39
|
selectedEngine: ConnectionName;
|
|
@@ -77,7 +87,7 @@ export const SQLEngineSelect: React.FC<SelectProps> = ({
|
|
|
77
87
|
<SelectItem key={connection.name} value={connection.name}>
|
|
78
88
|
<div className="flex items-center gap-1">
|
|
79
89
|
<DatabaseLogo className="h-3 w-3" name={connection.dialect} />
|
|
80
|
-
<span className="truncate">
|
|
90
|
+
<span className="truncate ml-0.5">
|
|
81
91
|
{transformDisplayName(connection.display_name)}
|
|
82
92
|
</span>
|
|
83
93
|
</div>
|
|
@@ -88,9 +98,9 @@ export const SQLEngineSelect: React.FC<SelectProps> = ({
|
|
|
88
98
|
return (
|
|
89
99
|
<div className="flex flex-row gap-1 items-center">
|
|
90
100
|
<Select value={selectedEngine} onValueChange={handleSelectEngine}>
|
|
91
|
-
<
|
|
101
|
+
<SQLSelectTrigger>
|
|
92
102
|
<SelectValue placeholder="Select an engine" />
|
|
93
|
-
</
|
|
103
|
+
</SQLSelectTrigger>
|
|
94
104
|
<SelectContent>
|
|
95
105
|
<SelectGroup>
|
|
96
106
|
<SelectLabel>Database connections</SelectLabel>
|
|
@@ -130,3 +140,75 @@ export const SQLEngineSelect: React.FC<SelectProps> = ({
|
|
|
130
140
|
const HELP_KEY = "__help__";
|
|
131
141
|
const HELP_URL =
|
|
132
142
|
"http://docs.marimo.io/guides/working_with_data/sql/#connecting-to-a-custom-database";
|
|
143
|
+
|
|
144
|
+
export const SQLModeSelect: React.FC = () => {
|
|
145
|
+
const { sqlMode, setSQLMode } = useSQLMode();
|
|
146
|
+
|
|
147
|
+
const handleToggleMode = () => {
|
|
148
|
+
const nextMode = sqlMode === "validate" ? "default" : "validate";
|
|
149
|
+
if (nextMode === "default") {
|
|
150
|
+
clearAllSqlValidationErrors();
|
|
151
|
+
}
|
|
152
|
+
setSQLMode(nextMode);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const getModeIcon = (mode: SQLMode) => {
|
|
156
|
+
return mode === "validate" ? (
|
|
157
|
+
<SearchCheck className="h-3 w-3" />
|
|
158
|
+
) : (
|
|
159
|
+
<DatabaseBackup className="h-3 w-3" />
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const getTooltipContent = (mode: SQLMode) => {
|
|
164
|
+
return mode === "validate" ? (
|
|
165
|
+
<div className="text-xs">
|
|
166
|
+
<div className="font-semibold mb-1 flex flex-row items-center gap-1">
|
|
167
|
+
<SearchCheck className="h-3 w-3" />
|
|
168
|
+
Validate Mode
|
|
169
|
+
</div>
|
|
170
|
+
<p>Queries are validated as you write them</p>
|
|
171
|
+
</div>
|
|
172
|
+
) : (
|
|
173
|
+
<div className="text-xs">
|
|
174
|
+
<div className="font-semibold mb-1 flex flex-row items-center gap-1">
|
|
175
|
+
<DatabaseBackup className="h-3 w-3" />
|
|
176
|
+
Default Mode
|
|
177
|
+
</div>
|
|
178
|
+
<p>Standard editing</p>
|
|
179
|
+
</div>
|
|
180
|
+
);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<div className="flex flex-row gap-1 items-center">
|
|
185
|
+
<Tooltip delayDuration={300} content={getTooltipContent(sqlMode)}>
|
|
186
|
+
<Button
|
|
187
|
+
variant="ghost"
|
|
188
|
+
size="sm"
|
|
189
|
+
onClick={handleToggleMode}
|
|
190
|
+
className="h-5 px-1.5 text-xs border-border shadow-none hover:bg-accent"
|
|
191
|
+
>
|
|
192
|
+
{getModeIcon(sqlMode)}
|
|
193
|
+
<span className="ml-1">
|
|
194
|
+
{sqlMode === "validate" ? "Validate" : "Default"}
|
|
195
|
+
</span>
|
|
196
|
+
</Button>
|
|
197
|
+
</Tooltip>
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const SQLSelectTrigger: React.FC<SelectTriggerProps> = ({
|
|
203
|
+
children,
|
|
204
|
+
...props
|
|
205
|
+
}) => {
|
|
206
|
+
return (
|
|
207
|
+
<SelectTrigger
|
|
208
|
+
className="text-xs border-border shadow-none! ring-0! h-5 px-1.5 hover:bg-accent transition-colors"
|
|
209
|
+
{...props}
|
|
210
|
+
>
|
|
211
|
+
{children}
|
|
212
|
+
</SelectTrigger>
|
|
213
|
+
);
|
|
214
|
+
};
|
|
@@ -10,7 +10,7 @@ export function parseArgsKwargs(
|
|
|
10
10
|
code: string,
|
|
11
11
|
): {
|
|
12
12
|
args: SyntaxNode[];
|
|
13
|
-
kwargs:
|
|
13
|
+
kwargs: { key: string; value: string }[];
|
|
14
14
|
} {
|
|
15
15
|
// Check we are in an ArgList
|
|
16
16
|
const name = argCursor.name;
|
|
@@ -54,8 +54,8 @@ function parseArgs(argCursor: TreeCursor): SyntaxNode[] {
|
|
|
54
54
|
function parseKwargs(
|
|
55
55
|
argCursor: TreeCursor,
|
|
56
56
|
code: string,
|
|
57
|
-
):
|
|
58
|
-
const kwargs:
|
|
57
|
+
): { key: string; value: string }[] {
|
|
58
|
+
const kwargs: { key: string; value: string }[] = [];
|
|
59
59
|
let name = argCursor.name;
|
|
60
60
|
|
|
61
61
|
do {
|
|
@@ -115,7 +115,7 @@ export class FederatedLanguageServerClient implements ILanguageServerClient {
|
|
|
115
115
|
|
|
116
116
|
async textDocumentCodeAction(
|
|
117
117
|
params: LSP.CodeActionParams,
|
|
118
|
-
): Promise<
|
|
118
|
+
): Promise<(LSP.Command | LSP.CodeAction)[] | null> {
|
|
119
119
|
const client = this.firstWithCapability("codeActionProvider");
|
|
120
120
|
if (client) {
|
|
121
121
|
return client.textDocumentCodeAction(params);
|
|
@@ -206,9 +206,9 @@ export class FederatedLanguageServerClient implements ILanguageServerClient {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
function mergeCompletions(
|
|
209
|
-
results:
|
|
210
|
-
|
|
211
|
-
|
|
209
|
+
results: PromiseSettledResult<
|
|
210
|
+
LSP.CompletionList | LSP.CompletionItem[] | null
|
|
211
|
+
>[],
|
|
212
212
|
): LSP.CompletionList {
|
|
213
213
|
const completions: LSP.CompletionItem[] = [];
|
|
214
214
|
let isIncomplete = false;
|
|
@@ -22,10 +22,10 @@ export interface NotebookLens {
|
|
|
22
22
|
reversePosition: (position: LSP.Position, cellId: CellId) => LSP.Position;
|
|
23
23
|
|
|
24
24
|
/** Clip a range to the given cell */
|
|
25
|
-
getEditsForNewText: (newText: string) =>
|
|
25
|
+
getEditsForNewText: (newText: string) => {
|
|
26
26
|
cellId: CellId;
|
|
27
27
|
text: string;
|
|
28
|
-
}
|
|
28
|
+
}[];
|
|
29
29
|
|
|
30
30
|
/** Check if a range falls within the given cell */
|
|
31
31
|
isInRange: (range: LSP.Range, cellId: CellId) => boolean;
|
|
@@ -84,10 +84,10 @@ export function createNotebookLens(
|
|
|
84
84
|
throw new Error("Cannot apply rename when there are new lines");
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
const edits:
|
|
87
|
+
const edits: {
|
|
88
88
|
cellId: CellId;
|
|
89
89
|
text: string;
|
|
90
|
-
}
|
|
90
|
+
}[] = [];
|
|
91
91
|
|
|
92
92
|
for (const [cellId, code] of Objects.entries(codes)) {
|
|
93
93
|
if (!cellLineOffsets.has(cellId)) {
|
|
@@ -300,7 +300,7 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
|
|
|
300
300
|
|
|
301
301
|
textDocumentCodeAction(
|
|
302
302
|
params: LSP.CodeActionParams,
|
|
303
|
-
): Promise<
|
|
303
|
+
): Promise<(LSP.Command | LSP.CodeAction)[] | null> {
|
|
304
304
|
const disabledCodeAction = true;
|
|
305
305
|
if (disabledCodeAction) {
|
|
306
306
|
return Promise.resolve(null);
|
|
@@ -49,7 +49,7 @@ export function isClientWithNotify(
|
|
|
49
49
|
export function isClientWithPlugins(
|
|
50
50
|
client: ILanguageServerClient,
|
|
51
51
|
): client is ILanguageServerClient & {
|
|
52
|
-
plugins:
|
|
52
|
+
plugins: { documentUri: string; view?: EditorView }[];
|
|
53
53
|
} {
|
|
54
54
|
return "plugins" in client;
|
|
55
55
|
}
|
|
@@ -133,7 +133,7 @@ const latexSymbolCompletionSource: CompletionSource = (context) => {
|
|
|
133
133
|
|
|
134
134
|
// Common LaTeX symbols with their UTF-8 equivalents
|
|
135
135
|
const getLatexSymbolList = once((): Completion[] => {
|
|
136
|
-
const symbols:
|
|
136
|
+
const symbols: [string, string, string][] = [
|
|
137
137
|
// Greek letters
|
|
138
138
|
["alpha", "α", "Greek small letter alpha"],
|
|
139
139
|
["beta", "β", "Greek small letter beta"],
|
|
@@ -67,7 +67,7 @@ export function findReactiveVariables(options: {
|
|
|
67
67
|
// Maps to track variable declarations and scopes
|
|
68
68
|
const allDeclarations = new Map<number, Set<string>>(); // scope position -> variable names
|
|
69
69
|
const scopeTypes = new Map<number, string>(); // scope position -> scope type (e.g., "ClassDefinition")
|
|
70
|
-
const classLevelDeclarations = new Map<number,
|
|
70
|
+
const classLevelDeclarations = new Map<number, [string, number][]>(); // class scope -> [varName, position] pairs
|
|
71
71
|
|
|
72
72
|
// Class-level variables require special handling because they're evaluated sequentially
|
|
73
73
|
// A variable is only available after its assignment statement completes
|
|
@@ -555,7 +555,7 @@ function extractAssignmentTargets(
|
|
|
555
555
|
state: EditorState;
|
|
556
556
|
allDeclarations: Map<number, Set<string>>;
|
|
557
557
|
scopeTypes: Map<number, string>;
|
|
558
|
-
classLevelDeclarations: Map<number,
|
|
558
|
+
classLevelDeclarations: Map<number, [string, number][]>;
|
|
559
559
|
assignmentPosition: number;
|
|
560
560
|
},
|
|
561
561
|
) {
|
|
@@ -302,7 +302,7 @@ const parseAwarenessUpdate = (
|
|
|
302
302
|
removed: PeerID[];
|
|
303
303
|
},
|
|
304
304
|
scopeId: ScopeId,
|
|
305
|
-
):
|
|
305
|
+
): StateEffect<CursorEffect>[] => {
|
|
306
306
|
const effects = [];
|
|
307
307
|
const { updated, added } = arg;
|
|
308
308
|
for (const update of [...updated, ...added]) {
|
|
@@ -163,6 +163,7 @@ export const UserConfigSchema = z
|
|
|
163
163
|
anthropic: AiConfigSchema.optional(),
|
|
164
164
|
google: AiConfigSchema.optional(),
|
|
165
165
|
ollama: AiConfigSchema.optional(),
|
|
166
|
+
openrouter: AiConfigSchema.optional(),
|
|
166
167
|
open_ai_compatible: AiConfigSchema.optional(),
|
|
167
168
|
azure: AiConfigSchema.optional(),
|
|
168
169
|
bedrock: z
|
|
@@ -12,8 +12,10 @@ export interface ExperimentalFeatures {
|
|
|
12
12
|
rtc_v2: boolean;
|
|
13
13
|
performant_table_charts: boolean;
|
|
14
14
|
mcp_docs: boolean;
|
|
15
|
+
chat_modes: boolean;
|
|
15
16
|
sql_linter: boolean;
|
|
16
17
|
external_agents: boolean;
|
|
18
|
+
sql_mode: boolean;
|
|
17
19
|
// Add new feature flags here
|
|
18
20
|
}
|
|
19
21
|
|
|
@@ -24,15 +26,17 @@ const defaultValues: ExperimentalFeatures = {
|
|
|
24
26
|
rtc_v2: false,
|
|
25
27
|
performant_table_charts: false,
|
|
26
28
|
mcp_docs: false,
|
|
27
|
-
|
|
29
|
+
chat_modes: false,
|
|
30
|
+
sql_linter: true,
|
|
28
31
|
external_agents: import.meta.env.DEV,
|
|
32
|
+
sql_mode: false,
|
|
29
33
|
};
|
|
30
34
|
|
|
31
35
|
export function getFeatureFlag<T extends keyof ExperimentalFeatures>(
|
|
32
36
|
feature: T,
|
|
33
37
|
): ExperimentalFeatures[T] {
|
|
34
38
|
return (
|
|
35
|
-
(getResolvedMarimoConfig()
|
|
39
|
+
(getResolvedMarimoConfig()?.experimental?.[
|
|
36
40
|
feature
|
|
37
41
|
] as ExperimentalFeatures[T]) ?? defaultValues[feature]
|
|
38
42
|
);
|