@marimo-team/frontend 0.16.2 → 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-B5cPvWoQ.js → ConnectedDataExplorerComponent-Brtw1DxF.js} +1 -1
- package/dist/assets/{ImageComparisonComponent-CqR26LSv.js → ImageComparisonComponent-Dxl-PbZX.js} +1 -1
- package/dist/assets/{VegaLite-DvQDATwI.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-ZcHkHPNJ.js → _createAggregator-VFK9K2d9.js} +1 -1
- package/dist/assets/{agent-panel-B91RoLct.js → agent-panel-BoscVLCT.js} +7 -7
- package/dist/assets/{any-language-editor-CxfHcm5h.js → any-language-editor-ChaY_VUU.js} +1 -1
- package/dist/assets/{architectureDiagram-W76B3OCA-BQsvK8uR.js → architectureDiagram-W76B3OCA-CueUUFYd.js} +1 -1
- package/dist/assets/{between-horizontal-start-BmYToIaM.js → between-horizontal-start-DAHqmLYT.js} +1 -1
- package/dist/assets/{blockDiagram-QIGZ2CNN-r3HgCj4w.js → blockDiagram-QIGZ2CNN-BYYygyWn.js} +1 -1
- package/dist/assets/{c4Diagram-FPNF74CW-BJbPNt41.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-Dv4MZ9Hj.js → chunk-4BX2VUAB-8g-RyHdt.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-CM4AHquB.js → chunk-55IACEB6-iWZZ8Mt6.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-C_Zz0ENB.js → chunk-FMBD7UC4-knjss4wk.js} +1 -1
- package/dist/assets/{chunk-K7UQS3LO-DYSmiXYq.js → chunk-K7UQS3LO-DVIwPBgZ.js} +1 -1
- package/dist/assets/{chunk-QN33PNHL-QM4OPuQP.js → chunk-QN33PNHL-CBU8pN6I.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-CfAsGyeB.js → chunk-QZHKN3VN-5ljElUF4.js} +1 -1
- package/dist/assets/{chunk-TVAH2DTR-6j_Cpjsi.js → chunk-TVAH2DTR-DkIdGINc.js} +1 -1
- package/dist/assets/{chunk-TZMSLE5B-BHslFJQE.js → chunk-TZMSLE5B-CIFOSTqh.js} +1 -1
- package/dist/assets/{circle-play-CK3UZRYQ.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-C4fDVSv8.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-D-lbuUwz.js → common-DahoYqdi.js} +1 -1
- package/dist/assets/{compile-DVQe1Mzk.js → compile-Bg8uJ7vm.js} +1 -1
- package/dist/assets/{cose-bilkent-S5V4N54A-D-IS7WC8.js → cose-bilkent-S5V4N54A-z_0gqD9K.js} +1 -1
- package/dist/assets/{dagre-5GWH7T2D-lYu-tEWT.js → dagre-5GWH7T2D-BMt7CNXL.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-C5peOCit.js → data-grid-overlay-editor-Ctn4XtXx.js} +1 -1
- package/dist/assets/{datasources-panel-D3NA20uZ.js → datasources-panel-C7sqRIHs.js} +1 -1
- package/dist/assets/{dependency-graph-panel-BGVYOfkV.js → dependency-graph-panel-DNajptzv.js} +4 -4
- package/dist/assets/{diagram-N5W7TBWH-BnvIuYUp.js → diagram-N5W7TBWH-BzwvLvAy.js} +1 -1
- package/dist/assets/{diagram-QEK2KX5R-DemedRK3.js → diagram-QEK2KX5R-DRLJ56FS.js} +1 -1
- package/dist/assets/{diagram-S2PKOQOG-iiY7AuyH.js → diagram-S2PKOQOG-Bf8x4KTU.js} +1 -1
- package/dist/assets/{documentation-panel-C3dSwOSQ.js → documentation-panel-Dm6Ozl67.js} +1 -1
- package/dist/assets/edit-page-CGc9EjuG.js +140 -0
- package/dist/assets/{ellipsis-vertical-CazJl8M7.js → ellipsis-vertical-Bj1YXvZe.js} +1 -1
- package/dist/assets/{empty-state-DW308mFO.js → empty-state-CYev-D31.js} +1 -1
- package/dist/assets/{erDiagram-AWTI2OKA-6wQ8Ugg0.js → erDiagram-AWTI2OKA-DmgzgN_I.js} +1 -1
- package/dist/assets/{error-panel-D1VnJ1yP.js → error-panel-BYG4twCa.js} +1 -1
- package/dist/assets/{file-explorer-panel-0oVd4t-D.js → file-explorer-panel-BSMiOApi.js} +1 -1
- package/dist/assets/{flowDiagram-PVAE7QVJ-C55IUWjm.js → flowDiagram-PVAE7QVJ-BdRKkajr.js} +1 -1
- package/dist/assets/{ganttDiagram-OWAHRB6G-DmqCM6ME.js → ganttDiagram-OWAHRB6G-lfRAMnq_.js} +5 -5
- package/dist/assets/{gitGraphDiagram-NY62KEGX-DBvhAeM_.js → gitGraphDiagram-NY62KEGX-CQVTIrHF.js} +1 -1
- package/dist/assets/{glide-data-editor-CHNuHidQ.js → glide-data-editor-D5A4pou7.js} +11 -11
- package/dist/assets/{graph-CG6BgUWQ.js → graph-CBNo279v.js} +1 -1
- package/dist/assets/{home-page-dgivXuSR.js → home-page-CmdznBJR.js} +3 -3
- package/dist/assets/{index-BTGpssVX.js → index-0dfGh-Gj.js} +1 -1
- package/dist/assets/{index-C7dtgr9A.js → index-BDYVSSzB.js} +1 -1
- package/dist/assets/{index-C02SqeRj.js → index-B_KyDZ94.js} +1 -1
- package/dist/assets/{index-mkubqy9-.js → index-Bfy-I_lW.js} +1 -1
- package/dist/assets/{index-BelfnXwL.js → index-Bh98Tp-z.js} +1 -1
- package/dist/assets/{index-CAQvMTzM.js → index-BhroIwBL.js} +1 -1
- package/dist/assets/{index-BneyUujp.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-Csd6QrCV.js → index-C6DWtSls.js} +1 -1
- package/dist/assets/{index-BYVZlBF8.js → index-C71cdkH-.js} +1 -1
- package/dist/assets/{index-z4krxQ4j.js → index-CT_FTqvK.js} +1 -1
- package/dist/assets/{index-Db36XTG_.js → index-CU5rRr66.js} +1 -1
- package/dist/assets/{index-CtPksxf0.js → index-Cb6duXQm.js} +1 -1
- package/dist/assets/{index-DAZ-9ri2.js → index-D23e9zQj.js} +1 -1
- package/dist/assets/index-DUGecC2Z.js +68 -0
- package/dist/assets/{index-M_pBKDSe.js → index-DcGIOAQi.js} +1 -1
- package/dist/assets/{index-DONRrmA2.js → index-PJfa9qXY.js} +1 -1
- package/dist/assets/{index-sbO9UaUU.js → index-SPslPC2B.js} +1 -1
- package/dist/assets/{index-DdIhdEVw.js → index-VPQlo4Uz.js} +1 -1
- package/dist/assets/{index-_luCZMLM.js → index-qbTLKWyG.js} +1 -1
- package/dist/assets/infoDiagram-STP46IZ2-DBu8p9gd.js +2 -0
- package/dist/assets/{isEmpty-CqX_YTIf.js → isEmpty-CnOLuQIv.js} +1 -1
- package/dist/assets/{journeyDiagram-BIP6EPQ6-Y5w_Tqe_.js → journeyDiagram-BIP6EPQ6-6U_vHJBH.js} +1 -1
- package/dist/assets/{kanban-definition-6OIFK2YF-DbXs5Rxi.js → kanban-definition-6OIFK2YF-DgnR14ys.js} +1 -1
- package/dist/assets/{layout-BCNPDACj.js → layout-RHmq4fP9.js} +1 -1
- package/dist/assets/{linear-uO6UVhXt.js → linear-CLdOVPGV.js} +1 -1
- package/dist/assets/links-Dd1icsEk.js +7 -0
- package/dist/assets/{logs-panel-BEQ1eRUp.js → logs-panel-CjbuhBLx.js} +1 -1
- package/dist/assets/{markdown-renderer-Dmzbb00W.js → markdown-renderer-X5YJvAZq.js} +3 -3
- package/dist/assets/{mermaid-qRc4MXIj.js → mermaid-Bl2T5oEC.js} +1 -1
- package/dist/assets/{mermaid.core-CvvJtCRj.js → mermaid.core-CfukBvGI.js} +4 -4
- package/dist/assets/min-BXIes1Za.js +1 -0
- package/dist/assets/{mindmap-definition-Q6HEUPPD-G5NognM-.js → mindmap-definition-Q6HEUPPD-BXCjP4Lu.js} +1 -1
- package/dist/assets/{number-overlay-editor-DPr5sHFu.js → number-overlay-editor-BUyqkSes.js} +1 -1
- package/dist/assets/{outline-panel-gxQXvVi4.js → outline-panel-BvGcPKdd.js} +1 -1
- package/dist/assets/{packages-panel-B1T0VPlg.js → packages-panel-BichDQWG.js} +1 -1
- package/dist/assets/{pieDiagram-ADFJNKIX-DK9SHkfc.js → pieDiagram-ADFJNKIX-CMzJFIJM.js} +1 -1
- package/dist/assets/{quadrantDiagram-LMRXKWRM-D1DdWF8C.js → quadrantDiagram-LMRXKWRM-CfGssUlO.js} +1 -1
- package/dist/assets/{react-plotly-CTwajqCb.js → react-plotly-DR3hV0HW.js} +1 -1
- package/dist/assets/{requirementDiagram-4UW4RH46-DnjDAypr.js → requirementDiagram-4UW4RH46-CfrFolth.js} +1 -1
- package/dist/assets/{run-page-CQY9im22.js → run-page-Bqd_4ePD.js} +1 -1
- package/dist/assets/{sankeyDiagram-GR3RE2ED-B67Va-ER.js → sankeyDiagram-GR3RE2ED-D_UttKU0.js} +1 -1
- package/dist/assets/scratchpad-panel-D5N15ji1.js +1 -0
- package/dist/assets/secrets-panel-BpbnAO4R.js +1 -0
- package/dist/assets/{sequenceDiagram-C3RYC4MD-DiWgZPtN.js → sequenceDiagram-C3RYC4MD-MdfQQApP.js} +1 -1
- package/dist/assets/{slides-component-DhpPRtQp.js → slides-component-C0z7rXmk.js} +1 -1
- package/dist/assets/{snippets-panel-CLkBXhJ2.js → snippets-panel-wlpZ_Wzx.js} +1 -1
- package/dist/assets/{sortBy-D4OG7w4O.js → sortBy-BW_zNHP6.js} +1 -1
- package/dist/assets/{state-Dz_3JyED.js → state-CDooX-dk.js} +1 -1
- package/dist/assets/{stateDiagram-KXAO66HF-ByF2AULw.js → stateDiagram-KXAO66HF-H7kfw3ot.js} +1 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-YMeb9qMR.js +1 -0
- package/dist/assets/{storage-Dr0CC44z.js → storage-b1QCapTq.js} +6 -6
- package/dist/assets/{terminal-BtdissBf.js → terminal-CPV44BXz.js} +1 -1
- package/dist/assets/{time-DKdOTnQg.js → time-DDy3xv5Y.js} +1 -1
- package/dist/assets/{timeline-definition-XQNQX7LJ-DzER9bf6.js → timeline-definition-XQNQX7LJ-J-cPRT2_.js} +1 -1
- package/dist/assets/{tracing-Dpx5M-u3.js → tracing-3eHHRUiJ.js} +2 -2
- package/dist/assets/{tracing-panel-hCjBkSER.js → tracing-panel-BMgy3D7d.js} +2 -2
- package/dist/assets/{trash-C6Ko-g5q.js → trash--tonOuDe.js} +1 -1
- package/dist/assets/{tree-BHN2gcCF.js → tree-ouIGEsVg.js} +6 -6
- package/dist/assets/{treemap-75Q7IDZK-DR79Mhzt.js → treemap-75Q7IDZK-CzJTJ_3R.js} +20 -20
- package/dist/assets/{variable-panel-PFBCFz36.js → variable-panel-sFTn4Oih.js} +1 -1
- package/dist/assets/{vega-component-Db6-uY4C.js → vega-component-BkPkzX9r.js} +1 -1
- package/dist/assets/{xychartDiagram-6GGTOJPD-DWzBP3tZ.js → xychartDiagram-6GGTOJPD-BZ8WOb_8.js} +1 -1
- package/dist/index.html +10 -3
- package/package.json +6 -6
- package/src/__mocks__/common.ts +5 -3
- package/src/__mocks__/notebook.ts +2 -2
- 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__/data-table.test.tsx +2 -2
- 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 +1 -1
- 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 +6 -5
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +1 -1
- 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 +6 -2
- 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 +12 -6
- package/src/components/editor/navigation/clipboard.ts +2 -2
- package/src/components/editor/output/ConsoleOutput.tsx +1 -1
- package/src/components/editor/output/JsonOutput.tsx +1 -1
- package/src/components/editor/output/MarimoErrorOutput.tsx +25 -25
- 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/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 +1 -1
- package/src/core/codemirror/language/__tests__/sql-validation.test.ts +1 -1
- 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/{validation-errors.ts → banner-validation-errors.ts} +9 -3
- 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.ts +151 -24
- package/src/core/codemirror/language/languages/sql/utils.ts +4 -1
- package/src/core/codemirror/language/panel/sql.tsx +6 -1
- 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 +3 -1
- package/src/core/datasets/request-registry.ts +17 -10
- 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/main.ts +2 -2
- package/src/core/islands/parse.ts +1 -3
- package/src/core/kernel/messages.ts +1 -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/types.ts +1 -1
- package/src/core/variables/state.ts +2 -2
- package/src/core/wasm/__tests__/state.test.ts +1 -1
- package/src/core/websocket/useMarimoWebSocket.tsx +5 -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/impl/DataTablePlugin.tsx +7 -2
- 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/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/utils/Logger.ts +1 -1
- package/src/utils/__tests__/data-views.test.ts +30 -68
- package/src/utils/__tests__/dom.test.ts +10 -10
- 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/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--KDTwKbG.js +0 -1
- package/dist/assets/_baseMap-Cu3o-eyO.js +0 -1
- package/dist/assets/_baseUniq-y7ZXnMo1.js +0 -1
- package/dist/assets/channel-DFaEx1fu.js +0 -1
- package/dist/assets/chat-panel-IoPMv8e2.js +0 -3
- package/dist/assets/classDiagram-KNZD7YFC-BsZtvV5O.js +0 -1
- package/dist/assets/classDiagram-v2-RKCZMP56-BsZtvV5O.js +0 -1
- package/dist/assets/clone-YBEvPE-s.js +0 -1
- package/dist/assets/command-palette-D7hOfvf6.js +0 -1
- package/dist/assets/edit-page-C5TsEeSo.js +0 -129
- package/dist/assets/index-CGDMlQfO.css +0 -1
- package/dist/assets/index-CelXfcd8.js +0 -580
- package/dist/assets/index-Cxyk7pt-.js +0 -68
- package/dist/assets/infoDiagram-STP46IZ2-wTALjfPc.js +0 -2
- package/dist/assets/links-Drv7cJgN.js +0 -7
- package/dist/assets/min-DYUOb1RR.js +0 -1
- package/dist/assets/scratchpad-panel-DlDfcDtW.js +0 -1
- package/dist/assets/secrets-panel-BDGyuGZA.js +0 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-CtBJqosP.js +0 -1
- package/src/__tests__/lru.test.ts +0 -74
|
@@ -11,7 +11,9 @@ 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";
|
|
@@ -39,16 +41,16 @@ import { parseArgsKwargs } from "../../utils/ast";
|
|
|
39
41
|
import { indentOneTab } from "../../utils/indentOneTab";
|
|
40
42
|
import type { QuotePrefixKind } from "../../utils/quotes";
|
|
41
43
|
import { MarkdownLanguageAdapter } from "../markdown";
|
|
44
|
+
import {
|
|
45
|
+
clearSqlValidationError,
|
|
46
|
+
setSqlValidationError,
|
|
47
|
+
} from "./banner-validation-errors";
|
|
42
48
|
import {
|
|
43
49
|
customKeywordCompletionSource,
|
|
44
50
|
tablesCompletionSource,
|
|
45
51
|
} from "./completion-sources";
|
|
46
52
|
import { SCHEMA_CACHE } from "./completion-store";
|
|
47
|
-
import { getSQLMode } from "./sql-mode";
|
|
48
|
-
import {
|
|
49
|
-
clearSqlValidationError,
|
|
50
|
-
setSqlValidationError,
|
|
51
|
-
} from "./validation-errors";
|
|
53
|
+
import { getSQLMode, type SQLMode } from "./sql-mode";
|
|
52
54
|
|
|
53
55
|
const DEFAULT_DIALECT = DuckDBDialect;
|
|
54
56
|
const DEFAULT_PARSER_DIALECT = "DuckDB";
|
|
@@ -245,7 +247,7 @@ export class SQLLanguageAdapter
|
|
|
245
247
|
|
|
246
248
|
if (this.sqlLinterEnabled) {
|
|
247
249
|
const theme = store.get(resolvedThemeAtom);
|
|
248
|
-
const parser = new
|
|
250
|
+
const parser = new CustomSqlParser({
|
|
249
251
|
getParserOptions: (state: EditorState) => {
|
|
250
252
|
return {
|
|
251
253
|
database: guessParserDialect(state) ?? DEFAULT_PARSER_DIALECT,
|
|
@@ -277,6 +279,11 @@ export class SQLLanguageAdapter
|
|
|
277
279
|
theme: defaultSqlHoverTheme(theme),
|
|
278
280
|
},
|
|
279
281
|
}),
|
|
282
|
+
EditorView.updateListener.of((update) => {
|
|
283
|
+
if (update.focusChanged) {
|
|
284
|
+
parser.setFocusState(update.view.hasFocus);
|
|
285
|
+
}
|
|
286
|
+
}),
|
|
280
287
|
);
|
|
281
288
|
}
|
|
282
289
|
|
|
@@ -288,6 +295,87 @@ export class SQLLanguageAdapter
|
|
|
288
295
|
}
|
|
289
296
|
}
|
|
290
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
|
+
|
|
291
379
|
/**
|
|
292
380
|
* Update the SQL dialect in the editor view.
|
|
293
381
|
*/
|
|
@@ -568,11 +656,22 @@ function safeDedent(code: string): string {
|
|
|
568
656
|
}
|
|
569
657
|
}
|
|
570
658
|
|
|
659
|
+
const SQL_VALIDATION_DEBOUNCE_MS = 300;
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Custom extension to run SQL queries in EXPLAIN mode on keypress.
|
|
663
|
+
*/
|
|
571
664
|
function sqlValidationExtension(): Extension {
|
|
572
|
-
let debounceTimeout:
|
|
665
|
+
let debounceTimeout: number | undefined;
|
|
573
666
|
let lastValidationRequest: string | null = null;
|
|
574
667
|
|
|
575
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
|
|
576
675
|
const sqlMode = getSQLMode();
|
|
577
676
|
if (sqlMode !== "validate") {
|
|
578
677
|
return;
|
|
@@ -580,12 +679,9 @@ function sqlValidationExtension(): Extension {
|
|
|
580
679
|
|
|
581
680
|
const metadata = getSQLMetadata(update.state);
|
|
582
681
|
const connectionName = metadata.engine;
|
|
583
|
-
if (!INTERNAL_SQL_ENGINES.has(connectionName)) {
|
|
584
|
-
// Currently only internal engines are supported
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
682
|
|
|
588
|
-
|
|
683
|
+
// Currently only DuckDB is supported
|
|
684
|
+
if (!INTERNAL_SQL_ENGINES.has(connectionName)) {
|
|
589
685
|
return;
|
|
590
686
|
}
|
|
591
687
|
|
|
@@ -594,11 +690,11 @@ function sqlValidationExtension(): Extension {
|
|
|
594
690
|
|
|
595
691
|
// Clear existing timeout
|
|
596
692
|
if (debounceTimeout) {
|
|
597
|
-
clearTimeout(debounceTimeout);
|
|
693
|
+
window.clearTimeout(debounceTimeout);
|
|
598
694
|
}
|
|
599
695
|
|
|
600
696
|
// Debounce the validation call
|
|
601
|
-
debounceTimeout = setTimeout(async () => {
|
|
697
|
+
debounceTimeout = window.setTimeout(async () => {
|
|
602
698
|
// Skip if content hasn't changed since last validation
|
|
603
699
|
if (lastValidationRequest === sqlContent) {
|
|
604
700
|
return;
|
|
@@ -613,20 +709,51 @@ function sqlValidationExtension(): Extension {
|
|
|
613
709
|
}
|
|
614
710
|
|
|
615
711
|
try {
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
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
|
+
});
|
|
624
728
|
} else {
|
|
625
729
|
clearSqlValidationError(cellId);
|
|
626
730
|
}
|
|
627
731
|
} catch (error) {
|
|
628
|
-
Logger.
|
|
732
|
+
Logger.error("Failed to validate SQL", { error });
|
|
629
733
|
}
|
|
630
|
-
},
|
|
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,
|
|
631
753
|
});
|
|
754
|
+
|
|
755
|
+
if (result.error) {
|
|
756
|
+
throw new Error(result.error);
|
|
757
|
+
}
|
|
758
|
+
return result;
|
|
632
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":
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
} from "@/core/datasets/engines";
|
|
33
33
|
import type { DataSourceConnection } from "@/core/kernel/messages";
|
|
34
34
|
import { useNonce } from "@/hooks/useNonce";
|
|
35
|
+
import { clearAllSqlValidationErrors } from "../languages/sql/banner-validation-errors";
|
|
35
36
|
import { type SQLMode, useSQLMode } from "../languages/sql/sql-mode";
|
|
36
37
|
|
|
37
38
|
interface SelectProps {
|
|
@@ -144,7 +145,11 @@ export const SQLModeSelect: React.FC = () => {
|
|
|
144
145
|
const { sqlMode, setSQLMode } = useSQLMode();
|
|
145
146
|
|
|
146
147
|
const handleToggleMode = () => {
|
|
147
|
-
|
|
148
|
+
const nextMode = sqlMode === "validate" ? "default" : "validate";
|
|
149
|
+
if (nextMode === "default") {
|
|
150
|
+
clearAllSqlValidationErrors();
|
|
151
|
+
}
|
|
152
|
+
setSQLMode(nextMode);
|
|
148
153
|
};
|
|
149
154
|
|
|
150
155
|
const getModeIcon = (mode: SQLMode) => {
|
|
@@ -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,6 +12,7 @@ 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;
|
|
17
18
|
sql_mode: boolean;
|
|
@@ -25,7 +26,8 @@ const defaultValues: ExperimentalFeatures = {
|
|
|
25
26
|
rtc_v2: false,
|
|
26
27
|
performant_table_charts: false,
|
|
27
28
|
mcp_docs: false,
|
|
28
|
-
|
|
29
|
+
chat_modes: false,
|
|
30
|
+
sql_linter: true,
|
|
29
31
|
external_agents: import.meta.env.DEV,
|
|
30
32
|
sql_mode: false,
|
|
31
33
|
};
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
SQLTablePreview,
|
|
5
5
|
ValidateSQLResult,
|
|
6
6
|
} from "../kernel/messages";
|
|
7
|
+
import { CachingRequestRegistry } from "../network/CachingRequestRegistry";
|
|
7
8
|
import { DeferredRequestRegistry } from "../network/DeferredRequestRegistry";
|
|
8
9
|
import { getRequestClient } from "../network/requests";
|
|
9
10
|
import type {
|
|
@@ -38,13 +39,19 @@ export const PreviewSQLTableList = new DeferredRequestRegistry<
|
|
|
38
39
|
});
|
|
39
40
|
});
|
|
40
41
|
|
|
41
|
-
export const ValidateSQL = new
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
});
|
|
42
|
+
export const ValidateSQL = new CachingRequestRegistry(
|
|
43
|
+
new DeferredRequestRegistry<
|
|
44
|
+
Omit<ValidateSQLRequest, "requestId">,
|
|
45
|
+
ValidateSQLResult
|
|
46
|
+
>("validate-sql", async (requestId, req) => {
|
|
47
|
+
const client = getRequestClient();
|
|
48
|
+
await client.validateSQL({
|
|
49
|
+
requestId: requestId,
|
|
50
|
+
...req,
|
|
51
|
+
});
|
|
52
|
+
}),
|
|
53
|
+
{
|
|
54
|
+
// Only keep the last 3 validation results
|
|
55
|
+
maxSize: 3,
|
|
56
|
+
},
|
|
57
|
+
);
|
package/src/core/dom/events.ts
CHANGED
|
@@ -43,7 +43,7 @@ export const MarimoIncomingMessageEvent = defineCustomEvent(
|
|
|
43
43
|
)<{
|
|
44
44
|
objectId: UIElementId;
|
|
45
45
|
message: unknown;
|
|
46
|
-
buffers: DataView[]
|
|
46
|
+
buffers: readonly DataView[];
|
|
47
47
|
}>();
|
|
48
48
|
export type MarimoIncomingMessageEventType = ReturnType<
|
|
49
49
|
typeof MarimoIncomingMessageEvent.create
|
package/src/core/dom/outline.ts
CHANGED
|
@@ -57,7 +57,7 @@ export function headingToIdentifier(heading: Element): OutlineItem["by"] {
|
|
|
57
57
|
return { path: `//${heading.tagName}[contains(., "${name}")]` };
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export function mergeOutlines(outlines:
|
|
60
|
+
export function mergeOutlines(outlines: (Outline | null)[]): Outline {
|
|
61
61
|
return {
|
|
62
62
|
items: outlines.filter(Boolean).flatMap((outline) => outline.items),
|
|
63
63
|
};
|
|
@@ -104,7 +104,7 @@ export function canCollapseOutline(outline: Outline | null): boolean {
|
|
|
104
104
|
*/
|
|
105
105
|
export function findCollapseRange(
|
|
106
106
|
startIndex: number,
|
|
107
|
-
outlines:
|
|
107
|
+
outlines: (Outline | null)[],
|
|
108
108
|
): [number, number] | null {
|
|
109
109
|
// Higher header is the lowest value
|
|
110
110
|
const getHighestHeader = (outline: Outline) => {
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import { byteStringToDataView } from "@/utils/data-views";
|
|
4
|
-
import type { Base64String } from "@/utils/json/base64";
|
|
5
|
-
import { typedAtob } from "@/utils/json/base64";
|
|
6
3
|
import { Logger } from "@/utils/Logger";
|
|
7
4
|
import type { CellId, UIElementId } from "../cells/ids";
|
|
8
5
|
import {
|
|
@@ -136,15 +133,12 @@ export class UIElementRegistry {
|
|
|
136
133
|
broadcastMessage(
|
|
137
134
|
objectId: UIElementId,
|
|
138
135
|
message: unknown,
|
|
139
|
-
buffers:
|
|
136
|
+
buffers: readonly DataView[],
|
|
140
137
|
): void {
|
|
141
138
|
const entry = this.entries.get(objectId);
|
|
142
139
|
if (entry === undefined) {
|
|
143
140
|
Logger.warn("UIElementRegistry missing entry", objectId);
|
|
144
141
|
} else {
|
|
145
|
-
const toDataView = (base64: Base64String) => {
|
|
146
|
-
return byteStringToDataView(typedAtob(base64));
|
|
147
|
-
};
|
|
148
142
|
entry.elements.forEach((element) => {
|
|
149
143
|
element.dispatchEvent(
|
|
150
144
|
MarimoIncomingMessageEvent.create({
|
|
@@ -153,7 +147,7 @@ export class UIElementRegistry {
|
|
|
153
147
|
detail: {
|
|
154
148
|
objectId: objectId,
|
|
155
149
|
message: message,
|
|
156
|
-
buffers: buffers
|
|
150
|
+
buffers: buffers,
|
|
157
151
|
},
|
|
158
152
|
}),
|
|
159
153
|
);
|
|
@@ -16,6 +16,10 @@ describe("getImportCode", () => {
|
|
|
16
16
|
});
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
+
const opts = {
|
|
20
|
+
aiEnabled: true,
|
|
21
|
+
};
|
|
22
|
+
|
|
19
23
|
describe("getAutoFixes", () => {
|
|
20
24
|
it("returns wrap in function fix for multiple-defs error", () => {
|
|
21
25
|
const error: MarimoError = {
|
|
@@ -24,7 +28,7 @@ describe("getAutoFixes", () => {
|
|
|
24
28
|
cells: ["foo"],
|
|
25
29
|
};
|
|
26
30
|
|
|
27
|
-
const fixes = getAutoFixes(error);
|
|
31
|
+
const fixes = getAutoFixes(error, opts);
|
|
28
32
|
expect(fixes).toHaveLength(1);
|
|
29
33
|
expect(fixes[0].title).toBe("Fix: Wrap in a function");
|
|
30
34
|
});
|
|
@@ -37,11 +41,25 @@ describe("getAutoFixes", () => {
|
|
|
37
41
|
raising_cell: null,
|
|
38
42
|
};
|
|
39
43
|
|
|
40
|
-
const fixes = getAutoFixes(error);
|
|
44
|
+
const fixes = getAutoFixes(error, opts);
|
|
41
45
|
expect(fixes).toHaveLength(1);
|
|
42
46
|
expect(fixes[0].title).toBe("Fix: Add 'import numpy as np'");
|
|
43
47
|
});
|
|
44
48
|
|
|
49
|
+
it("returns sql fix for sql-error error", () => {
|
|
50
|
+
const error: MarimoError = {
|
|
51
|
+
type: "sql-error",
|
|
52
|
+
msg: "syntax error",
|
|
53
|
+
sql_statement: "SELECT * FROM table",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const fixes = getAutoFixes(error, opts);
|
|
57
|
+
expect(fixes).toHaveLength(1);
|
|
58
|
+
expect(fixes[0].title).toBe("Fix with AI");
|
|
59
|
+
|
|
60
|
+
expect(getAutoFixes(error, { aiEnabled: false })).toHaveLength(0);
|
|
61
|
+
});
|
|
62
|
+
|
|
45
63
|
it("returns no fixes for NameError with unknown import", () => {
|
|
46
64
|
const error: MarimoError = {
|
|
47
65
|
type: "exception",
|
|
@@ -50,7 +68,7 @@ describe("getAutoFixes", () => {
|
|
|
50
68
|
raising_cell: null,
|
|
51
69
|
};
|
|
52
70
|
|
|
53
|
-
expect(getAutoFixes(error)).toHaveLength(0);
|
|
71
|
+
expect(getAutoFixes(error, opts)).toHaveLength(0);
|
|
54
72
|
});
|
|
55
73
|
|
|
56
74
|
it("returns no fixes for other error types", () => {
|
|
@@ -59,6 +77,6 @@ describe("getAutoFixes", () => {
|
|
|
59
77
|
msg: "invalid syntax",
|
|
60
78
|
};
|
|
61
79
|
|
|
62
|
-
expect(getAutoFixes(error)).toHaveLength(0);
|
|
80
|
+
expect(getAutoFixes(error, opts)).toHaveLength(0);
|
|
63
81
|
});
|
|
64
82
|
});
|
|
@@ -12,10 +12,19 @@ export interface AutoFix {
|
|
|
12
12
|
addCodeBelow: (code: string) => void;
|
|
13
13
|
editor: EditorView | undefined;
|
|
14
14
|
cellId: CellId;
|
|
15
|
+
setAiCompletionCell?: (cell: {
|
|
16
|
+
cellId: CellId;
|
|
17
|
+
initialPrompt?: string;
|
|
18
|
+
}) => void;
|
|
15
19
|
}) => Promise<void>;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
export function getAutoFixes(
|
|
22
|
+
export function getAutoFixes(
|
|
23
|
+
error: MarimoError,
|
|
24
|
+
opts: {
|
|
25
|
+
aiEnabled: boolean;
|
|
26
|
+
},
|
|
27
|
+
): AutoFix[] {
|
|
19
28
|
if (error.type === "multiple-defs") {
|
|
20
29
|
return [
|
|
21
30
|
{
|
|
@@ -57,6 +66,25 @@ export function getAutoFixes(error: MarimoError): AutoFix[] {
|
|
|
57
66
|
];
|
|
58
67
|
}
|
|
59
68
|
|
|
69
|
+
if (error.type === "sql-error") {
|
|
70
|
+
// Only show AI fix if AI is enabled
|
|
71
|
+
if (!opts.aiEnabled) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
return [
|
|
75
|
+
{
|
|
76
|
+
title: "Fix with AI",
|
|
77
|
+
description: "Fix the SQL statement",
|
|
78
|
+
onFix: async (ctx) => {
|
|
79
|
+
ctx.setAiCompletionCell?.({
|
|
80
|
+
cellId: ctx.cellId,
|
|
81
|
+
initialPrompt: `Fix the SQL statement: ${error.msg}`,
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
|
|
60
88
|
return [];
|
|
61
89
|
}
|
|
62
90
|
|
package/src/core/errors/state.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { generateUUID } from "@/utils/uuid";
|
|
|
7
7
|
import type { Banner } from "../kernel/messages";
|
|
8
8
|
|
|
9
9
|
interface BannerState {
|
|
10
|
-
banners:
|
|
10
|
+
banners: Identified<Banner>[];
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const { valueAtom: bannersAtom, useActions } = createReducerAndAtoms(
|