@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
@@ -80,6 +80,7 @@ import { useDeleteCellCallback } from "./cell/useDeleteCell";
80
80
  import { useRunCell } from "./cell/useRunCells";
81
81
  import { HideCodeButton } from "./code/readonly-python-code";
82
82
  import { cellDomProps } from "./common";
83
+ import { SqlValidationErrorBanner } from "./errors/sql-validation-errors";
83
84
  import { useCellNavigationProps } from "./navigation/navigation";
84
85
  import {
85
86
  useTemporarilyShownCode,
@@ -450,6 +451,7 @@ const EditableCellComponent = ({
450
451
  });
451
452
  const canCollapse = canCollapseOutline(cellRuntime.outline);
452
453
  const hasOutput = !isOutputEmpty(cellRuntime.output);
454
+ const isStaleCell = outputIsStale(cellRuntime, cellData.edited);
453
455
  const hasConsoleOutput = cellRuntime.consoleOutputs.length > 0;
454
456
  const cellOutput = userConfig.display.cell_output;
455
457
 
@@ -510,7 +512,7 @@ const EditableCellComponent = ({
510
512
  className="output-area"
511
513
  cellId={cellId}
512
514
  output={cellRuntime.output}
513
- stale={outputIsStale(cellRuntime, cellData.edited)}
515
+ stale={isStaleCell}
514
516
  loading={outputIsLoading(cellRuntime.status)}
515
517
  />
516
518
  {isMarkdownCodeHidden &&
@@ -653,6 +655,10 @@ const EditableCellComponent = ({
653
655
  )}
654
656
  </div>
655
657
  </div>
658
+ <SqlValidationErrorBanner
659
+ cellId={cellId}
660
+ hide={cellRuntime.errored && !isStaleCell}
661
+ />
656
662
  {cellOutput === "below" && outputArea}
657
663
  {cellRuntime.serialization && (
658
664
  <div className="py-1 px-2 flex items-center justify-end gap-2 last:rounded-b">
@@ -16,7 +16,7 @@ export class StreamingChunkTransport<
16
16
  private onChunkReceived: (chunk: UIMessageChunk) => void;
17
17
 
18
18
  constructor(
19
- options: HttpChatTransportInitOptions<UI_MESSAGE> = {},
19
+ options: HttpChatTransportInitOptions<UI_MESSAGE>,
20
20
  onChunkReceived: (chunk: UIMessageChunk) => void,
21
21
  ) {
22
22
  super(options);
@@ -18,7 +18,7 @@ function getRootScrollableElement() {
18
18
  * React hook to find the active header in the outline
19
19
  */
20
20
  export function useActiveOutline(
21
- headerElements: Array<readonly [HTMLElement, string]>,
21
+ headerElements: (readonly [HTMLElement, string])[],
22
22
  ) {
23
23
  const [activeHeaderId, setActiveHeaderId] = useState<string | undefined>(
24
24
  undefined,
@@ -300,7 +300,7 @@ const InstallPackageForm: React.FC<{
300
300
 
301
301
  const PackagesList: React.FC<{
302
302
  onSuccess: () => void;
303
- packages: Array<{ name: string; version: string }>;
303
+ packages: { name: string; version: string }[];
304
304
  }> = ({ onSuccess, packages }) => {
305
305
  if (packages.length === 0) {
306
306
  return (
@@ -7,7 +7,7 @@ import { NotebookScopedLocalStorage } from "@/utils/localStorage";
7
7
  const BASE_KEY = "marimo:notebook-col-sizes";
8
8
 
9
9
  interface ColumnSizes {
10
- widths: Array<number | "contentWidth">;
10
+ widths: (number | "contentWidth")[];
11
11
  }
12
12
 
13
13
  function initialState(): ColumnSizes {
@@ -28,6 +28,42 @@ engine = clickhouse_connect.get_client(
28
28
  )"
29
29
  `;
30
30
 
31
+ exports[`generateDatabaseCode > basic connections > databricks 1`] = `
32
+ "import os
33
+ import sqlalchemy
34
+
35
+ _access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "my_access_token")
36
+ _server_hostname = os.environ.get("DATABRICKS_SERVER_HOSTNAME", "localhost")
37
+ _http_path = os.environ.get("DATABRICKS_HTTP_PATH", "http://localhost:8080")
38
+ DATABASE_URL = f"databricks://token:{_access_token}@{_server_hostname}?http_path={_http_path}"
39
+ engine = sqlalchemy.create_engine(DATABASE_URL)"
40
+ `;
41
+
42
+ exports[`generateDatabaseCode > basic connections > databricks with catalog and schema 1`] = `
43
+ "import os
44
+ import sqlalchemy
45
+
46
+ _access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "my_access_token")
47
+ _server_hostname = os.environ.get("DATABRICKS_SERVER_HOSTNAME", "localhost")
48
+ _http_path = os.environ.get("DATABRICKS_HTTP_PATH", "http://localhost:8080")
49
+ DATABASE_URL = f"databricks://token:{_access_token}@{_server_hostname}?http_path={_http_path}&catalog=my_catalog&schema=my_schema"
50
+ engine = sqlalchemy.create_engine(DATABASE_URL)"
51
+ `;
52
+
53
+ exports[`generateDatabaseCode > basic connections > databricks with ibis 1`] = `
54
+ "import ibis
55
+ import os
56
+
57
+ _access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "my_access_token")
58
+ _server_hostname = os.environ.get("DATABRICKS_SERVER_HOSTNAME", "localhost")
59
+ _http_path = os.environ.get("DATABRICKS_HTTP_PATH", "http://localhost:8080")
60
+ engine = ibis.databricks.connect(
61
+ server_hostname=_server_hostname,
62
+ http_path=_http_path,
63
+ access_token=_access_token
64
+ )"
65
+ `;
66
+
31
67
  exports[`generateDatabaseCode > basic connections > datafusion 1`] = `
32
68
  "from datafusion import SessionContext
33
69
  import ibis
@@ -192,8 +192,24 @@ describe("generateDatabaseCode", () => {
192
192
  },
193
193
  };
194
194
 
195
+ const databricksConnection: DatabaseConnection = {
196
+ type: "databricks",
197
+ access_token: "my_access_token",
198
+ server_hostname: "localhost",
199
+ http_path: "http://localhost:8080",
200
+ };
201
+
202
+ const databricksWithCatalogSchema: DatabaseConnection = {
203
+ type: "databricks",
204
+ access_token: "my_access_token",
205
+ server_hostname: "localhost",
206
+ http_path: "http://localhost:8080",
207
+ catalog: "my_catalog",
208
+ schema: "my_schema",
209
+ };
210
+
195
211
  describe("basic connections", () => {
196
- const testCases: Array<[string, DatabaseConnection, ConnectionLibrary]> = [
212
+ const testCases: [string, DatabaseConnection, ConnectionLibrary][] = [
197
213
  ["postgres with SQLModel", basePostgres, "sqlmodel"],
198
214
  ["postgres with SQLAlchemy", basePostgres, "sqlalchemy"],
199
215
  ["mysql with SQLModel", baseMysql, "sqlmodel"],
@@ -218,9 +234,16 @@ describe("generateDatabaseCode", () => {
218
234
  ["pyspark with session", pysparkConnSession, "ibis"],
219
235
  ["redshift with DB credentials", redshiftDBConnection, "redshift"],
220
236
  ["redshift with IAM credentials", redshiftIAMConnection, "redshift"],
237
+ ["databricks", databricksConnection, "sqlalchemy"],
238
+ [
239
+ "databricks with catalog and schema",
240
+ databricksWithCatalogSchema,
241
+ "sqlalchemy",
242
+ ],
243
+ ["databricks with ibis", databricksConnection, "ibis"],
221
244
  ];
222
245
 
223
- it.each(testCases)("%s", (name, connection, orm) => {
246
+ it.each(testCases)("%s", (_name, connection, orm) => {
224
247
  expect(generateDatabaseCode(connection, orm)).toMatchSnapshot();
225
248
  });
226
249
  });
@@ -292,7 +315,7 @@ describe("generateDatabaseCode", () => {
292
315
  },
293
316
  "duckdb",
294
317
  ],
295
- ])("%s", (name, connection, orm) => {
318
+ ])("%s", (_name, connection, orm) => {
296
319
  expect(
297
320
  generateDatabaseCode(connection, orm as ConnectionLibrary),
298
321
  ).toMatchSnapshot();
@@ -300,7 +323,7 @@ describe("generateDatabaseCode", () => {
300
323
  });
301
324
 
302
325
  describe("edge cases", () => {
303
- const testCases: Array<[string, DatabaseConnection, string]> = [
326
+ const testCases: [string, DatabaseConnection, string][] = [
304
327
  [
305
328
  "ENV with special chars SQLModel",
306
329
  {
@@ -504,7 +527,7 @@ describe("generateDatabaseCode", () => {
504
527
  ],
505
528
  ];
506
529
 
507
- it.each(testCases)("%s", (name, connection, orm) => {
530
+ it.each(testCases)("%s", (_name, connection, orm) => {
508
531
  expect(
509
532
  generateDatabaseCode(connection, orm as ConnectionLibrary),
510
533
  ).toMatchSnapshot();
@@ -548,7 +571,7 @@ describe("generateDatabaseCode", () => {
548
571
  credentials_json: '{"type": "service_account", "project_id": "test"',
549
572
  },
550
573
  ],
551
- ])("%s", (name, connection) => {
574
+ ])("%s", (_name, connection) => {
552
575
  expect(generateDatabaseCode(connection, "sqlmodel")).toMatchSnapshot();
553
576
  expect(generateDatabaseCode(connection, "sqlalchemy")).toMatchSnapshot();
554
577
  });
@@ -591,7 +614,7 @@ describe("generateDatabaseCode", () => {
591
614
  "sqlmodel",
592
615
  ),
593
616
  ],
594
- ])("%s", (name, fn) => {
617
+ ])("%s", (_name, fn) => {
595
618
  expect(fn).toThrow();
596
619
  });
597
620
  });
@@ -39,6 +39,7 @@ import {
39
39
  ChdbConnectionSchema,
40
40
  ClickhouseConnectionSchema,
41
41
  type DatabaseConnection,
42
+ DatabricksConnectionSchema,
42
43
  DataFusionConnectionSchema,
43
44
  DuckDBConnectionSchema,
44
45
  IcebergConnectionSchema,
@@ -210,6 +211,16 @@ const DATABASES = [
210
211
  preferred: "redshift",
211
212
  },
212
213
  },
214
+ {
215
+ name: "Databricks",
216
+ schema: DatabricksConnectionSchema,
217
+ color: "#c41e0c",
218
+ logo: "databricks",
219
+ connectionLibraries: {
220
+ libraries: ["sqlalchemy", "sqlmodel", "ibis"],
221
+ preferred: "sqlalchemy",
222
+ },
223
+ },
213
224
  ] satisfies ConnectionSchema[];
214
225
 
215
226
  const DATA_CATALOGS = [
@@ -14,7 +14,8 @@ export type ConnectionLibrary =
14
14
  | "pyiceberg"
15
15
  | "ibis"
16
16
  | "motherduck"
17
- | "redshift";
17
+ | "redshift"
18
+ | "databricks";
18
19
 
19
20
  export const ConnectionDisplayNames: Record<ConnectionLibrary, string> = {
20
21
  sqlmodel: "SQLModel",
@@ -26,6 +27,7 @@ export const ConnectionDisplayNames: Record<ConnectionLibrary, string> = {
26
27
  ibis: "Ibis",
27
28
  motherduck: "MotherDuck",
28
29
  redshift: "Redshift",
30
+ databricks: "Databricks",
29
31
  };
30
32
 
31
33
  abstract class CodeGenerator<T extends DatabaseConnection["type"]> {
@@ -55,6 +57,9 @@ abstract class CodeGenerator<T extends DatabaseConnection["type"]> {
55
57
  case "duckdb":
56
58
  imports.add("import duckdb");
57
59
  break;
60
+ case "ibis":
61
+ imports.add("import ibis");
62
+ break;
58
63
  }
59
64
  return imports;
60
65
  }
@@ -138,10 +143,38 @@ class SecretContainer {
138
143
  return `{${value}}`;
139
144
  }
140
145
 
146
+ /**
147
+ * Generate a password variable for connection strings, supporting inline values,
148
+ * environment variable lookups, and f-string formatting.
149
+ * @param {string|undefined} password - Fallback password value.
150
+ * @param {string} passwordPlaceholder - Environment variable name.
151
+ * @param {boolean} inFString - If true, wrap for Python f-string.
152
+ * @param {string} [variableName] - Variable name (default: "password").
153
+ * @returns {string}
154
+ *
155
+ * @example
156
+ * `printPassword("token123", "DATABRICKS_ACCESS_TOKEN", true, "access_token")`
157
+ *
158
+ * Returns:
159
+ * ```python
160
+ * _access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "token123")
161
+ * f"db://sample:{_access_token}@sample.com"
162
+ * ```
163
+ *
164
+ * @example
165
+ * `printPassword("token123", "DATABRICKS_ACCESS_TOKEN", false, "access_token")`
166
+ *
167
+ * Returns:
168
+ * ```python
169
+ * access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "token123")
170
+ * f"db://sample:access_token@sample.com"
171
+ * ```
172
+ */
141
173
  printPassword(
142
174
  password: string | undefined,
143
175
  passwordPlaceholder: string,
144
176
  inFString: boolean,
177
+ variableName?: string,
145
178
  ): string {
146
179
  // Inline passwords should use printInFString, otherwise use print
147
180
  const printMethod = inFString
@@ -149,8 +182,8 @@ class SecretContainer {
149
182
  : this.print.bind(this);
150
183
 
151
184
  return isSecret(password)
152
- ? printMethod("password", password)
153
- : printMethod("password", passwordPlaceholder, password);
185
+ ? printMethod(variableName || "password", password)
186
+ : printMethod(variableName || "password", passwordPlaceholder, password);
154
187
  }
155
188
 
156
189
  getSecrets(): Record<string, string> {
@@ -557,7 +590,7 @@ class PyIcebergGenerator extends CodeGenerator<"iceberg"> {
557
590
  class DataFusionGenerator extends CodeGenerator<"datafusion"> {
558
591
  generateImports(): string[] {
559
592
  // To trigger installation of ibis-datafusion
560
- return ["import ibis", "from datafusion import SessionContext"];
593
+ return ["from datafusion import SessionContext"];
561
594
  }
562
595
 
563
596
  generateConnectionCode(): string {
@@ -578,7 +611,7 @@ class DataFusionGenerator extends CodeGenerator<"datafusion"> {
578
611
 
579
612
  class PySparkGenerator extends CodeGenerator<"pyspark"> {
580
613
  generateImports(): string[] {
581
- return ["import ibis", "from pyspark.sql import SparkSession"];
614
+ return ["from pyspark.sql import SparkSession"];
582
615
  }
583
616
 
584
617
  generateConnectionCode(): string {
@@ -668,6 +701,70 @@ ${formatUrlParams(params, (inner) => ` ${inner}`)},
668
701
  }
669
702
  }
670
703
 
704
+ class DatabricksGenerator extends CodeGenerator<"databricks"> {
705
+ generateImports(): string[] {
706
+ return [];
707
+ }
708
+
709
+ generateConnectionCode(): string {
710
+ const useFString = this.orm !== "ibis";
711
+
712
+ const accessToken = this.secrets.printPassword(
713
+ this.connection.access_token,
714
+ "DATABRICKS_ACCESS_TOKEN",
715
+ useFString,
716
+ "access_token",
717
+ );
718
+
719
+ const serverHostname = this.secrets.printPassword(
720
+ this.connection.server_hostname,
721
+ "DATABRICKS_SERVER_HOSTNAME",
722
+ useFString,
723
+ "server_hostname",
724
+ );
725
+
726
+ const httpPath = this.secrets.printPassword(
727
+ this.connection.http_path,
728
+ "DATABRICKS_HTTP_PATH",
729
+ useFString,
730
+ "http_path",
731
+ );
732
+
733
+ const catalog = this.connection.catalog
734
+ ? this.secrets.printInFString("catalog", this.connection.catalog)
735
+ : undefined;
736
+ const schema = this.connection.schema
737
+ ? this.secrets.printInFString("schema", this.connection.schema)
738
+ : undefined;
739
+
740
+ let BASE_URL = `databricks://token:${accessToken}@${serverHostname}?http_path=${httpPath}`;
741
+ if (catalog) {
742
+ BASE_URL += `&catalog=${catalog}`;
743
+ }
744
+ if (schema) {
745
+ BASE_URL += `&schema=${schema}`;
746
+ }
747
+
748
+ if (this.orm === "ibis") {
749
+ const catalogParam = catalog ? `\n catalog=${catalog},` : "";
750
+ const schemaParam = schema ? `\n schema=${schema},` : "";
751
+
752
+ return dedent(`
753
+ engine = ibis.databricks.connect(
754
+ server_hostname=${serverHostname},
755
+ http_path=${httpPath},${catalogParam}${schemaParam}
756
+ access_token=${accessToken}
757
+ )
758
+ `);
759
+ }
760
+
761
+ return dedent(`
762
+ DATABASE_URL = f"${BASE_URL}"
763
+ engine = ${this.orm}.create_engine(DATABASE_URL)
764
+ `);
765
+ }
766
+ }
767
+
671
768
  class CodeGeneratorFactory {
672
769
  public secrets = new SecretContainer();
673
770
 
@@ -706,6 +803,8 @@ class CodeGeneratorFactory {
706
803
  return new PySparkGenerator(connection, orm, this.secrets);
707
804
  case "redshift":
708
805
  return new RedshiftGenerator(connection, orm, this.secrets);
806
+ case "databricks":
807
+ return new DatabricksGenerator(connection, orm, this.secrets);
709
808
  default:
710
809
  assertNever(connection);
711
810
  }
@@ -16,18 +16,16 @@ function passwordField() {
16
16
  );
17
17
  }
18
18
 
19
- function tokenField() {
20
- return z
21
- .string()
22
- .optional()
23
- .describe(
24
- FieldOptions.of({
25
- label: "Token",
26
- inputType: "password",
27
- placeholder: "token",
28
- optionRegex: ".*token.*",
29
- }),
30
- );
19
+ function tokenField(label?: string, required?: boolean) {
20
+ const field = z.string().describe(
21
+ FieldOptions.of({
22
+ label: label || "Token",
23
+ inputType: "password",
24
+ placeholder: "token",
25
+ optionRegex: ".*token.*",
26
+ }),
27
+ );
28
+ return required ? field.nonempty() : field.optional();
31
29
  }
32
30
 
33
31
  function warehouseNameField() {
@@ -43,20 +41,22 @@ function warehouseNameField() {
43
41
  );
44
42
  }
45
43
 
46
- function uriField() {
47
- return z
44
+ function uriField(label?: string, required?: boolean) {
45
+ const field = z
48
46
  .string()
49
- .optional()
50
- .describe(FieldOptions.of({ label: "URI", optionRegex: ".*uri.*" }));
47
+ .describe(
48
+ FieldOptions.of({ label: label || "URI", optionRegex: ".*uri.*" }),
49
+ );
50
+ return required ? field.nonempty() : field.optional();
51
51
  }
52
52
 
53
- function hostField() {
53
+ function hostField(label?: string) {
54
54
  return z
55
55
  .string()
56
56
  .nonempty()
57
57
  .describe(
58
58
  FieldOptions.of({
59
- label: "Host",
59
+ label: label || "Host",
60
60
  placeholder: "localhost",
61
61
  optionRegex: ".*host.*",
62
62
  }),
@@ -464,6 +464,23 @@ export const RedshiftConnectionSchema = z
464
464
  })
465
465
  .describe(FieldOptions.of({ direction: "two-columns" }));
466
466
 
467
+ export const DatabricksConnectionSchema = z
468
+ .object({
469
+ type: z.literal("databricks"),
470
+ access_token: tokenField("Access Token", true),
471
+ server_hostname: hostField("Server Hostname"),
472
+ http_path: uriField("HTTP Path", true),
473
+ catalog: z
474
+ .string()
475
+ .optional()
476
+ .describe(FieldOptions.of({ label: "Catalog" })),
477
+ schema: z
478
+ .string()
479
+ .optional()
480
+ .describe(FieldOptions.of({ label: "Schema" })),
481
+ })
482
+ .describe(FieldOptions.of({ direction: "two-columns" }));
483
+
467
484
  export const DatabaseConnectionSchema = z.discriminatedUnion("type", [
468
485
  PostgresConnectionSchema,
469
486
  MySQLConnectionSchema,
@@ -480,6 +497,7 @@ export const DatabaseConnectionSchema = z.discriminatedUnion("type", [
480
497
  DataFusionConnectionSchema,
481
498
  PySparkConnectionSchema,
482
499
  RedshiftConnectionSchema,
500
+ DatabricksConnectionSchema,
483
501
  ]);
484
502
 
485
503
  export type DatabaseConnection = z.infer<typeof DatabaseConnectionSchema>;
@@ -1,24 +1,33 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
2
 
3
+ import { useAtomValue, useSetAtom } from "jotai";
3
4
  import { WrenchIcon } from "lucide-react";
4
5
  import { Button } from "@/components/ui/button";
5
6
  import { Tooltip } from "@/components/ui/tooltip";
7
+ import { aiCompletionCellAtom } from "@/core/ai/state";
6
8
  import { notebookAtom, useCellActions } from "@/core/cells/cells";
7
9
  import type { CellId } from "@/core/cells/ids";
10
+ import { aiEnabledAtom } from "@/core/config/config";
8
11
  import { getAutoFixes } from "@/core/errors/errors";
9
12
  import type { MarimoError } from "@/core/kernel/messages";
10
13
  import { store } from "@/core/state/jotai";
14
+ import { cn } from "@/utils/cn";
11
15
 
12
16
  export const AutoFixButton = ({
13
17
  errors,
14
18
  cellId,
19
+ className,
15
20
  }: {
16
21
  errors: MarimoError[];
17
22
  cellId: CellId;
18
23
  className?: string;
19
24
  }) => {
20
25
  const { createNewCell } = useCellActions();
21
- const autoFixes = errors.flatMap((error) => getAutoFixes(error));
26
+ const aiEnabled = useAtomValue(aiEnabledAtom);
27
+ const autoFixes = errors.flatMap((error) =>
28
+ getAutoFixes(error, { aiEnabled }),
29
+ );
30
+ const setAiCompletionCell = useSetAtom(aiCompletionCellAtom);
22
31
 
23
32
  if (autoFixes.length === 0) {
24
33
  return null;
@@ -33,7 +42,7 @@ export const AutoFixButton = ({
33
42
  <Button
34
43
  size="xs"
35
44
  variant="outline"
36
- className="my-2 font-normal"
45
+ className={cn("my-2 font-normal", className)}
37
46
  onClick={() => {
38
47
  const editorView =
39
48
  store.get(notebookAtom).cellHandles[cellId].current?.editorView;
@@ -48,6 +57,7 @@ export const AutoFixButton = ({
48
57
  },
49
58
  editor: editorView,
50
59
  cellId: cellId,
60
+ setAiCompletionCell,
51
61
  });
52
62
  // Focus the editor
53
63
  editorView?.focus();
@@ -0,0 +1,40 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+
3
+ import { AlertCircleIcon } from "lucide-react";
4
+ import type { CellId } from "@/core/cells/ids";
5
+ import { useSqlValidationErrorsForCell } from "@/core/codemirror/language/languages/sql/banner-validation-errors";
6
+
7
+ export const SqlValidationErrorBanner = ({
8
+ cellId,
9
+ hide,
10
+ }: {
11
+ cellId: CellId;
12
+ hide: boolean;
13
+ }) => {
14
+ const error = useSqlValidationErrorsForCell(cellId);
15
+
16
+ if (!error || hide) {
17
+ return;
18
+ }
19
+
20
+ return (
21
+ <div className="p-3 text-sm flex flex-col text-muted-foreground gap-1.5 bg-destructive/4">
22
+ <div className="flex items-start gap-1.5">
23
+ <AlertCircleIcon size={13} className="mt-[3px] text-destructive" />
24
+ <p>
25
+ <span className="font-bold text-destructive">{error.errorType}:</span>{" "}
26
+ <span className="whitespace-pre-wrap">{error.errorMessage}</span>
27
+ </p>
28
+ </div>
29
+
30
+ {error.codeblock && (
31
+ <pre
32
+ lang="sql"
33
+ className="text-xs bg-muted/80 rounded p-2 pb-0 mx-3 font-medium whitespace-pre-wrap"
34
+ >
35
+ {error.codeblock}
36
+ </pre>
37
+ )}
38
+ </div>
39
+ );
40
+ };
@@ -11,9 +11,9 @@ import { Logger } from "@/utils/Logger";
11
11
  const MARIMO_CELL_MIMETYPE = "web application/x-marimo-cell";
12
12
 
13
13
  interface ClipboardCellData {
14
- cells: Array<{
14
+ cells: {
15
15
  code: string;
16
- }>;
16
+ }[];
17
17
  version: "1.0";
18
18
  }
19
19
 
@@ -14,6 +14,7 @@ import type { OutputMessage } from "@/core/kernel/messages";
14
14
  import { useSelectAllContent } from "@/hooks/useSelectAllContent";
15
15
  import { cn } from "@/utils/cn";
16
16
  import { copyToClipboard } from "@/utils/copy";
17
+ import { ansiToPlainText, parseHtmlContent } from "@/utils/dom";
17
18
  import { invariant } from "@/utils/invariant";
18
19
  import { Strings } from "@/utils/strings";
19
20
  import { NameCellContentEditable } from "../actions/name-cell-input";
@@ -27,7 +28,7 @@ interface Props {
27
28
  cellId: CellId;
28
29
  cellName: string;
29
30
  className?: string;
30
- consoleOutputs: Array<WithResponse<OutputMessage>>;
31
+ consoleOutputs: WithResponse<OutputMessage>[];
31
32
  stale: boolean;
32
33
  debuggerActive: boolean;
33
34
  onRefactorWithAI?: (opts: { prompt: string }) => void;
@@ -124,7 +125,18 @@ const ConsoleOutputInternal = (props: Props): React.ReactNode => {
124
125
  onClick={() => {
125
126
  const text = reversedOutputs
126
127
  .filter((output) => output.channel !== "pdb")
127
- .map((output) => Strings.asString(output.data))
128
+ .map((output) => {
129
+ // If starts with `<`, then assume it's HTML
130
+ if (
131
+ typeof output.data === "string" &&
132
+ output.data.startsWith("<")
133
+ ) {
134
+ return parseHtmlContent(output.data);
135
+ }
136
+
137
+ // Otherwise, convert the ANSI to HTML, then parse as HTML
138
+ return ansiToPlainText(Strings.asString(output.data));
139
+ })
128
140
  .join("\n");
129
141
  void copyToClipboard(text);
130
142
  }}
@@ -200,7 +200,7 @@ const LEAF_RENDERERS = {
200
200
  };
201
201
 
202
202
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
203
- const MIME_TYPES: Array<DataType<any>> = Object.entries(LEAF_RENDERERS).map(
203
+ const MIME_TYPES: DataType<any>[] = Object.entries(LEAF_RENDERERS).map(
204
204
  ([leafType, render]) => ({
205
205
  is: (value) => typeof value === "string" && value.startsWith(leafType),
206
206
  PostComponent: PyCopyButton,