@marimo-team/frontend 0.16.2 → 0.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/dist/assets/{ConnectedDataExplorerComponent-B5cPvWoQ.js → ConnectedDataExplorerComponent-Brtw1DxF.js} +1 -1
  2. package/dist/assets/{ImageComparisonComponent-CqR26LSv.js → ImageComparisonComponent-Dxl-PbZX.js} +1 -1
  3. package/dist/assets/{VegaLite-DvQDATwI.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-ZcHkHPNJ.js → _createAggregator-VFK9K2d9.js} +1 -1
  8. package/dist/assets/{agent-panel-B91RoLct.js → agent-panel-BoscVLCT.js} +7 -7
  9. package/dist/assets/{any-language-editor-CxfHcm5h.js → any-language-editor-ChaY_VUU.js} +1 -1
  10. package/dist/assets/{architectureDiagram-W76B3OCA-BQsvK8uR.js → architectureDiagram-W76B3OCA-CueUUFYd.js} +1 -1
  11. package/dist/assets/{between-horizontal-start-BmYToIaM.js → between-horizontal-start-DAHqmLYT.js} +1 -1
  12. package/dist/assets/{blockDiagram-QIGZ2CNN-r3HgCj4w.js → blockDiagram-QIGZ2CNN-BYYygyWn.js} +1 -1
  13. package/dist/assets/{c4Diagram-FPNF74CW-BJbPNt41.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-Dv4MZ9Hj.js → chunk-4BX2VUAB-8g-RyHdt.js} +1 -1
  17. package/dist/assets/{chunk-55IACEB6-CM4AHquB.js → chunk-55IACEB6-iWZZ8Mt6.js} +1 -1
  18. package/dist/assets/{chunk-FMBD7UC4-C_Zz0ENB.js → chunk-FMBD7UC4-knjss4wk.js} +1 -1
  19. package/dist/assets/{chunk-K7UQS3LO-DYSmiXYq.js → chunk-K7UQS3LO-DVIwPBgZ.js} +1 -1
  20. package/dist/assets/{chunk-QN33PNHL-QM4OPuQP.js → chunk-QN33PNHL-CBU8pN6I.js} +1 -1
  21. package/dist/assets/{chunk-QZHKN3VN-CfAsGyeB.js → chunk-QZHKN3VN-5ljElUF4.js} +1 -1
  22. package/dist/assets/{chunk-TVAH2DTR-6j_Cpjsi.js → chunk-TVAH2DTR-DkIdGINc.js} +1 -1
  23. package/dist/assets/{chunk-TZMSLE5B-BHslFJQE.js → chunk-TZMSLE5B-CIFOSTqh.js} +1 -1
  24. package/dist/assets/{circle-play-CK3UZRYQ.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-C4fDVSv8.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-D-lbuUwz.js → common-DahoYqdi.js} +1 -1
  31. package/dist/assets/{compile-DVQe1Mzk.js → compile-Bg8uJ7vm.js} +1 -1
  32. package/dist/assets/{cose-bilkent-S5V4N54A-D-IS7WC8.js → cose-bilkent-S5V4N54A-z_0gqD9K.js} +1 -1
  33. package/dist/assets/{dagre-5GWH7T2D-lYu-tEWT.js → dagre-5GWH7T2D-BMt7CNXL.js} +1 -1
  34. package/dist/assets/{data-grid-overlay-editor-C5peOCit.js → data-grid-overlay-editor-Ctn4XtXx.js} +1 -1
  35. package/dist/assets/{datasources-panel-D3NA20uZ.js → datasources-panel-C7sqRIHs.js} +1 -1
  36. package/dist/assets/{dependency-graph-panel-BGVYOfkV.js → dependency-graph-panel-DNajptzv.js} +4 -4
  37. package/dist/assets/{diagram-N5W7TBWH-BnvIuYUp.js → diagram-N5W7TBWH-BzwvLvAy.js} +1 -1
  38. package/dist/assets/{diagram-QEK2KX5R-DemedRK3.js → diagram-QEK2KX5R-DRLJ56FS.js} +1 -1
  39. package/dist/assets/{diagram-S2PKOQOG-iiY7AuyH.js → diagram-S2PKOQOG-Bf8x4KTU.js} +1 -1
  40. package/dist/assets/{documentation-panel-C3dSwOSQ.js → documentation-panel-Dm6Ozl67.js} +1 -1
  41. package/dist/assets/edit-page-CGc9EjuG.js +140 -0
  42. package/dist/assets/{ellipsis-vertical-CazJl8M7.js → ellipsis-vertical-Bj1YXvZe.js} +1 -1
  43. package/dist/assets/{empty-state-DW308mFO.js → empty-state-CYev-D31.js} +1 -1
  44. package/dist/assets/{erDiagram-AWTI2OKA-6wQ8Ugg0.js → erDiagram-AWTI2OKA-DmgzgN_I.js} +1 -1
  45. package/dist/assets/{error-panel-D1VnJ1yP.js → error-panel-BYG4twCa.js} +1 -1
  46. package/dist/assets/{file-explorer-panel-0oVd4t-D.js → file-explorer-panel-BSMiOApi.js} +1 -1
  47. package/dist/assets/{flowDiagram-PVAE7QVJ-C55IUWjm.js → flowDiagram-PVAE7QVJ-BdRKkajr.js} +1 -1
  48. package/dist/assets/{ganttDiagram-OWAHRB6G-DmqCM6ME.js → ganttDiagram-OWAHRB6G-lfRAMnq_.js} +5 -5
  49. package/dist/assets/{gitGraphDiagram-NY62KEGX-DBvhAeM_.js → gitGraphDiagram-NY62KEGX-CQVTIrHF.js} +1 -1
  50. package/dist/assets/{glide-data-editor-CHNuHidQ.js → glide-data-editor-D5A4pou7.js} +11 -11
  51. package/dist/assets/{graph-CG6BgUWQ.js → graph-CBNo279v.js} +1 -1
  52. package/dist/assets/{home-page-dgivXuSR.js → home-page-CmdznBJR.js} +3 -3
  53. package/dist/assets/{index-BTGpssVX.js → index-0dfGh-Gj.js} +1 -1
  54. package/dist/assets/{index-C7dtgr9A.js → index-BDYVSSzB.js} +1 -1
  55. package/dist/assets/{index-C02SqeRj.js → index-B_KyDZ94.js} +1 -1
  56. package/dist/assets/{index-mkubqy9-.js → index-Bfy-I_lW.js} +1 -1
  57. package/dist/assets/{index-BelfnXwL.js → index-Bh98Tp-z.js} +1 -1
  58. package/dist/assets/{index-CAQvMTzM.js → index-BhroIwBL.js} +1 -1
  59. package/dist/assets/{index-BneyUujp.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-Csd6QrCV.js → index-C6DWtSls.js} +1 -1
  63. package/dist/assets/{index-BYVZlBF8.js → index-C71cdkH-.js} +1 -1
  64. package/dist/assets/{index-z4krxQ4j.js → index-CT_FTqvK.js} +1 -1
  65. package/dist/assets/{index-Db36XTG_.js → index-CU5rRr66.js} +1 -1
  66. package/dist/assets/{index-CtPksxf0.js → index-Cb6duXQm.js} +1 -1
  67. package/dist/assets/{index-DAZ-9ri2.js → index-D23e9zQj.js} +1 -1
  68. package/dist/assets/index-DUGecC2Z.js +68 -0
  69. package/dist/assets/{index-M_pBKDSe.js → index-DcGIOAQi.js} +1 -1
  70. package/dist/assets/{index-DONRrmA2.js → index-PJfa9qXY.js} +1 -1
  71. package/dist/assets/{index-sbO9UaUU.js → index-SPslPC2B.js} +1 -1
  72. package/dist/assets/{index-DdIhdEVw.js → index-VPQlo4Uz.js} +1 -1
  73. package/dist/assets/{index-_luCZMLM.js → index-qbTLKWyG.js} +1 -1
  74. package/dist/assets/infoDiagram-STP46IZ2-DBu8p9gd.js +2 -0
  75. package/dist/assets/{isEmpty-CqX_YTIf.js → isEmpty-CnOLuQIv.js} +1 -1
  76. package/dist/assets/{journeyDiagram-BIP6EPQ6-Y5w_Tqe_.js → journeyDiagram-BIP6EPQ6-6U_vHJBH.js} +1 -1
  77. package/dist/assets/{kanban-definition-6OIFK2YF-DbXs5Rxi.js → kanban-definition-6OIFK2YF-DgnR14ys.js} +1 -1
  78. package/dist/assets/{layout-BCNPDACj.js → layout-RHmq4fP9.js} +1 -1
  79. package/dist/assets/{linear-uO6UVhXt.js → linear-CLdOVPGV.js} +1 -1
  80. package/dist/assets/links-Dd1icsEk.js +7 -0
  81. package/dist/assets/{logs-panel-BEQ1eRUp.js → logs-panel-CjbuhBLx.js} +1 -1
  82. package/dist/assets/{markdown-renderer-Dmzbb00W.js → markdown-renderer-X5YJvAZq.js} +3 -3
  83. package/dist/assets/{mermaid-qRc4MXIj.js → mermaid-Bl2T5oEC.js} +1 -1
  84. package/dist/assets/{mermaid.core-CvvJtCRj.js → mermaid.core-CfukBvGI.js} +4 -4
  85. package/dist/assets/min-BXIes1Za.js +1 -0
  86. package/dist/assets/{mindmap-definition-Q6HEUPPD-G5NognM-.js → mindmap-definition-Q6HEUPPD-BXCjP4Lu.js} +1 -1
  87. package/dist/assets/{number-overlay-editor-DPr5sHFu.js → number-overlay-editor-BUyqkSes.js} +1 -1
  88. package/dist/assets/{outline-panel-gxQXvVi4.js → outline-panel-BvGcPKdd.js} +1 -1
  89. package/dist/assets/{packages-panel-B1T0VPlg.js → packages-panel-BichDQWG.js} +1 -1
  90. package/dist/assets/{pieDiagram-ADFJNKIX-DK9SHkfc.js → pieDiagram-ADFJNKIX-CMzJFIJM.js} +1 -1
  91. package/dist/assets/{quadrantDiagram-LMRXKWRM-D1DdWF8C.js → quadrantDiagram-LMRXKWRM-CfGssUlO.js} +1 -1
  92. package/dist/assets/{react-plotly-CTwajqCb.js → react-plotly-DR3hV0HW.js} +1 -1
  93. package/dist/assets/{requirementDiagram-4UW4RH46-DnjDAypr.js → requirementDiagram-4UW4RH46-CfrFolth.js} +1 -1
  94. package/dist/assets/{run-page-CQY9im22.js → run-page-Bqd_4ePD.js} +1 -1
  95. package/dist/assets/{sankeyDiagram-GR3RE2ED-B67Va-ER.js → sankeyDiagram-GR3RE2ED-D_UttKU0.js} +1 -1
  96. package/dist/assets/scratchpad-panel-D5N15ji1.js +1 -0
  97. package/dist/assets/secrets-panel-BpbnAO4R.js +1 -0
  98. package/dist/assets/{sequenceDiagram-C3RYC4MD-DiWgZPtN.js → sequenceDiagram-C3RYC4MD-MdfQQApP.js} +1 -1
  99. package/dist/assets/{slides-component-DhpPRtQp.js → slides-component-C0z7rXmk.js} +1 -1
  100. package/dist/assets/{snippets-panel-CLkBXhJ2.js → snippets-panel-wlpZ_Wzx.js} +1 -1
  101. package/dist/assets/{sortBy-D4OG7w4O.js → sortBy-BW_zNHP6.js} +1 -1
  102. package/dist/assets/{state-Dz_3JyED.js → state-CDooX-dk.js} +1 -1
  103. package/dist/assets/{stateDiagram-KXAO66HF-ByF2AULw.js → stateDiagram-KXAO66HF-H7kfw3ot.js} +1 -1
  104. package/dist/assets/stateDiagram-v2-UMBNRL4Z-YMeb9qMR.js +1 -0
  105. package/dist/assets/{storage-Dr0CC44z.js → storage-b1QCapTq.js} +6 -6
  106. package/dist/assets/{terminal-BtdissBf.js → terminal-CPV44BXz.js} +1 -1
  107. package/dist/assets/{time-DKdOTnQg.js → time-DDy3xv5Y.js} +1 -1
  108. package/dist/assets/{timeline-definition-XQNQX7LJ-DzER9bf6.js → timeline-definition-XQNQX7LJ-J-cPRT2_.js} +1 -1
  109. package/dist/assets/{tracing-Dpx5M-u3.js → tracing-3eHHRUiJ.js} +2 -2
  110. package/dist/assets/{tracing-panel-hCjBkSER.js → tracing-panel-BMgy3D7d.js} +2 -2
  111. package/dist/assets/{trash-C6Ko-g5q.js → trash--tonOuDe.js} +1 -1
  112. package/dist/assets/{tree-BHN2gcCF.js → tree-ouIGEsVg.js} +6 -6
  113. package/dist/assets/{treemap-75Q7IDZK-DR79Mhzt.js → treemap-75Q7IDZK-CzJTJ_3R.js} +20 -20
  114. package/dist/assets/{variable-panel-PFBCFz36.js → variable-panel-sFTn4Oih.js} +1 -1
  115. package/dist/assets/{vega-component-Db6-uY4C.js → vega-component-BkPkzX9r.js} +1 -1
  116. package/dist/assets/{xychartDiagram-6GGTOJPD-DWzBP3tZ.js → xychartDiagram-6GGTOJPD-BZ8WOb_8.js} +1 -1
  117. package/dist/index.html +10 -3
  118. package/package.json +6 -6
  119. package/src/__mocks__/common.ts +5 -3
  120. package/src/__mocks__/notebook.ts +2 -2
  121. package/src/__tests__/main.test.tsx +2 -2
  122. package/src/components/ai/ai-provider-icon.tsx +2 -0
  123. package/src/components/app-config/ai-config.tsx +32 -1
  124. package/src/components/app-config/common.tsx +2 -2
  125. package/src/components/app-config/user-config-form.tsx +26 -0
  126. package/src/components/audio/audio-recorder.tsx +0 -1
  127. package/src/components/chat/acp/blocks.tsx +2 -2
  128. package/src/components/chat/acp/thread.tsx +3 -5
  129. package/src/components/chat/acp/utils.ts +5 -5
  130. package/src/components/chat/chat-panel.tsx +1 -1
  131. package/src/components/data-table/__tests__/data-table.test.tsx +2 -2
  132. package/src/components/data-table/charts/__tests__/altair-generator.test.ts +1 -1
  133. package/src/components/data-table/charts/chart-spec/tooltips.ts +3 -3
  134. package/src/components/data-table/charts/components/chart-items.tsx +1 -1
  135. package/src/components/data-table/charts/components/form-fields.tsx +2 -2
  136. package/src/components/data-table/charts/constants.ts +1 -1
  137. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  138. package/src/components/data-table/column-summary/chart-spec-model.tsx +2 -2
  139. package/src/components/data-table/columns.tsx +1 -1
  140. package/src/components/data-table/data-table.tsx +35 -3
  141. package/src/components/data-table/date-popover.tsx +1 -1
  142. package/src/components/data-table/download-actions.tsx +1 -1
  143. package/src/components/data-table/range-focus/__tests__/utils.test.ts +5 -5
  144. package/src/components/data-table/renderers.tsx +6 -5
  145. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +1 -1
  146. package/src/components/data-table/types.ts +4 -3
  147. package/src/components/datasources/column-preview.tsx +9 -6
  148. package/src/components/debugger/debugger-code.tsx +1 -1
  149. package/src/components/dependency-graph/custom-node.tsx +15 -6
  150. package/src/components/dependency-graph/dependency-graph-minimap.tsx +2 -2
  151. package/src/components/dependency-graph/dependency-graph-tree.tsx +2 -2
  152. package/src/components/dependency-graph/dependency-graph.tsx +1 -1
  153. package/src/components/dependency-graph/elements.ts +7 -7
  154. package/src/components/dependency-graph/utils/changes.ts +4 -4
  155. package/src/components/editor/Cell.tsx +6 -2
  156. package/src/components/editor/ai/transport/chat-transport.tsx +1 -1
  157. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +1 -1
  158. package/src/components/editor/chrome/panels/packages-panel.tsx +1 -1
  159. package/src/components/editor/columns/storage.ts +1 -1
  160. package/src/components/editor/database/__tests__/__snapshots__/as-code.test.ts.snap +36 -0
  161. package/src/components/editor/database/__tests__/as-code.test.ts +30 -7
  162. package/src/components/editor/database/add-database-form.tsx +11 -0
  163. package/src/components/editor/database/as-code.ts +104 -5
  164. package/src/components/editor/database/schemas.ts +36 -18
  165. package/src/components/editor/errors/auto-fix.tsx +12 -2
  166. package/src/components/editor/errors/sql-validation-errors.tsx +12 -6
  167. package/src/components/editor/navigation/clipboard.ts +2 -2
  168. package/src/components/editor/output/ConsoleOutput.tsx +1 -1
  169. package/src/components/editor/output/JsonOutput.tsx +1 -1
  170. package/src/components/editor/output/MarimoErrorOutput.tsx +25 -25
  171. package/src/components/editor/output/MarimoTracebackOutput.tsx +17 -2
  172. package/src/components/editor/renderers/grid-layout/types.ts +2 -2
  173. package/src/components/editor/renderers/plugins.ts +1 -1
  174. package/src/components/editor/renderers/types.ts +1 -1
  175. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +7 -7
  176. package/src/components/forms/form.tsx +5 -5
  177. package/src/components/ui/links.tsx +1 -0
  178. package/src/core/ai/__tests__/model-registry.test.ts +0 -10
  179. package/src/core/ai/context/providers/error.ts +2 -2
  180. package/src/core/ai/ids/ids.ts +1 -0
  181. package/src/core/ai/model-registry.ts +2 -1
  182. package/src/core/cells/cells.ts +5 -5
  183. package/src/core/cells/logs.ts +1 -1
  184. package/src/core/cells/types.ts +1 -1
  185. package/src/core/codemirror/__tests__/format.test.ts +6 -0
  186. package/src/core/codemirror/cells/traceback-decorations.ts +1 -1
  187. package/src/core/codemirror/editing/commands.ts +2 -2
  188. package/src/core/codemirror/find-replace/navigate.ts +1 -1
  189. package/src/core/codemirror/language/__tests__/extension.test.ts +1 -1
  190. package/src/core/codemirror/language/__tests__/sql-validation.test.ts +1 -1
  191. package/src/core/codemirror/language/__tests__/sql.test.ts +764 -79
  192. package/src/core/codemirror/language/languages/markdown.ts +4 -1
  193. package/src/core/codemirror/language/languages/sql/{validation-errors.ts → banner-validation-errors.ts} +9 -3
  194. package/src/core/codemirror/language/languages/sql/completion-builder.ts +160 -0
  195. package/src/core/codemirror/language/languages/sql/completion-sources.tsx +9 -3
  196. package/src/core/codemirror/language/languages/sql/completion-store.ts +46 -50
  197. package/src/core/codemirror/language/languages/sql/renderers.tsx +485 -0
  198. package/src/core/codemirror/language/languages/sql/sql.ts +151 -24
  199. package/src/core/codemirror/language/languages/sql/utils.ts +4 -1
  200. package/src/core/codemirror/language/panel/sql.tsx +6 -1
  201. package/src/core/codemirror/language/utils/ast.ts +3 -3
  202. package/src/core/codemirror/lsp/federated-lsp.ts +4 -4
  203. package/src/core/codemirror/lsp/lens.ts +4 -4
  204. package/src/core/codemirror/lsp/notebook-lsp.ts +1 -1
  205. package/src/core/codemirror/lsp/types.ts +1 -1
  206. package/src/core/codemirror/markdown/completions.ts +1 -1
  207. package/src/core/codemirror/reactive-references/analyzer.ts +2 -2
  208. package/src/core/codemirror/rtc/loro/awareness.ts +1 -1
  209. package/src/core/config/config-schema.ts +1 -0
  210. package/src/core/config/feature-flag.tsx +3 -1
  211. package/src/core/datasets/request-registry.ts +17 -10
  212. package/src/core/dom/events.ts +1 -1
  213. package/src/core/dom/outline.ts +2 -2
  214. package/src/core/dom/uiregistry.ts +2 -8
  215. package/src/core/errors/__tests__/errors.test.ts +22 -4
  216. package/src/core/errors/errors.ts +29 -1
  217. package/src/core/errors/state.ts +1 -1
  218. package/src/core/islands/main.ts +2 -2
  219. package/src/core/islands/parse.ts +1 -3
  220. package/src/core/kernel/messages.ts +1 -1
  221. package/src/core/network/CachingRequestRegistry.ts +74 -0
  222. package/src/core/network/DeferredRequestRegistry.ts +3 -1
  223. package/src/core/network/__tests__/CachingRequestRegistry.test.ts +73 -0
  224. package/src/core/network/types.ts +1 -1
  225. package/src/core/variables/state.ts +2 -2
  226. package/src/core/wasm/__tests__/state.test.ts +1 -1
  227. package/src/core/websocket/useMarimoWebSocket.tsx +5 -2
  228. package/src/custom.d.ts +1 -1
  229. package/src/hooks/useCellRenderCount.ts +1 -0
  230. package/src/hooks/useResizeHandle.ts +4 -1
  231. package/src/plugins/core/RenderHTML.tsx +1 -2
  232. package/src/plugins/impl/DataTablePlugin.tsx +7 -2
  233. package/src/plugins/impl/FileUploadPlugin.tsx +1 -1
  234. package/src/plugins/impl/RefreshPlugin.tsx +1 -1
  235. package/src/plugins/impl/SliderPlugin.tsx +4 -0
  236. package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +27 -9
  237. package/src/plugins/impl/anywidget/__tests__/AnyWidgetPlugin.test.tsx +58 -2
  238. package/src/plugins/impl/anywidget/__tests__/model.test.ts +3 -4
  239. package/src/plugins/impl/anywidget/model.ts +2 -3
  240. package/src/plugins/impl/data-editor/types.ts +1 -1
  241. package/src/plugins/impl/data-explorer/components/query-form.tsx +1 -1
  242. package/src/plugins/impl/data-frames/types.ts +1 -1
  243. package/src/plugins/impl/panel/PanelPlugin.tsx +2 -2
  244. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +3 -3
  245. package/src/plugins/impl/vega/__tests__/loader.test.ts +2 -2
  246. package/src/plugins/impl/vega/loader.ts +1 -1
  247. package/src/plugins/impl/vega/vega-component.tsx +1 -1
  248. package/src/plugins/impl/vega/vega-loader.ts +2 -2
  249. package/src/plugins/layout/NavigationMenuPlugin.tsx +1 -1
  250. package/src/plugins/layout/RoutesPlugin.tsx +1 -2
  251. package/src/plugins/plugins.ts +2 -2
  252. package/src/utils/Logger.ts +1 -1
  253. package/src/utils/__tests__/data-views.test.ts +30 -68
  254. package/src/utils/__tests__/dom.test.ts +10 -10
  255. package/src/utils/__tests__/id-tree.test.ts +49 -1
  256. package/src/utils/__tests__/storage.test.ts +1 -1
  257. package/src/utils/__tests__/traceback.test.ts +13 -2
  258. package/src/utils/arrays.ts +1 -1
  259. package/src/utils/createReducer.ts +1 -5
  260. package/src/utils/data-views.ts +6 -19
  261. package/src/utils/edit-distance.ts +1 -1
  262. package/src/utils/fileToBase64.ts +1 -1
  263. package/src/utils/id-tree.tsx +20 -18
  264. package/src/utils/json/base64.ts +13 -0
  265. package/src/utils/json/json-parser.ts +2 -2
  266. package/src/utils/lru.ts +4 -0
  267. package/src/utils/mergeRefs.ts +1 -1
  268. package/src/utils/objects.ts +3 -3
  269. package/src/utils/pluralize.ts +1 -1
  270. package/src/utils/routes.ts +2 -2
  271. package/src/utils/sets.ts +1 -1
  272. package/src/utils/traceback.ts +45 -15
  273. package/src/utils/tracer.ts +11 -9
  274. package/dist/assets/_baseEach--KDTwKbG.js +0 -1
  275. package/dist/assets/_baseMap-Cu3o-eyO.js +0 -1
  276. package/dist/assets/_baseUniq-y7ZXnMo1.js +0 -1
  277. package/dist/assets/channel-DFaEx1fu.js +0 -1
  278. package/dist/assets/chat-panel-IoPMv8e2.js +0 -3
  279. package/dist/assets/classDiagram-KNZD7YFC-BsZtvV5O.js +0 -1
  280. package/dist/assets/classDiagram-v2-RKCZMP56-BsZtvV5O.js +0 -1
  281. package/dist/assets/clone-YBEvPE-s.js +0 -1
  282. package/dist/assets/command-palette-D7hOfvf6.js +0 -1
  283. package/dist/assets/edit-page-C5TsEeSo.js +0 -129
  284. package/dist/assets/index-CGDMlQfO.css +0 -1
  285. package/dist/assets/index-CelXfcd8.js +0 -580
  286. package/dist/assets/index-Cxyk7pt-.js +0 -68
  287. package/dist/assets/infoDiagram-STP46IZ2-wTALjfPc.js +0 -2
  288. package/dist/assets/links-Drv7cJgN.js +0 -7
  289. package/dist/assets/min-DYUOb1RR.js +0 -1
  290. package/dist/assets/scratchpad-panel-DlDfcDtW.js +0 -1
  291. package/dist/assets/secrets-panel-BDGyuGZA.js +0 -1
  292. package/dist/assets/stateDiagram-v2-UMBNRL4Z-CtBJqosP.js +0 -1
  293. package/src/__tests__/lru.test.ts +0 -74
