@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
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
InfoIcon,
|
|
5
|
+
NotebookPenIcon,
|
|
6
|
+
SquareArrowOutUpRightIcon,
|
|
7
|
+
} from "lucide-react";
|
|
4
8
|
import { Fragment, type JSX } from "react";
|
|
5
9
|
import {
|
|
6
10
|
Accordion,
|
|
@@ -72,6 +76,8 @@ export const MarimoErrorOutput = ({
|
|
|
72
76
|
titleContents = "Ancestor stopped";
|
|
73
77
|
alertVariant = "default";
|
|
74
78
|
titleColor = "text-secondary-foreground";
|
|
79
|
+
} else if (errors.some((e) => e.type === "sql-error")) {
|
|
80
|
+
titleContents = "SQL error";
|
|
75
81
|
} else {
|
|
76
82
|
// Check for exception type
|
|
77
83
|
const exceptionError = errors.find((e) => e.type === "exception");
|
|
@@ -126,6 +132,10 @@ export const MarimoErrorOutput = ({
|
|
|
126
132
|
const unknownErrors = errors.filter(
|
|
127
133
|
(e): e is Extract<MarimoError, { type: "unknown" }> => e.type === "unknown",
|
|
128
134
|
);
|
|
135
|
+
const sqlErrors = errors.filter(
|
|
136
|
+
(e): e is Extract<MarimoError, { type: "sql-error" }> =>
|
|
137
|
+
e.type === "sql-error",
|
|
138
|
+
);
|
|
129
139
|
|
|
130
140
|
const openScratchpad = () => {
|
|
131
141
|
chromeActions.openApplication("scratchpad");
|
|
@@ -485,6 +495,55 @@ export const MarimoErrorOutput = ({
|
|
|
485
495
|
);
|
|
486
496
|
}
|
|
487
497
|
|
|
498
|
+
if (sqlErrors.length > 0) {
|
|
499
|
+
messages.push(
|
|
500
|
+
<div key="sql-errors">
|
|
501
|
+
{sqlErrors.map((error, idx) => {
|
|
502
|
+
const line =
|
|
503
|
+
error.sql_line == null ? null : Math.trunc(error?.sql_line) + 1;
|
|
504
|
+
const col =
|
|
505
|
+
error.sql_col == null ? null : Math.trunc(error?.sql_col) + 1;
|
|
506
|
+
return (
|
|
507
|
+
<div key={`sql-error-${idx}`} className="space-y-2 mt-2">
|
|
508
|
+
<p className="text-muted-foreground font-medium">{error.msg}</p>
|
|
509
|
+
{error.hint && (
|
|
510
|
+
<div className="flex items-start gap-2">
|
|
511
|
+
<InfoIcon
|
|
512
|
+
size={11}
|
|
513
|
+
className="text-muted-foreground mt-1 flex-shrink-0"
|
|
514
|
+
/>
|
|
515
|
+
<p className="whitespace-pre-wrap text-sm text-muted-foreground">
|
|
516
|
+
{error.hint}
|
|
517
|
+
</p>
|
|
518
|
+
</div>
|
|
519
|
+
)}
|
|
520
|
+
{error.sql_statement && (
|
|
521
|
+
<pre
|
|
522
|
+
lang="sql"
|
|
523
|
+
className="text-xs bg-muted/80 rounded whitespace-pre-wrap p-3.5"
|
|
524
|
+
>
|
|
525
|
+
{error.sql_statement.trim()}
|
|
526
|
+
</pre>
|
|
527
|
+
)}
|
|
528
|
+
{line !== null && col !== null && (
|
|
529
|
+
<p className="text-xs text-muted-foreground">
|
|
530
|
+
Error at line {line}, column {col}
|
|
531
|
+
</p>
|
|
532
|
+
)}
|
|
533
|
+
</div>
|
|
534
|
+
);
|
|
535
|
+
})}
|
|
536
|
+
{cellId && (
|
|
537
|
+
<AutoFixButton
|
|
538
|
+
errors={sqlErrors}
|
|
539
|
+
cellId={cellId}
|
|
540
|
+
className="mt-2.5"
|
|
541
|
+
/>
|
|
542
|
+
)}
|
|
543
|
+
</div>,
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
|
|
488
547
|
return messages;
|
|
489
548
|
};
|
|
490
549
|
|
|
@@ -108,7 +108,7 @@ export const MarimoTracebackOutput = ({
|
|
|
108
108
|
Fix with AI
|
|
109
109
|
</Button>
|
|
110
110
|
)}
|
|
111
|
-
{tracebackInfo && !isWasm() && (
|
|
111
|
+
{tracebackInfo && tracebackInfo.kind === "cell" && !isWasm() && (
|
|
112
112
|
<Tooltip content={"Attach pdb to the exception point."}>
|
|
113
113
|
<Button
|
|
114
114
|
size="xs"
|
|
@@ -180,7 +180,7 @@ function lastLine(text: string): string {
|
|
|
180
180
|
|
|
181
181
|
export const replaceTracebackFilenames = (domNode: DOMNode) => {
|
|
182
182
|
const info = getTracebackInfo(domNode);
|
|
183
|
-
if (info) {
|
|
183
|
+
if (info?.kind === "cell") {
|
|
184
184
|
const tooltipContent = <InsertBreakpointContent />;
|
|
185
185
|
return (
|
|
186
186
|
<span className="nb">
|
|
@@ -211,6 +211,21 @@ export const replaceTracebackFilenames = (domNode: DOMNode) => {
|
|
|
211
211
|
</span>
|
|
212
212
|
);
|
|
213
213
|
}
|
|
214
|
+
if (info?.kind === "file") {
|
|
215
|
+
return (
|
|
216
|
+
<div
|
|
217
|
+
className="inline-block cursor-pointer text-destructive hover:underline"
|
|
218
|
+
onClick={(_) => {
|
|
219
|
+
getRequestClient().openFile({
|
|
220
|
+
path: info.filePath,
|
|
221
|
+
lineNumber: info.lineNumber,
|
|
222
|
+
});
|
|
223
|
+
}}
|
|
224
|
+
>
|
|
225
|
+
<span className="nb">"{info.filePath}"</span>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
214
229
|
};
|
|
215
230
|
|
|
216
231
|
export const replaceTracebackPrefix = (domNode: DOMNode) => {
|
|
@@ -68,13 +68,13 @@ export interface GridLayout extends Omit<SerializedGridLayout, "cells"> {
|
|
|
68
68
|
/**
|
|
69
69
|
* The cells in the layout.
|
|
70
70
|
*/
|
|
71
|
-
cells:
|
|
71
|
+
cells: {
|
|
72
72
|
i: string;
|
|
73
73
|
x: number;
|
|
74
74
|
y: number;
|
|
75
75
|
w: number;
|
|
76
76
|
h: number;
|
|
77
|
-
}
|
|
77
|
+
}[];
|
|
78
78
|
|
|
79
79
|
scrollableCells: Set<CellId>;
|
|
80
80
|
|
|
@@ -8,7 +8,7 @@ import { VerticalLayoutPlugin } from "./vertical-layout/vertical-layout";
|
|
|
8
8
|
|
|
9
9
|
// If more renderers are added, we may want to consider lazy loading them.
|
|
10
10
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
-
export const cellRendererPlugins:
|
|
11
|
+
export const cellRendererPlugins: ICellRendererPlugin<any, any>[] = [
|
|
12
12
|
GridLayoutPlugin,
|
|
13
13
|
SlidesLayoutPlugin,
|
|
14
14
|
VerticalLayoutPlugin,
|
|
@@ -198,7 +198,7 @@ const ActionButtons: React.FC<{
|
|
|
198
198
|
actions.push(
|
|
199
199
|
<DropdownMenuItem
|
|
200
200
|
onSelect={onToggleShowCode}
|
|
201
|
-
|
|
201
|
+
data-testid="notebook-action-show-code"
|
|
202
202
|
key="show-code"
|
|
203
203
|
>
|
|
204
204
|
<Code2Icon className="mr-2" size={14} strokeWidth={1.5} />
|
|
@@ -213,7 +213,7 @@ const ActionButtons: React.FC<{
|
|
|
213
213
|
actions.push(
|
|
214
214
|
<DropdownMenuItem
|
|
215
215
|
onSelect={handleDownloadAsHTML}
|
|
216
|
-
|
|
216
|
+
data-testid="notebook-action-download-html"
|
|
217
217
|
key="download-html"
|
|
218
218
|
>
|
|
219
219
|
<FolderDownIcon className="mr-2" size={14} strokeWidth={1.5} />
|
|
@@ -222,7 +222,7 @@ const ActionButtons: React.FC<{
|
|
|
222
222
|
<DropdownMenuSeparator key="download-html-separator" />,
|
|
223
223
|
<DropdownMenuItem
|
|
224
224
|
onSelect={handleDownloadAsPNG}
|
|
225
|
-
|
|
225
|
+
data-testid="notebook-action-download-png"
|
|
226
226
|
key="download-png"
|
|
227
227
|
>
|
|
228
228
|
<ImageIcon className="mr-2" size={14} strokeWidth={1.5} />
|
|
@@ -239,7 +239,7 @@ const ActionButtons: React.FC<{
|
|
|
239
239
|
// as this may be used in custom css to hide/show the actions dropdown
|
|
240
240
|
return (
|
|
241
241
|
<div
|
|
242
|
-
|
|
242
|
+
data-testid="notebook-actions-dropdown"
|
|
243
243
|
className={cn(
|
|
244
244
|
"right-0 top-0 z-50 m-4 no-print flex gap-2 print:hidden",
|
|
245
245
|
// If the notebook is static, we have a banner at the top, so
|
|
@@ -419,10 +419,10 @@ export const VerticalLayoutPlugin: ICellRendererPlugin<
|
|
|
419
419
|
};
|
|
420
420
|
|
|
421
421
|
export function groupCellsByColumn(
|
|
422
|
-
cells:
|
|
423
|
-
):
|
|
422
|
+
cells: (CellRuntimeState & CellData)[],
|
|
423
|
+
): [number, (CellRuntimeState & CellData)[]][] {
|
|
424
424
|
// Group cells by column
|
|
425
|
-
const cellsByColumn = new Map<number,
|
|
425
|
+
const cellsByColumn = new Map<number, (CellRuntimeState & CellData)[]>();
|
|
426
426
|
let lastSeenColumn = 0;
|
|
427
427
|
cells.forEach((cell) => {
|
|
428
428
|
const column = cell.config.column ?? lastSeenColumn;
|
|
@@ -59,7 +59,7 @@ interface Props<T extends FieldValues> {
|
|
|
59
59
|
form: UseFormReturn<T>;
|
|
60
60
|
schema: z.ZodType;
|
|
61
61
|
path?: Path<T>;
|
|
62
|
-
renderers:
|
|
62
|
+
renderers: FormRenderer<T>[] | undefined;
|
|
63
63
|
children?: React.ReactNode;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -82,7 +82,7 @@ export function renderZodSchema<T extends FieldValues, S>(
|
|
|
82
82
|
schema: z.ZodType<S>,
|
|
83
83
|
form: UseFormReturn<T>,
|
|
84
84
|
path: Path<T>,
|
|
85
|
-
renderers:
|
|
85
|
+
renderers: FormRenderer<T>[],
|
|
86
86
|
) {
|
|
87
87
|
// Try custom renderers first
|
|
88
88
|
for (const renderer of renderers) {
|
|
@@ -330,7 +330,7 @@ export function renderZodSchema<T extends FieldValues, S>(
|
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
if (schema instanceof z.ZodDiscriminatedUnion) {
|
|
333
|
-
const options = schema._def.options as
|
|
333
|
+
const options = schema._def.options as z.ZodType<unknown>[];
|
|
334
334
|
const discriminator = schema._def.discriminator;
|
|
335
335
|
const optionsMap = schema._def.optionsMap;
|
|
336
336
|
return (
|
|
@@ -392,7 +392,7 @@ export function renderZodSchema<T extends FieldValues, S>(
|
|
|
392
392
|
control={form.control}
|
|
393
393
|
name={path}
|
|
394
394
|
render={({ field }) => {
|
|
395
|
-
const options = schema._def.options as
|
|
395
|
+
const options = schema._def.options as z.ZodType<unknown>[];
|
|
396
396
|
let value: string = field.value;
|
|
397
397
|
const types = options.map((option) => {
|
|
398
398
|
return getUnionLiteral(option)._def.value;
|
|
@@ -812,6 +812,6 @@ const MultiSelectFormField = ({
|
|
|
812
812
|
);
|
|
813
813
|
};
|
|
814
814
|
|
|
815
|
-
function joinPath<T>(...parts:
|
|
815
|
+
function joinPath<T>(...parts: (string | number)[]): Path<T> {
|
|
816
816
|
return parts.filter((part) => part !== "").join(".") as Path<T>;
|
|
817
817
|
}
|
|
@@ -8,6 +8,7 @@ export const ExternalLink = ({
|
|
|
8
8
|
| `https://console.anthropic.com/${string}`
|
|
9
9
|
| `https://aistudio.google.com/${string}`
|
|
10
10
|
| `https://github.com/${string}`
|
|
11
|
+
| `https://openrouter.ai/${string}`
|
|
11
12
|
| `https://docs.marimo.io/${string}`
|
|
12
13
|
| `https://docs.python.org/${string}`
|
|
13
14
|
| `https://marimo.io/${string}`
|
|
@@ -250,16 +250,6 @@ describe("AiModelRegistry", () => {
|
|
|
250
250
|
const providers = listModelsByProvider.map(([provider]) => provider);
|
|
251
251
|
expect(providers).toEqual(PROVIDER_SORT_ORDER);
|
|
252
252
|
});
|
|
253
|
-
|
|
254
|
-
it("should include custom providers at the top", () => {
|
|
255
|
-
const customModels = ["openrouter/custom-gpt"];
|
|
256
|
-
const registry = AiModelRegistry.create({ customModels });
|
|
257
|
-
const listModelsByProvider = registry.getListModelsByProvider();
|
|
258
|
-
expect(listModelsByProvider).toHaveLength(4);
|
|
259
|
-
|
|
260
|
-
const providers = listModelsByProvider.map(([provider]) => provider);
|
|
261
|
-
expect(providers).toEqual(["openrouter", ...PROVIDER_SORT_ORDER]);
|
|
262
|
-
});
|
|
263
253
|
});
|
|
264
254
|
|
|
265
255
|
describe("getCustomModels", () => {
|
|
@@ -9,6 +9,7 @@ import { displayCellName } from "@/core/cells/names";
|
|
|
9
9
|
import { isOutputEmpty } from "@/core/cells/outputs";
|
|
10
10
|
import type { OutputMessage } from "@/core/kernel/messages";
|
|
11
11
|
import type { JotaiStore } from "@/core/state/jotai";
|
|
12
|
+
import { parseHtmlContent } from "@/utils/dom";
|
|
12
13
|
import { Logger } from "@/utils/Logger";
|
|
13
14
|
import { type AIContextItem, AIContextProvider } from "../registry";
|
|
14
15
|
import { contextToXml } from "../utils";
|
|
@@ -64,24 +65,6 @@ function isMediaMimetype(
|
|
|
64
65
|
return false;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
function parseHtmlContent(htmlString: string): string {
|
|
68
|
-
try {
|
|
69
|
-
// Create a temporary DOM element to parse HTML
|
|
70
|
-
const tempDiv = document.createElement("div");
|
|
71
|
-
tempDiv.innerHTML = htmlString;
|
|
72
|
-
|
|
73
|
-
// Extract text content, removing HTML tags
|
|
74
|
-
const textContent = tempDiv.textContent || tempDiv.innerText || "";
|
|
75
|
-
|
|
76
|
-
// Clean up extra whitespace
|
|
77
|
-
return textContent.replaceAll(/\s+/g, " ").trim();
|
|
78
|
-
} catch (error) {
|
|
79
|
-
Logger.error("Error parsing HTML content:", error);
|
|
80
|
-
// If parsing fails, return the original string
|
|
81
|
-
return htmlString;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
68
|
export class CellOutputContextProvider extends AIContextProvider<CellOutputContextItem> {
|
|
86
69
|
readonly title = "Cell Outputs";
|
|
87
70
|
readonly mentionPrefix = "@";
|
package/src/core/ai/ids/ids.ts
CHANGED
|
@@ -19,6 +19,7 @@ export const PROVIDER_SORT_ORDER: ProviderId[] = [
|
|
|
19
19
|
"openai",
|
|
20
20
|
"google",
|
|
21
21
|
"github",
|
|
22
|
+
"openrouter",
|
|
22
23
|
"deepseek",
|
|
23
24
|
"azure",
|
|
24
25
|
"bedrock",
|
|
@@ -201,7 +202,7 @@ export class AiModelRegistry {
|
|
|
201
202
|
return this.modelsByProviderMap;
|
|
202
203
|
}
|
|
203
204
|
|
|
204
|
-
getListModelsByProvider():
|
|
205
|
+
getListModelsByProvider(): [ProviderId, AiModel[]][] {
|
|
205
206
|
const modelsByProvider = this.getGroupedModelsByProvider();
|
|
206
207
|
const arrayModels = [...modelsByProvider.entries()];
|
|
207
208
|
const providerToOrderIdx = getProviderMap().providerToOrderIdx;
|
package/src/core/cells/cells.ts
CHANGED
|
@@ -84,14 +84,14 @@ export interface NotebookState {
|
|
|
84
84
|
*
|
|
85
85
|
* (CodeMirror types the serialized config as any.)
|
|
86
86
|
*/
|
|
87
|
-
history:
|
|
87
|
+
history: {
|
|
88
88
|
name: string;
|
|
89
89
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
90
90
|
serializedEditorState: any;
|
|
91
91
|
column: CellColumnId;
|
|
92
92
|
index: CellIndex;
|
|
93
93
|
isSetupCell: boolean;
|
|
94
|
-
}
|
|
94
|
+
}[];
|
|
95
95
|
/**
|
|
96
96
|
* Key of cell to scroll to; typically set by actions that re-order the cell
|
|
97
97
|
* array. Call the SCROLL_TO_TARGET action to scroll to the specified cell
|
|
@@ -1128,10 +1128,10 @@ const {
|
|
|
1128
1128
|
|
|
1129
1129
|
// Find the start/end of the collapsed ranges
|
|
1130
1130
|
const nodes = [...column.nodes];
|
|
1131
|
-
const rangeIndexes:
|
|
1131
|
+
const rangeIndexes: {
|
|
1132
1132
|
start: CellIndex;
|
|
1133
1133
|
end: CellIndex;
|
|
1134
|
-
}
|
|
1134
|
+
}[] = [];
|
|
1135
1135
|
const reversedCollapseRanges = [];
|
|
1136
1136
|
|
|
1137
1137
|
// Iterate in reverse order (bottom-up) to process children first
|
|
@@ -1668,7 +1668,7 @@ export const getCellEditorView = (cellId: CellId) => {
|
|
|
1668
1668
|
|
|
1669
1669
|
export function flattenTopLevelNotebookCells(
|
|
1670
1670
|
state: NotebookState,
|
|
1671
|
-
):
|
|
1671
|
+
): (CellData & CellRuntimeState)[] {
|
|
1672
1672
|
const { cellIds, cellData, cellRuntime } = state;
|
|
1673
1673
|
return cellIds.getColumns().flatMap((column) =>
|
|
1674
1674
|
column.topLevelIds.map((cellId) => ({
|
package/src/core/cells/logs.ts
CHANGED
|
@@ -87,7 +87,7 @@ const CellLogLogger = {
|
|
|
87
87
|
? "red"
|
|
88
88
|
: "orange";
|
|
89
89
|
const status = payload.level.toUpperCase();
|
|
90
|
-
|
|
90
|
+
/** biome-ignore lint/suspicious/noConsole: for debugging */
|
|
91
91
|
console.log(
|
|
92
92
|
`%c[${status}]`,
|
|
93
93
|
`color:${color}; padding:2px 0; border-radius:2px; font-weight:bold`,
|
package/src/core/cells/types.ts
CHANGED
|
@@ -93,7 +93,7 @@ export interface CellRuntimeState {
|
|
|
93
93
|
/** TOC outline */
|
|
94
94
|
outline: Outline | null;
|
|
95
95
|
/** messages encoding the cell's console outputs. */
|
|
96
|
-
consoleOutputs:
|
|
96
|
+
consoleOutputs: WithResponse<OutputMessage>[];
|
|
97
97
|
/** current status of the cell */
|
|
98
98
|
status: RuntimeState;
|
|
99
99
|
/** whether the cell has stale inputs*/
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { python } from "@codemirror/lang-python";
|
|
4
4
|
import { EditorState } from "@codemirror/state";
|
|
5
5
|
import { EditorView } from "@codemirror/view";
|
|
6
|
+
import { atom } from "jotai";
|
|
6
7
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
8
|
import { MockRequestClient } from "@/__mocks__/requests";
|
|
8
9
|
import type { NotebookState } from "@/core/cells/cells";
|
|
@@ -34,6 +35,11 @@ vi.mock("@/core/cells/utils", () => ({
|
|
|
34
35
|
|
|
35
36
|
vi.mock("@/core/config/config", () => ({
|
|
36
37
|
getResolvedMarimoConfig: vi.fn(),
|
|
38
|
+
resolvedMarimoConfigAtom: atom({
|
|
39
|
+
display: {
|
|
40
|
+
theme: "light",
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
37
43
|
}));
|
|
38
44
|
|
|
39
45
|
const updateCellCode = vi.fn();
|
|
@@ -29,7 +29,7 @@ function createErrorDecorations(state: EditorState, errors: TracebackInfos) {
|
|
|
29
29
|
|
|
30
30
|
// Filter and sort errors by line number to ensure they're added in order
|
|
31
31
|
const relevantErrors = errors
|
|
32
|
-
.filter((error) => error.cellId === cellId)
|
|
32
|
+
.filter((error) => error.kind === "cell" && error.cellId === cellId)
|
|
33
33
|
.sort((a, b) => a.lineNumber - b.lineNumber);
|
|
34
34
|
|
|
35
35
|
for (const error of relevantErrors) {
|
|
@@ -3,14 +3,14 @@ import { foldAll, unfoldAll } from "@codemirror/language";
|
|
|
3
3
|
import type { Command, EditorView } from "@codemirror/view";
|
|
4
4
|
import type { Nullable } from "vitest";
|
|
5
5
|
|
|
6
|
-
export type BulkCommand = (targets:
|
|
6
|
+
export type BulkCommand = (targets: Nullable<EditorView>[]) => boolean;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Make a bulk command from a single {@type Command} that applies
|
|
10
10
|
* the given command to all targets.
|
|
11
11
|
*/
|
|
12
12
|
export function makeBulkCommand(command: Command) {
|
|
13
|
-
return (targets:
|
|
13
|
+
return (targets: Nullable<EditorView>[]) => {
|
|
14
14
|
let changed = false;
|
|
15
15
|
for (const target of targets) {
|
|
16
16
|
if (target) {
|
|
@@ -110,7 +110,7 @@ export const findPrev = findInDirection("prev");
|
|
|
110
110
|
*/
|
|
111
111
|
export const replaceAll = searchCommand(({ query }) => {
|
|
112
112
|
const views = getAllEditorViews();
|
|
113
|
-
const undoHandlers:
|
|
113
|
+
const undoHandlers: (() => void)[] = [];
|
|
114
114
|
for (const view of views) {
|
|
115
115
|
if (view.state.readOnly) {
|
|
116
116
|
continue;
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
languageAdapterState,
|
|
15
15
|
switchLanguage,
|
|
16
16
|
} from "../extension";
|
|
17
|
+
import { exportedForTesting as sqlValidationErrorsForTesting } from "../languages/sql/banner-validation-errors";
|
|
17
18
|
import { languageMetadataField } from "../metadata";
|
|
18
19
|
|
|
19
20
|
let view: EditorView | null = null;
|
|
@@ -258,3 +259,26 @@ describe("switchLanguage", () => {
|
|
|
258
259
|
});
|
|
259
260
|
});
|
|
260
261
|
});
|
|
262
|
+
|
|
263
|
+
describe("sqlValidationErrors", () => {
|
|
264
|
+
const { splitErrorMessage } = sqlValidationErrorsForTesting;
|
|
265
|
+
|
|
266
|
+
describe("split error message", () => {
|
|
267
|
+
it("should split the error message into error type and error message", () => {
|
|
268
|
+
const error = "SyntaxError: SELECT * FROM df";
|
|
269
|
+
const { errorType, errorMessage } = splitErrorMessage(error);
|
|
270
|
+
expect(errorType).toBe("SyntaxError");
|
|
271
|
+
expect(errorMessage).toBe("SELECT * FROM df");
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it("should handle multiple colons", () => {
|
|
275
|
+
const error =
|
|
276
|
+
"SyntaxError: SELECT * FROM df:SyntaxError: SELECT * FROM df";
|
|
277
|
+
const { errorType, errorMessage } = splitErrorMessage(error);
|
|
278
|
+
expect(errorType).toBe("SyntaxError");
|
|
279
|
+
expect(errorMessage).toBe(
|
|
280
|
+
"SELECT * FROM df:SyntaxError: SELECT * FROM df",
|
|
281
|
+
);
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { exportedForTesting } from "../languages/sql/banner-validation-errors";
|
|
5
|
+
|
|
6
|
+
describe("Error Message Splitting", () => {
|
|
7
|
+
it("should handle error message splitting correctly", () => {
|
|
8
|
+
const { splitErrorMessage } = exportedForTesting;
|
|
9
|
+
|
|
10
|
+
const result1 = splitErrorMessage("Syntax error: unexpected token");
|
|
11
|
+
expect(result1.errorType).toBe("Syntax error");
|
|
12
|
+
expect(result1.errorMessage).toBe("unexpected token");
|
|
13
|
+
|
|
14
|
+
const result2 = splitErrorMessage("Multiple: colons: in error");
|
|
15
|
+
expect(result2.errorType).toBe("Multiple");
|
|
16
|
+
expect(result2.errorMessage).toBe("colons: in error");
|
|
17
|
+
|
|
18
|
+
const result3 = splitErrorMessage("No colon error");
|
|
19
|
+
expect(result3.errorType).toBe("No colon error");
|
|
20
|
+
expect(result3.errorMessage).toBe("");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("DuckDB Error Handling", () => {
|
|
25
|
+
it("should extract codeblock from error with LINE information", () => {
|
|
26
|
+
const { handleDuckdbError } = exportedForTesting;
|
|
27
|
+
|
|
28
|
+
const error =
|
|
29
|
+
'Binder Error: Referenced column "attacks" not found in FROM clause! Candidate bindings: "Attack", "Total" LINE 1:... from pokemon WHERE \'type_2\' = 32 and attack = 32 and not attacks = \'hi\' ^';
|
|
30
|
+
|
|
31
|
+
const result = handleDuckdbError(error);
|
|
32
|
+
|
|
33
|
+
expect(result.errorType).toBe("Binder Error");
|
|
34
|
+
expect(result.errorMessage).toBe(
|
|
35
|
+
'Referenced column "attacks" not found in FROM clause! Candidate bindings: "Attack", "Total"',
|
|
36
|
+
);
|
|
37
|
+
expect(result.codeblock).toBe(
|
|
38
|
+
"LINE 1:... from pokemon WHERE 'type_2' = 32 and attack = 32 and not attacks = 'hi' ^",
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should handle error without LINE information", () => {
|
|
43
|
+
const { handleDuckdbError } = exportedForTesting;
|
|
44
|
+
|
|
45
|
+
const error = "Syntax Error: Invalid syntax near WHERE";
|
|
46
|
+
|
|
47
|
+
const result = handleDuckdbError(error);
|
|
48
|
+
|
|
49
|
+
expect(result.errorType).toBe("Syntax Error");
|
|
50
|
+
expect(result.errorMessage).toBe("Invalid syntax near WHERE");
|
|
51
|
+
expect(result.codeblock).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should handle error with LINE at the beginning", () => {
|
|
55
|
+
const { handleDuckdbError } = exportedForTesting;
|
|
56
|
+
|
|
57
|
+
const error = "LINE 1: SELECT * FROM table WHERE invalid_column = 1 ^";
|
|
58
|
+
|
|
59
|
+
const result = handleDuckdbError(error);
|
|
60
|
+
|
|
61
|
+
expect(result.errorType).toBe("LINE 1");
|
|
62
|
+
expect(result.errorMessage).toBe(
|
|
63
|
+
"SELECT * FROM table WHERE invalid_column = 1 ^",
|
|
64
|
+
);
|
|
65
|
+
expect(result.codeblock).toBeUndefined();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should handle error with multiple LINE occurrences", () => {
|
|
69
|
+
const { handleDuckdbError } = exportedForTesting;
|
|
70
|
+
|
|
71
|
+
const error =
|
|
72
|
+
"Error: Something went wrong LINE 1: SELECT * FROM table WHERE invalid_column = 1 ^";
|
|
73
|
+
|
|
74
|
+
const result = handleDuckdbError(error);
|
|
75
|
+
|
|
76
|
+
expect(result.errorType).toBe("Error");
|
|
77
|
+
expect(result.errorMessage).toBe("Something went wrong");
|
|
78
|
+
expect(result.codeblock).toBe(
|
|
79
|
+
"LINE 1: SELECT * FROM table WHERE invalid_column = 1 ^",
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should handle complex error with nested quotes", () => {
|
|
84
|
+
const { handleDuckdbError } = exportedForTesting;
|
|
85
|
+
|
|
86
|
+
const error =
|
|
87
|
+
"Binder Error: Column \"name\" not found! LINE 1: SELECT * FROM users WHERE name = 'John' AND age > 25 ^";
|
|
88
|
+
|
|
89
|
+
const result = handleDuckdbError(error);
|
|
90
|
+
|
|
91
|
+
expect(result.errorType).toBe("Binder Error");
|
|
92
|
+
expect(result.errorMessage).toBe('Column "name" not found!');
|
|
93
|
+
expect(result.codeblock).toBe(
|
|
94
|
+
"LINE 1: SELECT * FROM users WHERE name = 'John' AND age > 25 ^",
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should handle error with LINE but no caret", () => {
|
|
99
|
+
const { handleDuckdbError } = exportedForTesting;
|
|
100
|
+
|
|
101
|
+
const error = "Error: Invalid query LINE 1: SELECT * FROM table";
|
|
102
|
+
|
|
103
|
+
const result = handleDuckdbError(error);
|
|
104
|
+
|
|
105
|
+
expect(result.errorType).toBe("Error");
|
|
106
|
+
expect(result.errorMessage).toBe("Invalid query");
|
|
107
|
+
expect(result.codeblock).toBe("LINE 1: SELECT * FROM table");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should trim whitespace from codeblock", () => {
|
|
111
|
+
const { handleDuckdbError } = exportedForTesting;
|
|
112
|
+
|
|
113
|
+
const error = "Error: Something wrong LINE 1: SELECT * FROM table ^ ";
|
|
114
|
+
|
|
115
|
+
const result = handleDuckdbError(error);
|
|
116
|
+
|
|
117
|
+
expect(result.errorType).toBe("Error");
|
|
118
|
+
expect(result.errorMessage).toBe("Something wrong");
|
|
119
|
+
expect(result.codeblock).toBe("LINE 1: SELECT * FROM table ^");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should handle empty error message", () => {
|
|
123
|
+
const { handleDuckdbError } = exportedForTesting;
|
|
124
|
+
|
|
125
|
+
const error = "";
|
|
126
|
+
|
|
127
|
+
const result = handleDuckdbError(error);
|
|
128
|
+
|
|
129
|
+
expect(result.errorType).toBe("");
|
|
130
|
+
expect(result.errorMessage).toBe("");
|
|
131
|
+
expect(result.codeblock).toBeUndefined();
|
|
132
|
+
});
|
|
133
|
+
});
|