@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,10 +1,16 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
SQLTableListPreview,
|
|
4
|
+
SQLTablePreview,
|
|
5
|
+
ValidateSQLResult,
|
|
6
|
+
} from "../kernel/messages";
|
|
7
|
+
import { CachingRequestRegistry } from "../network/CachingRequestRegistry";
|
|
3
8
|
import { DeferredRequestRegistry } from "../network/DeferredRequestRegistry";
|
|
4
9
|
import { getRequestClient } from "../network/requests";
|
|
5
10
|
import type {
|
|
6
11
|
PreviewSQLTableListRequest,
|
|
7
12
|
PreviewSQLTableRequest,
|
|
13
|
+
ValidateSQLRequest,
|
|
8
14
|
} from "../network/types";
|
|
9
15
|
|
|
10
16
|
// We make a request to the backend to preview the table, passing in Engine, DB, Schema, and Table
|
|
@@ -32,3 +38,20 @@ export const PreviewSQLTableList = new DeferredRequestRegistry<
|
|
|
32
38
|
...req,
|
|
33
39
|
});
|
|
34
40
|
});
|
|
41
|
+
|
|
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(
|
|
@@ -153,6 +153,7 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
|
153
153
|
previewSQLTable = throwNotImplemented;
|
|
154
154
|
previewSQLTableList = throwNotImplemented;
|
|
155
155
|
previewDataSourceConnection = throwNotImplemented;
|
|
156
|
+
validateSQL = throwNotImplemented;
|
|
156
157
|
openFile = throwNotImplemented;
|
|
157
158
|
sendListFiles = throwNotImplemented;
|
|
158
159
|
sendSearchFiles = throwNotImplemented;
|
package/src/core/islands/main.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { renderHTML } from "@/plugins/core/RenderHTML";
|
|
|
16
16
|
import { initializePlugins } from "@/plugins/plugins";
|
|
17
17
|
import { logNever } from "@/utils/assertNever";
|
|
18
18
|
import { Functions } from "@/utils/functions";
|
|
19
|
-
import
|
|
19
|
+
import { safeExtractSetUIElementMessageBuffers } from "@/utils/json/base64";
|
|
20
20
|
import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
|
|
21
21
|
import { Logger } from "@/utils/Logger";
|
|
22
22
|
import {
|
|
@@ -119,6 +119,7 @@ export async function initialize() {
|
|
|
119
119
|
case "sql-table-list-preview":
|
|
120
120
|
case "datasets":
|
|
121
121
|
case "data-source-connections":
|
|
122
|
+
case "validate-sql-result":
|
|
122
123
|
case "secret-keys-result":
|
|
123
124
|
case "startup-logs":
|
|
124
125
|
// Unsupported
|
|
@@ -144,7 +145,7 @@ export async function initialize() {
|
|
|
144
145
|
UI_ELEMENT_REGISTRY.broadcastMessage(
|
|
145
146
|
msg.data.ui_element as UIElementId,
|
|
146
147
|
msg.data.message,
|
|
147
|
-
msg.data
|
|
148
|
+
safeExtractSetUIElementMessageBuffers(msg.data),
|
|
148
149
|
);
|
|
149
150
|
return;
|
|
150
151
|
|
|
@@ -88,9 +88,7 @@ export function parseMarimoIslandApps(): MarimoIslandApp[] {
|
|
|
88
88
|
return [...apps.values()];
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
export function createMarimoFile(app: {
|
|
92
|
-
cells: Array<{ code: string }>;
|
|
93
|
-
}): string {
|
|
91
|
+
export function createMarimoFile(app: { cells: { code: string }[] }): string {
|
|
94
92
|
const lines = [
|
|
95
93
|
"import marimo",
|
|
96
94
|
"app = marimo.App()",
|
|
@@ -24,7 +24,7 @@ export type OutputChannel = schemas["CellChannel"];
|
|
|
24
24
|
export type CellOutput = schemas["CellOutput"];
|
|
25
25
|
export type MarimoError = Extract<
|
|
26
26
|
CellOutput["data"],
|
|
27
|
-
|
|
27
|
+
{ type: string }[]
|
|
28
28
|
>[number];
|
|
29
29
|
export type OutputMessage = schemas["CellOutput"];
|
|
30
30
|
export type CompletionOption = schemas["CompletionResult"]["options"][0];
|
|
@@ -38,6 +38,7 @@ export type DataColumnPreview = OperationMessageData<"data-column-preview">;
|
|
|
38
38
|
export type SQLTablePreview = OperationMessageData<"sql-table-preview">;
|
|
39
39
|
export type SQLTableListPreview =
|
|
40
40
|
OperationMessageData<"sql-table-list-preview">;
|
|
41
|
+
export type ValidateSQLResult = OperationMessageData<"validate-sql-result">;
|
|
41
42
|
export type SecretKeysResult = OperationMessageData<"secret-keys-result">;
|
|
42
43
|
export type StartupLogs = OperationMessageData<"startup-logs">;
|
|
43
44
|
export type CellMessage = OperationMessageData<"cell-op">;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { LRUCache } from "@/utils/lru";
|
|
4
|
+
import type {
|
|
5
|
+
DeferredRequestRegistry,
|
|
6
|
+
RequestId,
|
|
7
|
+
} from "./DeferredRequestRegistry";
|
|
8
|
+
|
|
9
|
+
type ToKey<REQ> = (request: REQ) => string;
|
|
10
|
+
|
|
11
|
+
interface CachingOptions<REQ> {
|
|
12
|
+
toKey?: ToKey<REQ>;
|
|
13
|
+
maxSize?: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Light wrapper adding memoization and in-flight de-duplication on top of
|
|
18
|
+
* DeferredRequestRegistry, keyed by a string representation of the request.
|
|
19
|
+
*/
|
|
20
|
+
export class CachingRequestRegistry<REQ, RES> {
|
|
21
|
+
private delegate: DeferredRequestRegistry<REQ, RES>;
|
|
22
|
+
private toKey: ToKey<REQ>;
|
|
23
|
+
private cache: LRUCache<string, Promise<RES>>;
|
|
24
|
+
|
|
25
|
+
static jsonStringifySortKeys<T>(): ToKey<T> {
|
|
26
|
+
return (o: T) => {
|
|
27
|
+
if (typeof o !== "object" || o === null) {
|
|
28
|
+
return String(o);
|
|
29
|
+
}
|
|
30
|
+
return JSON.stringify(o, Object.keys(o).sort(), 2);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
delegate: DeferredRequestRegistry<REQ, RES>,
|
|
36
|
+
options: CachingOptions<REQ> = {},
|
|
37
|
+
) {
|
|
38
|
+
this.delegate = delegate;
|
|
39
|
+
this.toKey =
|
|
40
|
+
options.toKey ?? CachingRequestRegistry.jsonStringifySortKeys();
|
|
41
|
+
const maxSize = options.maxSize ?? 128;
|
|
42
|
+
this.cache = new LRUCache<string, Promise<RES>>(maxSize);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolve via cache if present, else delegate; de-duplicates concurrent
|
|
47
|
+
* requests with the same key and stores successful results in the cache.
|
|
48
|
+
*/
|
|
49
|
+
public request(req: REQ): Promise<RES> {
|
|
50
|
+
const key = this.toKey(req);
|
|
51
|
+
|
|
52
|
+
const cached = this.cache.get(key);
|
|
53
|
+
if (cached !== undefined) {
|
|
54
|
+
return cached;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const promise = this.delegate.request(req);
|
|
58
|
+
this.cache.set(key, promise);
|
|
59
|
+
return promise.catch((err) => {
|
|
60
|
+
this.cache.delete(key);
|
|
61
|
+
throw err;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Path through to the delegate
|
|
66
|
+
public resolve(requestId: RequestId, response: RES) {
|
|
67
|
+
this.delegate.resolve(requestId, response);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Path through to the delegate
|
|
71
|
+
public reject(requestId: RequestId, error: Error) {
|
|
72
|
+
this.delegate.reject(requestId, error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -45,7 +45,9 @@ export class DeferredRequestRegistry<REQ, RES> {
|
|
|
45
45
|
async request(opts: REQ): Promise<RES> {
|
|
46
46
|
if (this.opts.resolveExistingRequests) {
|
|
47
47
|
const result = this.opts.resolveExistingRequests();
|
|
48
|
-
|
|
48
|
+
for (const deferred of this.requests.values()) {
|
|
49
|
+
deferred.resolve(result);
|
|
50
|
+
}
|
|
49
51
|
this.requests.clear();
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { CachingRequestRegistry } from "../CachingRequestRegistry";
|
|
4
|
+
import {
|
|
5
|
+
DeferredRequestRegistry,
|
|
6
|
+
type RequestId,
|
|
7
|
+
} from "../DeferredRequestRegistry";
|
|
8
|
+
|
|
9
|
+
vi.mock("@/utils/uuid", () => ({
|
|
10
|
+
generateUUID: vi.fn().mockReturnValue("uuid"),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
describe("CachingRequestRegistry", () => {
|
|
14
|
+
const REQUEST_ID = "uuid" as RequestId;
|
|
15
|
+
let makeRequestMock = vi.fn();
|
|
16
|
+
let delegate: DeferredRequestRegistry<unknown, unknown>;
|
|
17
|
+
let caching: CachingRequestRegistry<unknown, unknown>;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
makeRequestMock = vi.fn().mockResolvedValue(undefined);
|
|
21
|
+
delegate = new DeferredRequestRegistry("operation", makeRequestMock);
|
|
22
|
+
caching = new CachingRequestRegistry(delegate);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should cache successful responses for identical requests", async () => {
|
|
26
|
+
const req = { a: 1 };
|
|
27
|
+
|
|
28
|
+
const p1 = caching.request(req);
|
|
29
|
+
expect(makeRequestMock).toHaveBeenCalledTimes(1);
|
|
30
|
+
expect(makeRequestMock).toHaveBeenCalledWith(REQUEST_ID, req);
|
|
31
|
+
|
|
32
|
+
// Resolve first request
|
|
33
|
+
delegate.resolve(REQUEST_ID, "response");
|
|
34
|
+
await expect(p1).resolves.toBe("response");
|
|
35
|
+
|
|
36
|
+
// Second call with equivalent request gets served from cache
|
|
37
|
+
const p2 = caching.request({ a: 1 });
|
|
38
|
+
expect(makeRequestMock).toHaveBeenCalledTimes(1);
|
|
39
|
+
await expect(p2).resolves.toBe("response");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should de-duplicate in-flight requests with the same key", async () => {
|
|
43
|
+
const req = { q: "select *" };
|
|
44
|
+
|
|
45
|
+
const p1 = caching.request(req);
|
|
46
|
+
const p2 = caching.request({ q: "select *" });
|
|
47
|
+
|
|
48
|
+
// Only one network invocation while in-flight
|
|
49
|
+
expect(makeRequestMock).toHaveBeenCalledTimes(1);
|
|
50
|
+
expect(p1).toStrictEqual(p2);
|
|
51
|
+
|
|
52
|
+
// Resolve and ensure both resolve to same result
|
|
53
|
+
delegate.resolve(REQUEST_ID, "ok");
|
|
54
|
+
await expect(p1).resolves.toBe("ok");
|
|
55
|
+
await expect(p2).resolves.toBe("ok");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should not cache errors", async () => {
|
|
59
|
+
// First call rejects
|
|
60
|
+
makeRequestMock.mockRejectedValueOnce(new Error("boom"));
|
|
61
|
+
|
|
62
|
+
await expect(caching.request({ x: 1 })).rejects.toThrow("boom");
|
|
63
|
+
expect(makeRequestMock).toHaveBeenCalledTimes(1);
|
|
64
|
+
|
|
65
|
+
// Next call should attempt again (not cached)
|
|
66
|
+
const p2 = caching.request({ x: 1 });
|
|
67
|
+
expect(makeRequestMock).toHaveBeenCalledTimes(2);
|
|
68
|
+
|
|
69
|
+
// Resolve the second request
|
|
70
|
+
delegate.resolve(REQUEST_ID, "ok");
|
|
71
|
+
await expect(p2).resolves.toBe("ok");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -207,6 +207,13 @@ export function createNetworkRequests(): EditRequests & RunRequests {
|
|
|
207
207
|
})
|
|
208
208
|
.then(handleResponseReturnNull);
|
|
209
209
|
},
|
|
210
|
+
validateSQL: (request) => {
|
|
211
|
+
return getClient()
|
|
212
|
+
.POST("/api/sql/validate", {
|
|
213
|
+
body: request,
|
|
214
|
+
})
|
|
215
|
+
.then(handleResponseReturnNull);
|
|
216
|
+
},
|
|
210
217
|
openFile: async (request) => {
|
|
211
218
|
await waitForConnectionOpen();
|
|
212
219
|
await getClient()
|
|
@@ -57,6 +57,7 @@ export function createStaticRequests(): EditRequests & RunRequests {
|
|
|
57
57
|
previewSQLTable: throwNotInEditMode,
|
|
58
58
|
previewSQLTableList: throwNotInEditMode,
|
|
59
59
|
previewDataSourceConnection: throwNotInEditMode,
|
|
60
|
+
validateSQL: throwNotInEditMode,
|
|
60
61
|
openFile: throwNotInEditMode,
|
|
61
62
|
getUsageStats: throwNotInEditMode,
|
|
62
63
|
sendListFiles: throwNotInEditMode,
|
|
@@ -35,6 +35,7 @@ export function createErrorToastingRequests(
|
|
|
35
35
|
previewSQLTable: "Failed to fetch SQL table",
|
|
36
36
|
previewSQLTableList: "Failed to fetch SQL table list",
|
|
37
37
|
previewDataSourceConnection: "Failed to preview data source connection",
|
|
38
|
+
validateSQL: "Failed to validate SQL",
|
|
38
39
|
openFile: "Failed to open file",
|
|
39
40
|
getUsageStats: "", // No toast
|
|
40
41
|
sendListFiles: "Failed to list files",
|
|
@@ -62,6 +62,7 @@ export type PreviewSQLTableRequest = schemas["PreviewSQLTableRequest"];
|
|
|
62
62
|
export type PreviewSQLTableListRequest = schemas["PreviewSQLTableListRequest"];
|
|
63
63
|
export type PreviewDataSourceConnectionRequest =
|
|
64
64
|
schemas["PreviewDataSourceConnectionRequest"];
|
|
65
|
+
export type ValidateSQLRequest = schemas["ValidateSQLRequest"];
|
|
65
66
|
export type PdbRequest = schemas["PdbRequest"];
|
|
66
67
|
export type ReadCodeResponse = schemas["ReadCodeResponse"];
|
|
67
68
|
export type RecentFilesResponse = schemas["RecentFilesResponse"];
|
|
@@ -140,7 +141,8 @@ export interface EditRequests {
|
|
|
140
141
|
previewDataSourceConnection: (
|
|
141
142
|
request: PreviewDataSourceConnectionRequest,
|
|
142
143
|
) => Promise<null>;
|
|
143
|
-
|
|
144
|
+
validateSQL: (request: ValidateSQLRequest) => Promise<null>;
|
|
145
|
+
openFile: (request: { path: string; lineNumber?: number }) => Promise<null>;
|
|
144
146
|
getUsageStats: () => Promise<UsageResponse>;
|
|
145
147
|
// Debugger
|
|
146
148
|
sendPdb: (request: PdbRequest) => Promise<null>;
|
|
@@ -38,11 +38,11 @@ const {
|
|
|
38
38
|
},
|
|
39
39
|
setMetadata: (
|
|
40
40
|
state,
|
|
41
|
-
metadata:
|
|
41
|
+
metadata: {
|
|
42
42
|
name: VariableName;
|
|
43
43
|
value?: string | null;
|
|
44
44
|
dataType?: string | null;
|
|
45
|
-
}
|
|
45
|
+
}[],
|
|
46
46
|
) => {
|
|
47
47
|
const newVariables = { ...state };
|
|
48
48
|
for (const { name, value, dataType } of metadata) {
|
|
@@ -13,7 +13,7 @@ import { hasAnyOutputAtom } from "../state";
|
|
|
13
13
|
|
|
14
14
|
describe("hasAnyOutputAtom", () => {
|
|
15
15
|
const createNotebookState = (
|
|
16
|
-
outputs:
|
|
16
|
+
outputs: (OutputMessage | null)[],
|
|
17
17
|
): NotebookState => ({
|
|
18
18
|
...initialNotebookState(),
|
|
19
19
|
cellIds: new MultiColumn([
|
package/src/core/wasm/bridge.ts
CHANGED
|
@@ -496,6 +496,11 @@ export class PyodideBridge implements RunRequests, EditRequests {
|
|
|
496
496
|
return null;
|
|
497
497
|
};
|
|
498
498
|
|
|
499
|
+
validateSQL: EditRequests["validateSQL"] = async (request) => {
|
|
500
|
+
await this.putControlRequest(request);
|
|
501
|
+
return null;
|
|
502
|
+
};
|
|
503
|
+
|
|
499
504
|
sendModelValue: RunRequests["sendModelValue"] = async (request) => {
|
|
500
505
|
await this.putControlRequest(request);
|
|
501
506
|
return null;
|
|
@@ -16,7 +16,10 @@ import {
|
|
|
16
16
|
} from "@/plugins/impl/anywidget/model";
|
|
17
17
|
import { logNever } from "@/utils/assertNever";
|
|
18
18
|
import { prettyError } from "@/utils/errors";
|
|
19
|
-
import
|
|
19
|
+
import {
|
|
20
|
+
type JsonString,
|
|
21
|
+
safeExtractSetUIElementMessageBuffers,
|
|
22
|
+
} from "@/utils/json/base64";
|
|
20
23
|
import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
|
|
21
24
|
import { Logger } from "@/utils/Logger";
|
|
22
25
|
import { reloadSafe } from "@/utils/reload-safe";
|
|
@@ -32,6 +35,7 @@ import type { ConnectionName } from "../datasets/engines";
|
|
|
32
35
|
import {
|
|
33
36
|
PreviewSQLTable,
|
|
34
37
|
PreviewSQLTableList,
|
|
38
|
+
ValidateSQL,
|
|
35
39
|
} from "../datasets/request-registry";
|
|
36
40
|
import { useDatasetsActions } from "../datasets/state";
|
|
37
41
|
import { UI_ELEMENT_REGISTRY } from "../dom/uiregistry";
|
|
@@ -111,7 +115,7 @@ export function useMarimoWebSocket(opts: {
|
|
|
111
115
|
const modelId = msg.data.model_id;
|
|
112
116
|
const uiElement = msg.data.ui_element;
|
|
113
117
|
const message = msg.data.message;
|
|
114
|
-
const buffers = (msg.data
|
|
118
|
+
const buffers = safeExtractSetUIElementMessageBuffers(msg.data);
|
|
115
119
|
|
|
116
120
|
if (modelId && isMessageWidgetState(message)) {
|
|
117
121
|
handleWidgetMessage({
|
|
@@ -238,6 +242,9 @@ export function useMarimoWebSocket(opts: {
|
|
|
238
242
|
case "sql-table-list-preview":
|
|
239
243
|
PreviewSQLTableList.resolve(msg.data.request_id as RequestId, msg.data);
|
|
240
244
|
return;
|
|
245
|
+
case "validate-sql-result":
|
|
246
|
+
ValidateSQL.resolve(msg.data.request_id as RequestId, msg.data);
|
|
247
|
+
return;
|
|
241
248
|
case "secret-keys-result":
|
|
242
249
|
SECRETS_REGISTRY.resolve(msg.data.request_id as RequestId, msg.data);
|
|
243
250
|
return;
|
package/src/custom.d.ts
CHANGED
|
@@ -29,7 +29,10 @@ export const useResizeHandle = ({
|
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
let width = Number.parseInt(
|
|
32
|
+
let width = Number.parseInt(
|
|
33
|
+
window.getComputedStyle(resizableDiv).width,
|
|
34
|
+
10,
|
|
35
|
+
);
|
|
33
36
|
let lastX = 0;
|
|
34
37
|
let isResizing = false;
|
|
35
38
|
let activeDirection: "left" | "right" | null = null;
|
|
@@ -89,7 +89,7 @@ const replaceSrcScripts = (domNode: DOMNode): JSX.Element | undefined => {
|
|
|
89
89
|
script.src = src;
|
|
90
90
|
document.head.append(script);
|
|
91
91
|
}
|
|
92
|
-
//
|
|
92
|
+
// biome-ignore lint/complexity/noUselessFragments: this is intentional
|
|
93
93
|
return <></>;
|
|
94
94
|
}
|
|
95
95
|
};
|
|
@@ -163,7 +163,6 @@ export const renderHTML = ({ html, additionalReplacements = [] }: Options) => {
|
|
|
163
163
|
return transformed;
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
-
// eslint-disable-next-line react/jsx-no-useless-fragment
|
|
167
166
|
return reactNode as JSX.Element;
|
|
168
167
|
},
|
|
169
168
|
});
|