@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.
Files changed (310) hide show
  1. package/dist/assets/{ConnectedDataExplorerComponent-2wVcyvDj.js → ConnectedDataExplorerComponent-Brtw1DxF.js} +1 -1
  2. package/dist/assets/{ImageComparisonComponent-D2j6i0hv.js → ImageComparisonComponent-Dxl-PbZX.js} +1 -1
  3. package/dist/assets/{VegaLite-BckFaf2D.js → VegaLite-BXQF0Cx_.js} +1 -1
  4. package/dist/assets/_baseEach-BjSm9ht3.js +1 -0
  5. package/dist/assets/_baseMap-CV4Ezmtf.js +1 -0
  6. package/dist/assets/_baseUniq-Ci9yZGxz.js +1 -0
  7. package/dist/assets/{_createAggregator-C5CVY-0t.js → _createAggregator-VFK9K2d9.js} +1 -1
  8. package/dist/assets/{agent-panel-RGLNjkYe.js → agent-panel-BoscVLCT.js} +7 -7
  9. package/dist/assets/{any-language-editor-DjuXwGCA.js → any-language-editor-ChaY_VUU.js} +1 -1
  10. package/dist/assets/{architectureDiagram-W76B3OCA-Dyj4ds_R.js → architectureDiagram-W76B3OCA-CueUUFYd.js} +1 -1
  11. package/dist/assets/{between-horizontal-start-Dt2aKpPf.js → between-horizontal-start-DAHqmLYT.js} +1 -1
  12. package/dist/assets/{blockDiagram-QIGZ2CNN-o-i7DDvN.js → blockDiagram-QIGZ2CNN-BYYygyWn.js} +1 -1
  13. package/dist/assets/{c4Diagram-FPNF74CW-DGHEwWrx.js → c4Diagram-FPNF74CW-DAz3xEh1.js} +1 -1
  14. package/dist/assets/channel-6SqQ2U_X.js +1 -0
  15. package/dist/assets/chat-panel-DJkOLrw9.js +3 -0
  16. package/dist/assets/{chunk-4BX2VUAB-BJecb-Ri.js → chunk-4BX2VUAB-8g-RyHdt.js} +1 -1
  17. package/dist/assets/{chunk-55IACEB6-CAATkc4w.js → chunk-55IACEB6-iWZZ8Mt6.js} +1 -1
  18. package/dist/assets/{chunk-FMBD7UC4-DPuNbQ-f.js → chunk-FMBD7UC4-knjss4wk.js} +1 -1
  19. package/dist/assets/{chunk-K7UQS3LO-C8TWVLiH.js → chunk-K7UQS3LO-DVIwPBgZ.js} +1 -1
  20. package/dist/assets/{chunk-QN33PNHL-DiZZ09q4.js → chunk-QN33PNHL-CBU8pN6I.js} +1 -1
  21. package/dist/assets/{chunk-QZHKN3VN-BIUM7usu.js → chunk-QZHKN3VN-5ljElUF4.js} +1 -1
  22. package/dist/assets/{chunk-TVAH2DTR-vGTArPBG.js → chunk-TVAH2DTR-DkIdGINc.js} +1 -1
  23. package/dist/assets/{chunk-TZMSLE5B-D2KRqp_x.js → chunk-TZMSLE5B-CIFOSTqh.js} +1 -1
  24. package/dist/assets/{circle-play-cjeNez0N.js → circle-play-BOdsbq5u.js} +1 -1
  25. package/dist/assets/classDiagram-KNZD7YFC-DVqXcTYf.js +1 -0
  26. package/dist/assets/classDiagram-v2-RKCZMP56-DVqXcTYf.js +1 -0
  27. package/dist/assets/{clear-button-C97JtAez.js → clear-button-GAjXl0CQ.js} +1 -1
  28. package/dist/assets/clone-DSDb0xen.js +1 -0
  29. package/dist/assets/command-palette-BUXkqoLh.js +1 -0
  30. package/dist/assets/{common-Du9rSOwD.js → common-DahoYqdi.js} +1 -1
  31. package/dist/assets/{compile-CZXqyOxa.js → compile-Bg8uJ7vm.js} +1 -1
  32. package/dist/assets/{cose-bilkent-S5V4N54A-CqUN5Y9b.js → cose-bilkent-S5V4N54A-z_0gqD9K.js} +1 -1
  33. package/dist/assets/{dagre-5GWH7T2D-RJqTI9DM.js → dagre-5GWH7T2D-BMt7CNXL.js} +1 -1
  34. package/dist/assets/{data-grid-overlay-editor-DZN0q1LV.js → data-grid-overlay-editor-Ctn4XtXx.js} +1 -1
  35. package/dist/assets/datasources-panel-C7sqRIHs.js +1 -0
  36. package/dist/assets/{dependency-graph-panel-CEog_O7V.js → dependency-graph-panel-DNajptzv.js} +4 -4
  37. package/dist/assets/{diagram-N5W7TBWH-D-l4zZ9d.js → diagram-N5W7TBWH-BzwvLvAy.js} +1 -1
  38. package/dist/assets/{diagram-QEK2KX5R-CCOmBUt-.js → diagram-QEK2KX5R-DRLJ56FS.js} +1 -1
  39. package/dist/assets/{diagram-S2PKOQOG-C_I_9jnZ.js → diagram-S2PKOQOG-Bf8x4KTU.js} +1 -1
  40. package/dist/assets/{documentation-panel-C1BtMZ3M.js → documentation-panel-Dm6Ozl67.js} +1 -1
  41. package/dist/assets/{edit-page-B-oevUZ9.js → edit-page-CGc9EjuG.js} +53 -42
  42. package/dist/assets/{ellipsis-vertical-BEb-J8z6.js → ellipsis-vertical-Bj1YXvZe.js} +1 -1
  43. package/dist/assets/{empty-state-C99UyDE3.js → empty-state-CYev-D31.js} +1 -1
  44. package/dist/assets/{erDiagram-AWTI2OKA-BePOLi5M.js → erDiagram-AWTI2OKA-DmgzgN_I.js} +1 -1
  45. package/dist/assets/{error-panel-Bs34jXFh.js → error-panel-BYG4twCa.js} +1 -1
  46. package/dist/assets/{file-explorer-panel-Ck6UL861.js → file-explorer-panel-BSMiOApi.js} +1 -1
  47. package/dist/assets/{flowDiagram-PVAE7QVJ-BgjFu5l7.js → flowDiagram-PVAE7QVJ-BdRKkajr.js} +1 -1
  48. package/dist/assets/{ganttDiagram-OWAHRB6G-YOPb3XSV.js → ganttDiagram-OWAHRB6G-lfRAMnq_.js} +5 -5
  49. package/dist/assets/{gitGraphDiagram-NY62KEGX-CGhqaDTy.js → gitGraphDiagram-NY62KEGX-CQVTIrHF.js} +1 -1
  50. package/dist/assets/{glide-data-editor-9QUH6iso.js → glide-data-editor-D5A4pou7.js} +4 -4
  51. package/dist/assets/{graph-DQQFGrho.js → graph-CBNo279v.js} +1 -1
  52. package/dist/assets/{home-page-DRKpPCrF.js → home-page-CmdznBJR.js} +2 -2
  53. package/dist/assets/{index-SGLNXrGP.js → index-0dfGh-Gj.js} +1 -1
  54. package/dist/assets/{index-aE43R74q.js → index-BDYVSSzB.js} +1 -1
  55. package/dist/assets/{index-BJNCMUmG.js → index-B_KyDZ94.js} +1 -1
  56. package/dist/assets/{index-BjgnbONl.js → index-Bfy-I_lW.js} +1 -1
  57. package/dist/assets/{index-CUFv_thQ.js → index-Bh98Tp-z.js} +1 -1
  58. package/dist/assets/{index-C2MD0vgD.js → index-BhroIwBL.js} +1 -1
  59. package/dist/assets/{index-DdnKZNxM.js → index-BtQtesaI.js} +1 -1
  60. package/dist/assets/index-C0iXCvyY.css +1 -0
  61. package/dist/assets/index-C1SHFMCp.js +581 -0
  62. package/dist/assets/{index-C_tkBKNO.js → index-C6DWtSls.js} +1 -1
  63. package/dist/assets/{index-Aeo6WiK7.js → index-C71cdkH-.js} +1 -1
  64. package/dist/assets/{index-G5QZppK2.js → index-CT_FTqvK.js} +1 -1
  65. package/dist/assets/{index-B8jXZ12t.js → index-CU5rRr66.js} +1 -1
  66. package/dist/assets/{index-BAbIIxHU.js → index-Cb6duXQm.js} +1 -1
  67. package/dist/assets/{index-BW3k9Gss.js → index-D23e9zQj.js} +1 -1
  68. package/dist/assets/index-DUGecC2Z.js +68 -0
  69. package/dist/assets/{index-CFKO7WXI.js → index-DcGIOAQi.js} +1 -1
  70. package/dist/assets/{index-ClzeQrN7.js → index-PJfa9qXY.js} +1 -1
  71. package/dist/assets/{index-C1ez98sk.js → index-SPslPC2B.js} +1 -1
  72. package/dist/assets/{index-BprjMYH5.js → index-VPQlo4Uz.js} +1 -1
  73. package/dist/assets/{index-CfaDbEdi.js → index-qbTLKWyG.js} +1 -1
  74. package/dist/assets/infoDiagram-STP46IZ2-DBu8p9gd.js +2 -0
  75. package/dist/assets/{isEmpty-D-4c7sMv.js → isEmpty-CnOLuQIv.js} +1 -1
  76. package/dist/assets/{journeyDiagram-BIP6EPQ6-C94u3Mv3.js → journeyDiagram-BIP6EPQ6-6U_vHJBH.js} +1 -1
  77. package/dist/assets/{kanban-definition-6OIFK2YF-BEXYFzz7.js → kanban-definition-6OIFK2YF-DgnR14ys.js} +1 -1
  78. package/dist/assets/{layout-Bz2BJ2ru.js → layout-RHmq4fP9.js} +1 -1
  79. package/dist/assets/{linear-D8s7K76e.js → linear-CLdOVPGV.js} +1 -1
  80. package/dist/assets/links-Dd1icsEk.js +7 -0
  81. package/dist/assets/{logs-panel-DC7wpmPz.js → logs-panel-CjbuhBLx.js} +1 -1
  82. package/dist/assets/{markdown-renderer-DRdSWR9X.js → markdown-renderer-X5YJvAZq.js} +3 -3
  83. package/dist/assets/{mermaid-Y3x4hmD0.js → mermaid-Bl2T5oEC.js} +1 -1
  84. package/dist/assets/{mermaid.core-DzthE35Y.js → mermaid.core-CfukBvGI.js} +4 -4
  85. package/dist/assets/min-BXIes1Za.js +1 -0
  86. package/dist/assets/{mindmap-definition-Q6HEUPPD-DktvuLe1.js → mindmap-definition-Q6HEUPPD-BXCjP4Lu.js} +1 -1
  87. package/dist/assets/{number-overlay-editor-BEfwI1IT.js → number-overlay-editor-BUyqkSes.js} +1 -1
  88. package/dist/assets/{outline-panel-CdsnAy2w.js → outline-panel-BvGcPKdd.js} +1 -1
  89. package/dist/assets/{packages-panel-DiTA-d_D.js → packages-panel-BichDQWG.js} +1 -1
  90. package/dist/assets/{pieDiagram-ADFJNKIX-DQDNQ-de.js → pieDiagram-ADFJNKIX-CMzJFIJM.js} +1 -1
  91. package/dist/assets/{quadrantDiagram-LMRXKWRM-0kgIXc2-.js → quadrantDiagram-LMRXKWRM-CfGssUlO.js} +1 -1
  92. package/dist/assets/{react-plotly-DJqqfM7c.js → react-plotly-DR3hV0HW.js} +1 -1
  93. package/dist/assets/{requirementDiagram-4UW4RH46-B5rb0ypd.js → requirementDiagram-4UW4RH46-CfrFolth.js} +1 -1
  94. package/dist/assets/{run-page-CFmLrv1R.js → run-page-Bqd_4ePD.js} +1 -1
  95. package/dist/assets/{sankeyDiagram-GR3RE2ED-Dom7IlnF.js → sankeyDiagram-GR3RE2ED-D_UttKU0.js} +1 -1
  96. package/dist/assets/{scratchpad-panel-CuHWpHO8.js → scratchpad-panel-D5N15ji1.js} +1 -1
  97. package/dist/assets/secrets-panel-BpbnAO4R.js +1 -0
  98. package/dist/assets/{sequenceDiagram-C3RYC4MD-PNJWXQbw.js → sequenceDiagram-C3RYC4MD-MdfQQApP.js} +1 -1
  99. package/dist/assets/{slides-component-CJgaTRZ0.js → slides-component-C0z7rXmk.js} +1 -1
  100. package/dist/assets/{snippets-panel-B2EC1txM.js → snippets-panel-wlpZ_Wzx.js} +1 -1
  101. package/dist/assets/sortBy-BW_zNHP6.js +1 -0
  102. package/dist/assets/{state-CWict9RU.js → state-CDooX-dk.js} +1 -1
  103. package/dist/assets/{stateDiagram-KXAO66HF-BE58aJnr.js → stateDiagram-KXAO66HF-H7kfw3ot.js} +1 -1
  104. package/dist/assets/stateDiagram-v2-UMBNRL4Z-YMeb9qMR.js +1 -0
  105. package/dist/assets/{storage-DRaR04wR.js → storage-b1QCapTq.js} +6 -6
  106. package/dist/assets/{terminal-BX3Su5q7.js → terminal-CPV44BXz.js} +1 -1
  107. package/dist/assets/{time-hUzZfpNE.js → time-DDy3xv5Y.js} +1 -1
  108. package/dist/assets/{timeline-definition-XQNQX7LJ-CqQP9t51.js → timeline-definition-XQNQX7LJ-J-cPRT2_.js} +1 -1
  109. package/dist/assets/{tracing-B10Q1n-L.js → tracing-3eHHRUiJ.js} +2 -2
  110. package/dist/assets/{tracing-panel-Du8WCnno.js → tracing-panel-BMgy3D7d.js} +2 -2
  111. package/dist/assets/{trash-B81GTiv6.js → trash--tonOuDe.js} +1 -1
  112. package/dist/assets/{tree-6vW2ogkh.js → tree-ouIGEsVg.js} +1 -1
  113. package/dist/assets/{treemap-75Q7IDZK-CdwDwwsz.js → treemap-75Q7IDZK-CzJTJ_3R.js} +20 -20
  114. package/dist/assets/{variable-panel-D5qgJI7k.js → variable-panel-sFTn4Oih.js} +1 -1
  115. package/dist/assets/{vega-component-DJaJWMJM.js → vega-component-BkPkzX9r.js} +1 -1
  116. package/dist/assets/{xychartDiagram-6GGTOJPD-WFtXqaM9.js → xychartDiagram-6GGTOJPD-BZ8WOb_8.js} +1 -1
  117. package/dist/index.html +10 -3
  118. package/package.json +8 -8
  119. package/src/__mocks__/common.ts +5 -3
  120. package/src/__mocks__/notebook.ts +2 -2
  121. package/src/__mocks__/requests.ts +1 -0
  122. package/src/__tests__/main.test.tsx +2 -2
  123. package/src/components/ai/ai-provider-icon.tsx +2 -0
  124. package/src/components/app-config/ai-config.tsx +32 -1
  125. package/src/components/app-config/common.tsx +2 -2
  126. package/src/components/app-config/user-config-form.tsx +26 -0
  127. package/src/components/audio/audio-recorder.tsx +0 -1
  128. package/src/components/chat/acp/blocks.tsx +2 -2
  129. package/src/components/chat/acp/thread.tsx +3 -5
  130. package/src/components/chat/acp/utils.ts +5 -5
  131. package/src/components/chat/chat-panel.tsx +1 -1
  132. package/src/components/data-table/__tests__/columns.test.tsx +38 -0
  133. package/src/components/data-table/__tests__/data-table.test.tsx +2 -2
  134. package/src/components/data-table/cell-hover-template/feature.ts +1 -1
  135. package/src/components/data-table/cell-hover-template/types.ts +1 -1
  136. package/src/components/data-table/charts/__tests__/altair-generator.test.ts +1 -1
  137. package/src/components/data-table/charts/chart-spec/tooltips.ts +3 -3
  138. package/src/components/data-table/charts/components/chart-items.tsx +1 -1
  139. package/src/components/data-table/charts/components/form-fields.tsx +2 -2
  140. package/src/components/data-table/charts/constants.ts +1 -1
  141. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  142. package/src/components/data-table/column-summary/chart-spec-model.tsx +2 -2
  143. package/src/components/data-table/columns.tsx +22 -3
  144. package/src/components/data-table/data-table.tsx +35 -3
  145. package/src/components/data-table/date-popover.tsx +1 -1
  146. package/src/components/data-table/download-actions.tsx +1 -1
  147. package/src/components/data-table/range-focus/__tests__/utils.test.ts +5 -5
  148. package/src/components/data-table/renderers.tsx +22 -13
  149. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +1 -1
  150. package/src/components/data-table/schemas.ts +16 -0
  151. package/src/components/data-table/types.ts +4 -3
  152. package/src/components/datasources/column-preview.tsx +9 -6
  153. package/src/components/debugger/debugger-code.tsx +1 -1
  154. package/src/components/dependency-graph/custom-node.tsx +15 -6
  155. package/src/components/dependency-graph/dependency-graph-minimap.tsx +2 -2
  156. package/src/components/dependency-graph/dependency-graph-tree.tsx +2 -2
  157. package/src/components/dependency-graph/dependency-graph.tsx +1 -1
  158. package/src/components/dependency-graph/elements.ts +7 -7
  159. package/src/components/dependency-graph/utils/changes.ts +4 -4
  160. package/src/components/editor/Cell.tsx +7 -1
  161. package/src/components/editor/ai/transport/chat-transport.tsx +1 -1
  162. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +1 -1
  163. package/src/components/editor/chrome/panels/packages-panel.tsx +1 -1
  164. package/src/components/editor/columns/storage.ts +1 -1
  165. package/src/components/editor/database/__tests__/__snapshots__/as-code.test.ts.snap +36 -0
  166. package/src/components/editor/database/__tests__/as-code.test.ts +30 -7
  167. package/src/components/editor/database/add-database-form.tsx +11 -0
  168. package/src/components/editor/database/as-code.ts +104 -5
  169. package/src/components/editor/database/schemas.ts +36 -18
  170. package/src/components/editor/errors/auto-fix.tsx +12 -2
  171. package/src/components/editor/errors/sql-validation-errors.tsx +40 -0
  172. package/src/components/editor/navigation/clipboard.ts +2 -2
  173. package/src/components/editor/output/ConsoleOutput.tsx +14 -2
  174. package/src/components/editor/output/JsonOutput.tsx +1 -1
  175. package/src/components/editor/output/MarimoErrorOutput.tsx +60 -1
  176. package/src/components/editor/output/MarimoTracebackOutput.tsx +17 -2
  177. package/src/components/editor/renderers/grid-layout/types.ts +2 -2
  178. package/src/components/editor/renderers/plugins.ts +1 -1
  179. package/src/components/editor/renderers/types.ts +1 -1
  180. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +7 -7
  181. package/src/components/forms/form.tsx +5 -5
  182. package/src/components/ui/links.tsx +1 -0
  183. package/src/core/ai/__tests__/model-registry.test.ts +0 -10
  184. package/src/core/ai/context/providers/cell-output.ts +1 -18
  185. package/src/core/ai/context/providers/error.ts +2 -2
  186. package/src/core/ai/ids/ids.ts +1 -0
  187. package/src/core/ai/model-registry.ts +2 -1
  188. package/src/core/cells/cells.ts +5 -5
  189. package/src/core/cells/logs.ts +1 -1
  190. package/src/core/cells/types.ts +1 -1
  191. package/src/core/codemirror/__tests__/format.test.ts +6 -0
  192. package/src/core/codemirror/cells/traceback-decorations.ts +1 -1
  193. package/src/core/codemirror/editing/commands.ts +2 -2
  194. package/src/core/codemirror/find-replace/navigate.ts +1 -1
  195. package/src/core/codemirror/language/__tests__/extension.test.ts +24 -0
  196. package/src/core/codemirror/language/__tests__/sql-validation.test.ts +133 -0
  197. package/src/core/codemirror/language/__tests__/sql.test.ts +764 -79
  198. package/src/core/codemirror/language/languages/markdown.ts +4 -1
  199. package/src/core/codemirror/language/languages/sql/banner-validation-errors.ts +85 -0
  200. package/src/core/codemirror/language/languages/sql/completion-builder.ts +160 -0
  201. package/src/core/codemirror/language/languages/sql/completion-sources.tsx +9 -3
  202. package/src/core/codemirror/language/languages/sql/completion-store.ts +46 -50
  203. package/src/core/codemirror/language/languages/sql/renderers.tsx +485 -0
  204. package/src/core/codemirror/language/languages/sql/sql-mode.ts +20 -0
  205. package/src/core/codemirror/language/languages/sql/sql.ts +218 -4
  206. package/src/core/codemirror/language/languages/sql/utils.ts +4 -1
  207. package/src/core/codemirror/language/panel/panel.tsx +8 -2
  208. package/src/core/codemirror/language/panel/sql.tsx +86 -4
  209. package/src/core/codemirror/language/utils/ast.ts +3 -3
  210. package/src/core/codemirror/lsp/federated-lsp.ts +4 -4
  211. package/src/core/codemirror/lsp/lens.ts +4 -4
  212. package/src/core/codemirror/lsp/notebook-lsp.ts +1 -1
  213. package/src/core/codemirror/lsp/types.ts +1 -1
  214. package/src/core/codemirror/markdown/completions.ts +1 -1
  215. package/src/core/codemirror/reactive-references/analyzer.ts +2 -2
  216. package/src/core/codemirror/rtc/loro/awareness.ts +1 -1
  217. package/src/core/config/config-schema.ts +1 -0
  218. package/src/core/config/feature-flag.tsx +6 -2
  219. package/src/core/datasets/request-registry.ts +24 -1
  220. package/src/core/dom/events.ts +1 -1
  221. package/src/core/dom/outline.ts +2 -2
  222. package/src/core/dom/uiregistry.ts +2 -8
  223. package/src/core/errors/__tests__/errors.test.ts +22 -4
  224. package/src/core/errors/errors.ts +29 -1
  225. package/src/core/errors/state.ts +1 -1
  226. package/src/core/islands/bridge.ts +1 -0
  227. package/src/core/islands/main.ts +3 -2
  228. package/src/core/islands/parse.ts +1 -3
  229. package/src/core/kernel/messages.ts +2 -1
  230. package/src/core/network/CachingRequestRegistry.ts +74 -0
  231. package/src/core/network/DeferredRequestRegistry.ts +3 -1
  232. package/src/core/network/__tests__/CachingRequestRegistry.test.ts +73 -0
  233. package/src/core/network/requests-network.ts +7 -0
  234. package/src/core/network/requests-static.ts +1 -0
  235. package/src/core/network/requests-toasting.ts +1 -0
  236. package/src/core/network/types.ts +3 -1
  237. package/src/core/variables/state.ts +2 -2
  238. package/src/core/wasm/__tests__/state.test.ts +1 -1
  239. package/src/core/wasm/bridge.ts +5 -0
  240. package/src/core/websocket/useMarimoWebSocket.tsx +9 -2
  241. package/src/custom.d.ts +1 -1
  242. package/src/hooks/useCellRenderCount.ts +1 -0
  243. package/src/hooks/useResizeHandle.ts +4 -1
  244. package/src/plugins/core/RenderHTML.tsx +1 -2
  245. package/src/plugins/core/registerReactComponent.tsx +23 -19
  246. package/src/plugins/impl/DataTablePlugin.tsx +18 -6
  247. package/src/plugins/impl/FileUploadPlugin.tsx +1 -1
  248. package/src/plugins/impl/RefreshPlugin.tsx +1 -1
  249. package/src/plugins/impl/SliderPlugin.tsx +4 -0
  250. package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +27 -9
  251. package/src/plugins/impl/anywidget/__tests__/AnyWidgetPlugin.test.tsx +58 -2
  252. package/src/plugins/impl/anywidget/__tests__/model.test.ts +3 -4
  253. package/src/plugins/impl/anywidget/model.ts +2 -3
  254. package/src/plugins/impl/data-editor/types.ts +1 -1
  255. package/src/plugins/impl/data-explorer/components/query-form.tsx +1 -1
  256. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +17 -5
  257. package/src/plugins/impl/data-frames/types.ts +1 -1
  258. package/src/plugins/impl/panel/PanelPlugin.tsx +2 -2
  259. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +3 -3
  260. package/src/plugins/impl/vega/__tests__/loader.test.ts +2 -2
  261. package/src/plugins/impl/vega/loader.ts +1 -1
  262. package/src/plugins/impl/vega/vega-component.tsx +1 -1
  263. package/src/plugins/impl/vega/vega-loader.ts +2 -2
  264. package/src/plugins/layout/NavigationMenuPlugin.tsx +1 -1
  265. package/src/plugins/layout/RoutesPlugin.tsx +1 -2
  266. package/src/plugins/plugins.ts +2 -2
  267. package/src/stories/dataframe.stories.tsx +2 -0
  268. package/src/utils/Logger.ts +1 -1
  269. package/src/utils/__tests__/data-views.test.ts +30 -68
  270. package/src/utils/__tests__/dom.test.ts +167 -0
  271. package/src/utils/__tests__/id-tree.test.ts +49 -1
  272. package/src/utils/__tests__/storage.test.ts +1 -1
  273. package/src/utils/__tests__/traceback.test.ts +13 -2
  274. package/src/utils/arrays.ts +1 -1
  275. package/src/utils/createReducer.ts +1 -5
  276. package/src/utils/data-views.ts +6 -19
  277. package/src/utils/dom.ts +55 -0
  278. package/src/utils/edit-distance.ts +1 -1
  279. package/src/utils/fileToBase64.ts +1 -1
  280. package/src/utils/id-tree.tsx +20 -18
  281. package/src/utils/json/base64.ts +13 -0
  282. package/src/utils/json/json-parser.ts +2 -2
  283. package/src/utils/lru.ts +4 -0
  284. package/src/utils/mergeRefs.ts +1 -1
  285. package/src/utils/objects.ts +3 -3
  286. package/src/utils/pluralize.ts +1 -1
  287. package/src/utils/routes.ts +2 -2
  288. package/src/utils/sets.ts +1 -1
  289. package/src/utils/traceback.ts +45 -15
  290. package/src/utils/tracer.ts +11 -9
  291. package/dist/assets/_baseEach-CvTX9w0Y.js +0 -1
  292. package/dist/assets/_baseMap-CtlwA90f.js +0 -1
  293. package/dist/assets/_baseUniq-BKktIGQ1.js +0 -1
  294. package/dist/assets/channel-Co6iMgWq.js +0 -1
  295. package/dist/assets/chat-panel-9alr8FS4.js +0 -3
  296. package/dist/assets/classDiagram-KNZD7YFC-BbJ0rY3y.js +0 -1
  297. package/dist/assets/classDiagram-v2-RKCZMP56-BbJ0rY3y.js +0 -1
  298. package/dist/assets/clone-BMP0PsTa.js +0 -1
  299. package/dist/assets/command-palette-B93Pjcky.js +0 -1
  300. package/dist/assets/datasources-panel-v7H3cR0p.js +0 -1
  301. package/dist/assets/index-2252nrk6.js +0 -68
  302. package/dist/assets/index-C7CoaNFb.js +0 -578
  303. package/dist/assets/index-DadI618h.css +0 -1
  304. package/dist/assets/infoDiagram-STP46IZ2-CJLOpSAf.js +0 -2
  305. package/dist/assets/links-BpXlz1GG.js +0 -7
  306. package/dist/assets/min-BBO3-1Hg.js +0 -1
  307. package/dist/assets/secrets-panel-CfHc5YD0.js +0 -1
  308. package/dist/assets/sortBy-DZnlX29-.js +0 -1
  309. package/dist/assets/stateDiagram-v2-UMBNRL4Z-CdThjimL.js +0 -1
  310. package/src/__tests__/lru.test.ts +0 -74