@@ -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();
@@ -2,29 +2,35 @@
2
2
 
3
3
  import { AlertCircleIcon } from "lucide-react";
4
4
  import type { CellId } from "@/core/cells/ids";
5
- import { useSqlValidationErrorsForCell } from "@/core/codemirror/language/languages/sql/validation-errors";
5
+ import { useSqlValidationErrorsForCell } from "@/core/codemirror/language/languages/sql/banner-validation-errors";
6
6
 
7
- export const SqlValidationErrorBanner = ({ cellId }: { cellId: CellId }) => {
7
+ export const SqlValidationErrorBanner = ({
8
+ cellId,
9
+ hide,
10
+ }: {
11
+ cellId: CellId;
12
+ hide: boolean;
13
+ }) => {
8
14
  const error = useSqlValidationErrorsForCell(cellId);
9
15
 
10
- if (!error) {
16
+ if (!error || hide) {
11
17
  return;
12
18
  }
13
19
 
14
20
  return (
15
- <div className="p-3 text-sm flex flex-col text-muted-foreground gap-1.5 bg-destructive/5">
21
+ <div className="p-3 text-sm flex flex-col text-muted-foreground gap-1.5 bg-destructive/4">
16
22
  <div className="flex items-start gap-1.5">
17
23
  <AlertCircleIcon size={13} className="mt-[3px] text-destructive" />
18
24
  <p>
19
25
  <span className="font-bold text-destructive">{error.errorType}:</span>{" "}
20
- {error.errorMessage}
26
+ <span className="whitespace-pre-wrap">{error.errorMessage}</span>
21
27
  </p>
22
28
  </div>
23
29
 
24
30
  {error.codeblock && (
25
31
  <pre
26
32
  lang="sql"
27
- className="text-xs bg-muted rounded p-2 pb-0 mx-3 overflow-x-auto font-mono whitespace-pre-wrap"
33
+ className="text-xs bg-muted/80 rounded p-2 pb-0 mx-3 font-medium whitespace-pre-wrap"
28
34
  >
29
35
  {error.codeblock}
30
36
  </pre>
@@ -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
 
@@ -28,7 +28,7 @@ interface Props {
28
28
  cellId: CellId;
29
29
  cellName: string;
30
30
  className?: string;
31
- consoleOutputs: Array<WithResponse<OutputMessage>>;
31
+ consoleOutputs: WithResponse<OutputMessage>[];
32
32
  stale: boolean;
33
33
  debuggerActive: boolean;
34
34
  onRefactorWithAI?: (opts: { prompt: string }) => void;
@@ -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,
@@ -77,7 +77,7 @@ export const MarimoErrorOutput = ({
77
77
  alertVariant = "default";
78
78
  titleColor = "text-secondary-foreground";
79
79
  } else if (errors.some((e) => e.type === "sql-error")) {
80
- titleContents = "SQL Error in statement";
80
+ titleContents = "SQL error";
81
81
  } else {
82
82
  // Check for exception type
83
83
  const exceptionError = errors.find((e) => e.type === "exception");
@@ -500,25 +500,30 @@ export const MarimoErrorOutput = ({
500
500
  <div key="sql-errors">
501
501
  {sqlErrors.map((error, idx) => {
502
502
  const line =
503
- error.sql_line != null ? (error?.sql_line | 0) + 1 : null;
504
- const col = error.sql_col != null ? (error?.sql_col | 0) + 1 : null;
503
+ error.sql_line == null ? null : Math.trunc(error?.sql_line) + 1;
504
+ const col =
505
+ error.sql_col == null ? null : Math.trunc(error?.sql_col) + 1;
505
506
  return (
506
- <div key={`sql-error-${idx}`} className="space-y-2">
507
- <p className="text-muted-foreground">{error.msg}</p>
507
+ <div key={`sql-error-${idx}`} className="space-y-2 mt-2">
508
+ <p className="text-muted-foreground font-medium">{error.msg}</p>
508
509
  {error.hint && (
509
510
  <div className="flex items-start gap-2">
510
- <InfoIcon className="h-4 w-4 text-muted-foreground mt-0.5 flex-shrink-0" />
511
- <pre className="whitespace-pre-wrap text-sm text-muted-foreground">
511
+ <InfoIcon
512
+ size={11}
513
+ className="text-muted-foreground mt-1 flex-shrink-0"
514
+ />
515
+ <p className="whitespace-pre-wrap text-sm text-muted-foreground">
512
516
  {error.hint}
513
- </pre>
517
+ </p>
514
518
  </div>
515
519
  )}
516
520
  {error.sql_statement && (
517
- <div className="bg-muted/50 p-2 rounded text-xs font-mono">
518
- <pre className="whitespace-pre-wrap">
519
- {error.sql_statement}
520
- </pre>
521
- </div>
521
+ <pre
522
+ lang="sql"
523
+ className="text-xs bg-muted/80 rounded whitespace-pre-wrap p-3.5"
524
+ >
525
+ {error.sql_statement.trim()}
526
+ </pre>
522
527
  )}
523
528
  {line !== null && col !== null && (
524
529
  <p className="text-xs text-muted-foreground">
@@ -528,18 +533,13 @@ export const MarimoErrorOutput = ({
528
533
  </div>
529
534
  );
530
535
  })}
531
- {cellId && <AutoFixButton errors={sqlErrors} cellId={cellId} />}
532
- <Tip title="How to fix SQL errors">
533
- <p className="pb-2">
534
- SQL parsing errors often occur due to invalid syntax, missing
535
- keywords, or unsupported SQL features.
536
- </p>
537
- <p className="py-2">
538
- Check your SQL syntax and ensure you're using supported SQL
539
- dialect features. The error location can help you identify the
540
- problematic part of your query.
541
- </p>
542
- </Tip>
536
+ {cellId && (
537
+ <AutoFixButton
538
+ errors={sqlErrors}
539
+ cellId={cellId}
540
+ className="mt-2.5"
541
+ />
542
+ )}
543
543
  </div>,
544
544
  );
545
545
  }
@@ -108,7 +108,7 @@ export const MarimoTracebackOutput = ({
108
108
  Fix with AI
109
109
  </Button>
110
110
  )}
111
- {tracebackInfo && !isWasm() && (
111
+ {tracebackInfo && tracebackInfo.kind === "cell" && !isWasm() && (
112
112
  <Tooltip content={"Attach pdb to the exception point."}>
113
113
  <Button
114
114
  size="xs"
@@ -180,7 +180,7 @@ function lastLine(text: string): string {
180
180
 
181
181
  export const replaceTracebackFilenames = (domNode: DOMNode) => {
182
182
  const info = getTracebackInfo(domNode);
183
- if (info) {
183
+ if (info?.kind === "cell") {
184
184
  const tooltipContent = <InsertBreakpointContent />;
185
185
  return (
186
186
  <span className="nb">
@@ -211,6 +211,21 @@ export const replaceTracebackFilenames = (domNode: DOMNode) => {
211
211
  </span>
212
212
  );
213
213
  }
214
+ if (info?.kind === "file") {
215
+ return (
216
+ <div
217
+ className="inline-block cursor-pointer text-destructive hover:underline"
218
+ onClick={(_) => {
219
+ getRequestClient().openFile({
220
+ path: info.filePath,
221
+ lineNumber: info.lineNumber,
222
+ });
223
+ }}
224
+ >
225
+ <span className="nb">"{info.filePath}"</span>
226
+ </div>
227
+ );
228
+ }
214
229
  };
215
230
 
216
231
  export const replaceTracebackPrefix = (domNode: DOMNode) => {
@@ -68,13 +68,13 @@ export interface GridLayout extends Omit<SerializedGridLayout, "cells"> {
68
68
  /**
69
69
  * The cells in the layout.
70
70
  */
71
- cells: Array<{
71
+ cells: {
72
72
  i: string;
73
73
  x: number;
74
74
  y: number;
75
75
  w: number;
76
76
  h: number;
77
- }>;
77
+ }[];
78
78
 
79
79
  scrollableCells: Set<CellId>;
80
80
 
@@ -8,7 +8,7 @@ import { VerticalLayoutPlugin } from "./vertical-layout/vertical-layout";
8
8
 
9
9
  // If more renderers are added, we may want to consider lazy loading them.
10
10
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
- export const cellRendererPlugins: Array<ICellRendererPlugin<any, any>> = [
11
+ export const cellRendererPlugins: ICellRendererPlugin<any, any>[] = [
12
12
  GridLayoutPlugin,
13
13
  SlidesLayoutPlugin,
14
14
  VerticalLayoutPlugin,
@@ -17,7 +17,7 @@ export interface ICellRendererProps<L> {
17
17
  /**
18
18
  * The cells to render.
19
19
  */
20
- cells: Array<CellRuntimeState & CellData>;
20
+ cells: (CellRuntimeState & CellData)[];
21
21
 
22
22
  /**
23
23
  * The layout configuration.
@@ -198,7 +198,7 @@ const ActionButtons: React.FC<{
198
198
  actions.push(
199
199
  <DropdownMenuItem
200
200
  onSelect={onToggleShowCode}
201
- id="notebook-action-show-code"
201
+ data-testid="notebook-action-show-code"
202
202
  key="show-code"
203
203
  >
204
204
  <Code2Icon className="mr-2" size={14} strokeWidth={1.5} />
@@ -213,7 +213,7 @@ const ActionButtons: React.FC<{
213
213
  actions.push(
214
214
  <DropdownMenuItem
215
215
  onSelect={handleDownloadAsHTML}
216
- id="notebook-action-download-html"
216
+ data-testid="notebook-action-download-html"
217
217
  key="download-html"
218
218
  >
219
219
  <FolderDownIcon className="mr-2" size={14} strokeWidth={1.5} />
@@ -222,7 +222,7 @@ const ActionButtons: React.FC<{
222
222
  <DropdownMenuSeparator key="download-html-separator" />,
223
223
  <DropdownMenuItem
224
224
  onSelect={handleDownloadAsPNG}
225
- id="notebook-action-download-png"
225
+ data-testid="notebook-action-download-png"
226
226
  key="download-png"
227
227
  >
228
228
  <ImageIcon className="mr-2" size={14} strokeWidth={1.5} />
@@ -239,7 +239,7 @@ const ActionButtons: React.FC<{
239
239
  // as this may be used in custom css to hide/show the actions dropdown
240
240
  return (
241
241
  <div
242
- id="notebook-actions-dropdown"
242
+ data-testid="notebook-actions-dropdown"
243
243
  className={cn(
244
244
  "right-0 top-0 z-50 m-4 no-print flex gap-2 print:hidden",
245
245
  // If the notebook is static, we have a banner at the top, so
@@ -419,10 +419,10 @@ export const VerticalLayoutPlugin: ICellRendererPlugin<
419
419
  };
420
420
 
421
421
  export function groupCellsByColumn(
422
- cells: Array<CellRuntimeState & CellData>,
423
- ): Array<[number, Array<CellRuntimeState & CellData>]> {
422
+ cells: (CellRuntimeState & CellData)[],
423
+ ): [number, (CellRuntimeState & CellData)[]][] {
424
424
  // Group cells by column
425
- const cellsByColumn = new Map<number, Array<CellRuntimeState & CellData>>();
425
+ const cellsByColumn = new Map<number, (CellRuntimeState & CellData)[]>();
426
426
  let lastSeenColumn = 0;
427
427
  cells.forEach((cell) => {
428
428
  const column = cell.config.column ?? lastSeenColumn;
@@ -59,7 +59,7 @@ interface Props<T extends FieldValues> {
59
59
  form: UseFormReturn<T>;
60
60
  schema: z.ZodType;
61
61
  path?: Path<T>;
62
- renderers: Array<FormRenderer<T>> | undefined;
62
+ renderers: FormRenderer<T>[] | undefined;
63
63
  children?: React.ReactNode;
64
64
  }
65
65
 
@@ -82,7 +82,7 @@ export function renderZodSchema<T extends FieldValues, S>(
82
82
  schema: z.ZodType<S>,
83
83
  form: UseFormReturn<T>,
84
84
  path: Path<T>,
85
- renderers: Array<FormRenderer<T>>,
85
+ renderers: FormRenderer<T>[],
86
86
  ) {
87
87
  // Try custom renderers first
88
88
  for (const renderer of renderers) {
@@ -330,7 +330,7 @@ export function renderZodSchema<T extends FieldValues, S>(
330
330
  }
331
331
 
332
332
  if (schema instanceof z.ZodDiscriminatedUnion) {
333
- const options = schema._def.options as Array<z.ZodType<unknown>>;
333
+ const options = schema._def.options as z.ZodType<unknown>[];
334
334
  const discriminator = schema._def.discriminator;
335
335
  const optionsMap = schema._def.optionsMap;
336
336
  return (
@@ -392,7 +392,7 @@ export function renderZodSchema<T extends FieldValues, S>(
392
392
  control={form.control}
393
393
  name={path}
394
394
  render={({ field }) => {
395
- const options = schema._def.options as Array<z.ZodType<unknown>>;
395
+ const options = schema._def.options as z.ZodType<unknown>[];
396
396
  let value: string = field.value;
397
397
  const types = options.map((option) => {
398
398
  return getUnionLiteral(option)._def.value;
@@ -812,6 +812,6 @@ const MultiSelectFormField = ({
812
812
  );
813
813
  };
814
814
 
815
- function joinPath<T>(...parts: Array<string | number>): Path<T> {
815
+ function joinPath<T>(...parts: (string | number)[]): Path<T> {
816
816
  return parts.filter((part) => part !== "").join(".") as Path<T>;
817
817
  }
@@ -8,6 +8,7 @@ export const ExternalLink = ({
8
8
  | `https://console.anthropic.com/${string}`
9
9
  | `https://aistudio.google.com/${string}`
10
10
  | `https://github.com/${string}`
11
+ | `https://openrouter.ai/${string}`
11
12
  | `https://docs.marimo.io/${string}`
12
13
  | `https://docs.python.org/${string}`
13
14
  | `https://marimo.io/${string}`