@@ -1,10 +1,16 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
- import type { SQLTableListPreview, SQLTablePreview } from "../kernel/messages";
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
+ );
@@ -43,7 +43,7 @@ export const MarimoIncomingMessageEvent = defineCustomEvent(
43
43
  )<{
44
44
  objectId: UIElementId;
45
45
  message: unknown;
46
- buffers: DataView[] | undefined;
46
+ buffers: readonly DataView[];
47
47
  }>();
48
48
  export type MarimoIncomingMessageEventType = ReturnType<
49
49
  typeof MarimoIncomingMessageEvent.create
@@ -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: Array<Outline | null>): Outline {
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: Array<Outline | null>,
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: Base64String[] | undefined | null,
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 ? buffers.map(toDataView) : undefined,
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(error: MarimoError): AutoFix[] {
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
 
@@ -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: Array<Identified<Banner>>;
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;
@@ -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 type { Base64String } from "@/utils/json/base64";
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.buffers as Base64String[],
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
- Array<{ type: string }>
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
- this.requests.forEach((deferred) => deferred.resolve(result));
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
- openFile: (request: { path: string }) => Promise<null>;
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: Array<{
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: Array<OutputMessage | null>,
16
+ outputs: (OutputMessage | null)[],
17
17
  ): NotebookState => ({
18
18
  ...initialNotebookState(),
19
19
  cellIds: new MultiColumn([
@@ -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 type { Base64String, JsonString } from "@/utils/json/base64";
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.buffers ?? []) as Base64String[];
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
@@ -20,5 +20,5 @@ interface JSON {
20
20
 
21
21
  // Improve type inference for Array.filter with BooleanConstructor
22
22
  interface Array<T> {
23
- filter(predicate: BooleanConstructor): Array<NonNullable<T>>;
23
+ filter(predicate: BooleanConstructor): NonNullable<T>[];
24
24
  }
@@ -8,6 +8,7 @@ export function useCellRenderCount() {
8
8
 
9
9
  const currentCount = Number.parseInt(
10
10
  document.body.dataset.cellRenderCount || "0",
11
+ 10,
11
12
  );
12
13
  document.body.dataset.cellRenderCount = (currentCount + 1).toString();
13
14
  },
@@ -29,7 +29,10 @@ export const useResizeHandle = ({
29
29
  return;
30
30
  }
31
31
 
32
- let width = Number.parseInt(window.getComputedStyle(resizableDiv).width);
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
- // eslint-disable-next-line react/jsx-no-useless-fragment
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
  });