@marimo-team/frontend 0.25.2-dev66 → 0.25.2-dev89

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 (153) hide show
  1. package/dist/assets/{CellStatus-CRFBVGjI.js → CellStatus-Bj7PvY_u.js} +1 -1
  2. package/dist/assets/{ErrorBoundary-BKmN7zye.js → ErrorBoundary-CG6gtgym.js} +2 -2
  3. package/dist/assets/{JsonOutput-nqqzL-n0.js → JsonOutput-NVH7GWyC.js} +1 -1
  4. package/dist/assets/{MarimoErrorOutput-DCu6fm2y.js → MarimoErrorOutput-z5iFryzf.js} +1 -1
  5. package/dist/assets/{RenderHTML-DRMkieKn.js → RenderHTML-C7QcdAgB.js} +1 -1
  6. package/dist/assets/{RunButton-CPZWjCL9.js → RunButton-A__3wcpF.js} +1 -1
  7. package/dist/assets/{add-cell-with-ai-D20NyZO4.js → add-cell-with-ai-Wyt6GBhk.js} +1 -1
  8. package/dist/assets/{add-connection-dialog-pQcdKIlO.js → add-connection-dialog-bl8dqCVs.js} +1 -1
  9. package/dist/assets/{agent-panel-tNErBgmq.js → agent-panel-BcoO8S6Q.js} +1 -1
  10. package/dist/assets/{ai-model-dropdown-BIeRPKed.js → ai-model-dropdown-CvJsRj9y.js} +1 -1
  11. package/dist/assets/{api-DYL9A86_.js → api-DVLtXyp7.js} +1 -1
  12. package/dist/assets/{app-config-button-DkNGV0b1.js → app-config-button-C7QrZbqr.js} +1 -1
  13. package/dist/assets/{blob-BIYte8oT.js → blob-Bx8A10xl.js} +1 -1
  14. package/dist/assets/{cell-editor-C5RTy4Y0.js → cell-editor-CevZDS63.js} +4 -4
  15. package/dist/assets/cell-link-DC1UZQr_.js +1 -0
  16. package/dist/assets/{cells-h5u00Nz8.js → cells-CxY8RSp7.js} +2 -2
  17. package/dist/assets/{chat-display-DzTkUWMw.js → chat-display-YETh6yXV.js} +1 -1
  18. package/dist/assets/{chat-panel-CKqEpnjN.js → chat-panel-DyaePe7B.js} +1 -1
  19. package/dist/assets/{chat-ui-CGzOsYVb.js → chat-ui-D_QL46qM.js} +1 -1
  20. package/dist/assets/code-visibility-DNzJgrTz.js +1 -0
  21. package/dist/assets/{column-preview-DtrgJzVI.js → column-preview-sL_Jo0hX.js} +1 -1
  22. package/dist/assets/{command-palette-BKYGTfS5.js → command-palette-DMQFuWz1.js} +1 -1
  23. package/dist/assets/{common-BMeq0Bqi.js → common-Cy3lJDvJ.js} +1 -1
  24. package/dist/assets/{components-CWcf8098.js → components-D9ZIJGG8.js} +1 -1
  25. package/dist/assets/{config-BAnYSdpO.js → config-D_c_6ce1.js} +1 -1
  26. package/dist/assets/{datasource-BLHGFSsT.js → datasource-Tst92Pzi.js} +1 -1
  27. package/dist/assets/{dependency-graph-panel-C8X3Nn8W.js → dependency-graph-panel-BwMayTyZ.js} +1 -1
  28. package/dist/assets/{documentation-panel-C8wrSKlX.js → documentation-panel-OMUbXgKW.js} +1 -1
  29. package/dist/assets/{download-CUgiCx7s.js → download-CPMAf7re.js} +1 -1
  30. package/dist/assets/{edit-page-CqPNBpAP.js → edit-page-DD1NFkiu.js} +6 -6
  31. package/dist/assets/{error-entries-DQD4A9cx.js → error-entries-DBpwg0GC.js} +1 -1
  32. package/dist/assets/{error-panel-BJYkwYEY.js → error-panel-ByOEJuZN.js} +1 -1
  33. package/dist/assets/{feedback-button-DbTjGwcX.js → feedback-button-7KY7nL-j.js} +2 -2
  34. package/dist/assets/feedback-button-DxjoRfo3.js +1 -0
  35. package/dist/assets/{file-explorer-panel-BQi88S1o.js → file-explorer-panel-B92ugwxr.js} +1 -1
  36. package/dist/assets/{file-name-input-DPJSxW_X.js → file-name-input-DZehOHLA.js} +1 -1
  37. package/dist/assets/{floating-outline-3PlTr0K1.js → floating-outline-K7cVdOlC.js} +1 -1
  38. package/dist/assets/{gallery-page-BqvVmwde.js → gallery-page-DoriMrLH.js} +1 -1
  39. package/dist/assets/{glide-data-editor-CAa14cIr.js → glide-data-editor-DWyeHe3u.js} +1 -1
  40. package/dist/assets/{home-page-Bg-WqjiD.js → home-page-BcJJsD_Q.js} +1 -1
  41. package/dist/assets/{hooks-DLBvBo8c.js → hooks-DNPsQf79.js} +1 -1
  42. package/dist/assets/index-B7ZZVUcj.css +2 -0
  43. package/dist/assets/{index-BtV91sqJ.js → index-CqJKdR1j.js} +5 -5
  44. package/dist/assets/{layout-mWXZofX2.js → layout-BaluekG6.js} +3 -3
  45. package/dist/assets/{logs-panel-IKL6F2OX.js → logs-panel-OkoO5mbN.js} +1 -1
  46. package/dist/assets/{markdown-renderer-DHvAXF8E.js → markdown-renderer-mDlWBE1M.js} +1 -1
  47. package/dist/assets/{name-cell-input-j4eGLLyd.js → name-cell-input-D_Q2IhP9.js} +1 -1
  48. package/dist/assets/{outline-panel-CprDWmxn.js → outline-panel-Dy2cmYDF.js} +1 -1
  49. package/dist/assets/packages-panel-CIvhx0hb.js +1 -0
  50. package/dist/assets/{panel-accordion-state-8xXVhawu.js → panel-accordion-state-BI4SU22L.js} +1 -1
  51. package/dist/assets/panels-CO6Clgel.js +4 -0
  52. package/dist/assets/{process-output-DOmeJ1VR.js → process-output-Crm0vqbi.js} +1 -1
  53. package/dist/assets/{readonly-code-display-xvH6MyT6.js → readonly-code-display-CNbw6v1-.js} +1 -1
  54. package/dist/assets/{readonly-python-code-D4YGmSvB.js → readonly-python-code-DcYhdd1B.js} +1 -1
  55. package/dist/assets/{reveal-component-CDUG1x74.js → reveal-component-DeZTBbnn.js} +1 -1
  56. package/dist/assets/{run-page-BAqLgcq9.js → run-page-BNEg-Ro9.js} +1 -1
  57. package/dist/assets/runtime-details-state-lxXYwJcI.js +1 -0
  58. package/dist/assets/{scratchpad-panel-BFbUuzdn.js → scratchpad-panel-lDJWcpVs.js} +1 -1
  59. package/dist/assets/{session-panel-BdN43Lzi.js → session-panel-BqutyoYd.js} +1 -1
  60. package/dist/assets/{snippets-panel-5_jR08Zd.js → snippets-panel-YttkYAW9.js} +1 -1
  61. package/dist/assets/state-B2ZbImvm.js +1 -0
  62. package/dist/assets/{state-BxJ_FX3k.js → state-B85OOscw.js} +1 -1
  63. package/dist/assets/{state-7os84dnI.js → state-sbCCk7ZP.js} +1 -1
  64. package/dist/assets/{terminal-DHWTOXu3.js → terminal-3hxM6K9q.js} +1 -1
  65. package/dist/assets/{tracing-CRkNpBaH.js → tracing-DZYfCw6p.js} +1 -1
  66. package/dist/assets/{tracing-panel-DV2-2TUI.js → tracing-panel-BUPJ77jB.js} +2 -2
  67. package/dist/assets/{tree-actions-CShqSonp.js → tree-actions-D5clvgKl.js} +1 -1
  68. package/dist/assets/{useAddCell-DesMfnE4.js → useAddCell-Bhv6GT3m.js} +1 -1
  69. package/dist/assets/{useBoolean-BofUVeKg.js → useBoolean-Co-_MyFz.js} +1 -1
  70. package/dist/assets/{useCellActionButton-BO5SFMxA.js → useCellActionButton-DwAUf_Cn.js} +1 -1
  71. package/dist/assets/{useDeleteCell-DSbUjpSC.js → useDeleteCell-BKN7t4DH.js} +1 -1
  72. package/dist/assets/{useDependencyPanelTab-JIFiQrr2.js → useDependencyPanelTab-CbcGEmqM.js} +1 -1
  73. package/dist/assets/{useInstallPackage-CCQcFc6U.js → useInstallPackage-HTUlGg0U.js} +1 -1
  74. package/dist/assets/{useNotebookActions-CjjED3t-.js → useNotebookActions-pXzVjrlk.js} +1 -1
  75. package/dist/assets/{useRunCells-Bx3wXUWO.js → useRunCells-zMO43eNR.js} +1 -1
  76. package/dist/assets/{useSplitCell-BRmQP02b.js → useSplitCell-xEtFLByO.js} +1 -1
  77. package/dist/assets/{vega-component-C28fL5fD.js → vega-component-Chbfi__Q.js} +1 -1
  78. package/dist/index.html +24 -24
  79. package/package.json +1 -1
  80. package/src/__tests__/mount.test.ts +6 -6
  81. package/src/components/editor/actions/useRestartKernel.tsx +2 -2
  82. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +224 -17
  83. package/src/components/editor/alerts/connection-details.tsx +61 -0
  84. package/src/components/editor/alerts/connection-notice.tsx +46 -53
  85. package/src/components/editor/alerts/startup-progress.tsx +73 -129
  86. package/src/components/editor/app-container.tsx +2 -2
  87. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +2 -2
  88. package/src/components/editor/cell/CreateCellButton.tsx +2 -2
  89. package/src/components/editor/cell/DeleteButton.tsx +2 -2
  90. package/src/components/editor/cell/RunButton.tsx +3 -3
  91. package/src/components/editor/cell/StopButton.tsx +2 -2
  92. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +4 -4
  93. package/src/components/editor/chrome/components/feedback-button.tsx +3 -3
  94. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +8 -8
  95. package/src/components/editor/chrome/panels/__tests__/{sandbox-details.test.tsx → runtime-details.test.tsx} +94 -22
  96. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +4 -4
  97. package/src/components/editor/chrome/panels/packages-panel.tsx +8 -29
  98. package/src/components/editor/chrome/panels/{sandbox-details-state.ts → runtime-details-state.ts} +1 -1
  99. package/src/components/editor/chrome/panels/{sandbox-panel.tsx → runtime-panel.tsx} +38 -66
  100. package/src/components/editor/chrome/panels/runtime-status-toggle.tsx +56 -0
  101. package/src/components/editor/chrome/panels/sandbox-controller.tsx +2 -2
  102. package/src/components/editor/chrome/wrapper/app-chrome.tsx +3 -3
  103. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +2 -2
  104. package/src/components/editor/controls/Controls.tsx +3 -3
  105. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +2 -2
  106. package/src/components/editor/header/__tests__/status.test.tsx +4 -4
  107. package/src/components/editor/header/app-header.tsx +2 -2
  108. package/src/components/editor/header/status.tsx +3 -3
  109. package/src/components/ui/progress-stages.tsx +114 -0
  110. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +106 -5
  111. package/src/core/codemirror/lsp/notebook-lsp.ts +16 -2
  112. package/src/core/codemirror/readonly/__tests__/extension.test.ts +6 -6
  113. package/src/core/codemirror/readonly/extension.ts +2 -2
  114. package/src/core/datasets/__tests__/data-source-discovery.test.ts +2 -2
  115. package/src/core/edit-app.tsx +5 -1
  116. package/src/core/export/hooks.ts +2 -2
  117. package/src/core/network/__tests__/connection.test.ts +3 -3
  118. package/src/core/network/connection-notice.ts +5 -5
  119. package/src/core/network/connection.ts +9 -9
  120. package/src/core/network/requests-lazy.ts +2 -2
  121. package/src/core/packages/__tests__/useSandboxController.test.tsx +2 -2
  122. package/src/core/packages/useSandboxController.ts +6 -6
  123. package/src/core/runtime/__tests__/adapter.test.ts +6 -6
  124. package/src/core/runtime/adapter.ts +7 -7
  125. package/src/core/runtime/config.ts +2 -2
  126. package/src/core/saving/filename.ts +2 -2
  127. package/src/core/saving/save-component.tsx +5 -5
  128. package/src/core/saving/useAutoSave.ts +2 -2
  129. package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +30 -25
  130. package/src/core/websocket/__tests__/useMarimoKernelConnection.test.ts +5 -5
  131. package/src/core/websocket/connection-utils.ts +21 -21
  132. package/src/core/websocket/types.ts +8 -9
  133. package/src/core/websocket/useMarimoKernelConnection.tsx +21 -21
  134. package/src/mount.tsx +2 -2
  135. package/src/plugins/core/__test__/registerReactComponent.test.ts +55 -0
  136. package/src/plugins/core/registerReactComponent.tsx +3 -1
  137. package/src/stories/cell.stories.tsx +2 -2
  138. package/src/stories/layout/vertical/one-column.stories.tsx +5 -5
  139. package/src/stories/progress-stages.stories.tsx +62 -0
  140. package/src/stories/runtime-existing.stories.tsx +44 -0
  141. package/src/stories/runtime-maintenance.stories.tsx +40 -0
  142. package/src/stories/runtime-pixi.stories.tsx +28 -0
  143. package/src/stories/{sandbox.stories.tsx → runtime-story.tsx} +191 -152
  144. package/src/stories/runtime-uv.stories.tsx +56 -0
  145. package/dist/assets/cell-link-BeZAiE1D.js +0 -1
  146. package/dist/assets/code-visibility-B5QjA0ie.js +0 -1
  147. package/dist/assets/feedback-button-JqvnTSfN.js +0 -1
  148. package/dist/assets/index-CF8Gfz1R.css +0 -2
  149. package/dist/assets/packages-panel-CDDChziK.js +0 -1
  150. package/dist/assets/panels-CU7deLqc.js +0 -4
  151. package/dist/assets/sandbox-panel-D5bRunTM.js +0 -1
  152. package/dist/assets/state-Bo8h64Rn.js +0 -1
  153. package/src/components/editor/chrome/panels/sandbox-toggle.tsx +0 -52
package/dist/index.html CHANGED
@@ -66,7 +66,7 @@
66
66
  <marimo-server-token data-token="{{ server_token }}" hidden></marimo-server-token>
67
67
  <!-- /TODO -->
68
68
  <title>{{ title }}</title>
69
- <script type="module" crossorigin src="./assets/index-BtV91sqJ.js"></script>
69
+ <script type="module" crossorigin src="./assets/index-CqJKdR1j.js"></script>
70
70
  <link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-B0Z9INg1.js">
71
71
  <link rel="modulepreload" crossorigin href="./assets/react-CUdNIagt.js">
72
72
  <link rel="modulepreload" crossorigin href="./assets/compiler-runtime-BQ9S8nyo.js">
@@ -86,7 +86,7 @@
86
86
  <link rel="modulepreload" crossorigin href="./assets/utils-B4K466FK.js">
87
87
  <link rel="modulepreload" crossorigin href="./assets/session-BykGt6S3.js">
88
88
  <link rel="modulepreload" crossorigin href="./assets/Deferred-CrTnjj37.js">
89
- <link rel="modulepreload" crossorigin href="./assets/config-BAnYSdpO.js">
89
+ <link rel="modulepreload" crossorigin href="./assets/config-D_c_6ce1.js">
90
90
  <link rel="modulepreload" crossorigin href="./assets/clsx-DB0hHKMi.js">
91
91
  <link rel="modulepreload" crossorigin href="./assets/cn-ldLVeaqm.js">
92
92
  <link rel="modulepreload" crossorigin href="./assets/jsx-runtime-B74pBk57.js">
@@ -139,7 +139,7 @@
139
139
  <link rel="modulepreload" crossorigin href="./assets/useTheme-BkPLyRl9.js">
140
140
  <link rel="modulepreload" crossorigin href="./assets/useAsyncData-DucTwMkf.js">
141
141
  <link rel="modulepreload" crossorigin href="./assets/purify.es--06brOip.js">
142
- <link rel="modulepreload" crossorigin href="./assets/cells-h5u00Nz8.js">
142
+ <link rel="modulepreload" crossorigin href="./assets/cells-CxY8RSp7.js">
143
143
  <link rel="modulepreload" crossorigin href="./assets/coerce-CZiN7rQ_.js">
144
144
  <link rel="modulepreload" crossorigin href="./assets/get-DjNf4SIX.js">
145
145
  <link rel="modulepreload" crossorigin href="./assets/_hasPath-BmRQipI0.js">
@@ -152,43 +152,43 @@
152
152
  <link rel="modulepreload" crossorigin href="./assets/copy-D03Y7IMR.js">
153
153
  <link rel="modulepreload" crossorigin href="./assets/micromark-factory-space-D9Dr-k4J.js">
154
154
  <link rel="modulepreload" crossorigin href="./assets/chunk-YOKDWASO-84E-_nIR.js">
155
- <link rel="modulepreload" crossorigin href="./assets/markdown-renderer-DHvAXF8E.js">
155
+ <link rel="modulepreload" crossorigin href="./assets/markdown-renderer-mDlWBE1M.js">
156
156
  <link rel="modulepreload" crossorigin href="./assets/copy-RyCOE8jo.js">
157
157
  <link rel="modulepreload" crossorigin href="./assets/copy-icon-wfSGfX8v.js">
158
- <link rel="modulepreload" crossorigin href="./assets/useRunCells-Bx3wXUWO.js">
159
- <link rel="modulepreload" crossorigin href="./assets/RenderHTML-DRMkieKn.js">
160
- <link rel="modulepreload" crossorigin href="./assets/blob-BIYte8oT.js">
158
+ <link rel="modulepreload" crossorigin href="./assets/useRunCells-zMO43eNR.js">
159
+ <link rel="modulepreload" crossorigin href="./assets/RenderHTML-C7QcdAgB.js">
160
+ <link rel="modulepreload" crossorigin href="./assets/blob-Bx8A10xl.js">
161
161
  <link rel="modulepreload" crossorigin href="./assets/kbd-BnUiViRu.js">
162
- <link rel="modulepreload" crossorigin href="./assets/useInstallPackage-CCQcFc6U.js">
162
+ <link rel="modulepreload" crossorigin href="./assets/useInstallPackage-HTUlGg0U.js">
163
163
  <link rel="modulepreload" crossorigin href="./assets/errors-D9vyuMar.js">
164
- <link rel="modulepreload" crossorigin href="./assets/api-DYL9A86_.js">
164
+ <link rel="modulepreload" crossorigin href="./assets/api-DVLtXyp7.js">
165
165
  <link rel="modulepreload" crossorigin href="./assets/share-BZW3tzEX.js">
166
166
  <link rel="modulepreload" crossorigin href="./assets/events-CbeVJ6OD.js">
167
- <link rel="modulepreload" crossorigin href="./assets/state-7os84dnI.js">
167
+ <link rel="modulepreload" crossorigin href="./assets/state-sbCCk7ZP.js">
168
168
  <link rel="modulepreload" crossorigin href="./assets/pair-_FSgYVX4.js">
169
- <link rel="modulepreload" crossorigin href="./assets/ErrorBoundary-BKmN7zye.js">
169
+ <link rel="modulepreload" crossorigin href="./assets/ErrorBoundary-CG6gtgym.js">
170
170
  <link rel="modulepreload" crossorigin href="./assets/config-CR2d-XsP.js">
171
171
  <link rel="modulepreload" crossorigin href="./assets/chevron-right-DOPs2jx8.js">
172
172
  <link rel="modulepreload" crossorigin href="./assets/dropdown-menu-B2JUUcK7.js">
173
173
  <link rel="modulepreload" crossorigin href="./assets/html-to-image-CFVIG1VZ.js">
174
- <link rel="modulepreload" crossorigin href="./assets/download-CUgiCx7s.js">
174
+ <link rel="modulepreload" crossorigin href="./assets/download-CPMAf7re.js">
175
175
  <link rel="modulepreload" crossorigin href="./assets/switch-C-83e2fG.js">
176
176
  <link rel="modulepreload" crossorigin href="./assets/tabs-QRT1DYjj.js">
177
177
  <link rel="modulepreload" crossorigin href="./assets/table-B7KYyTxw.js">
178
178
  <link rel="modulepreload" crossorigin href="./assets/eye-off-CfkK-QS3.js">
179
179
  <link rel="modulepreload" crossorigin href="./assets/refresh-cw-CEGpOrzd.js">
180
- <link rel="modulepreload" crossorigin href="./assets/tree-actions-CShqSonp.js">
180
+ <link rel="modulepreload" crossorigin href="./assets/tree-actions-D5clvgKl.js">
181
181
  <link rel="modulepreload" crossorigin href="./assets/ellipsis-CLMWXUqY.js">
182
182
  <link rel="modulepreload" crossorigin href="./assets/external-link-D2lKwXyB.js">
183
183
  <link rel="modulepreload" crossorigin href="./assets/spinner-CGdRKCnw.js">
184
184
  <link rel="modulepreload" crossorigin href="./assets/message-circle-OTHnVlxO.js">
185
185
  <link rel="modulepreload" crossorigin href="./assets/hat-glasses-DVgK5i5l.js">
186
186
  <link rel="modulepreload" crossorigin href="./assets/package-BeYhVWvM.js">
187
- <link rel="modulepreload" crossorigin href="./assets/datasource-BLHGFSsT.js">
187
+ <link rel="modulepreload" crossorigin href="./assets/datasource-Tst92Pzi.js">
188
188
  <link rel="modulepreload" crossorigin href="./assets/alert-MrQXRIin.js">
189
- <link rel="modulepreload" crossorigin href="./assets/state-BxJ_FX3k.js">
190
- <link rel="modulepreload" crossorigin href="./assets/cell-link-BeZAiE1D.js">
191
- <link rel="modulepreload" crossorigin href="./assets/MarimoErrorOutput-DCu6fm2y.js">
189
+ <link rel="modulepreload" crossorigin href="./assets/state-B85OOscw.js">
190
+ <link rel="modulepreload" crossorigin href="./assets/cell-link-DC1UZQr_.js">
191
+ <link rel="modulepreload" crossorigin href="./assets/MarimoErrorOutput-z5iFryzf.js">
192
192
  <link rel="modulepreload" crossorigin href="./assets/useDateFormatter-CTYCgKB-.js">
193
193
  <link rel="modulepreload" crossorigin href="./assets/en-US-B4U3zuiu.js">
194
194
  <link rel="modulepreload" crossorigin href="./assets/isValid-BEbe1fFs.js">
@@ -207,13 +207,13 @@
207
207
  <link rel="modulepreload" crossorigin href="./assets/formats-DkOlpVdf.js">
208
208
  <link rel="modulepreload" crossorigin href="./assets/table-Dg1KxH-q.js">
209
209
  <link rel="modulepreload" crossorigin href="./assets/react-resizable-panels.browser.esm-BL2E7f5c.js">
210
- <link rel="modulepreload" crossorigin href="./assets/JsonOutput-nqqzL-n0.js">
210
+ <link rel="modulepreload" crossorigin href="./assets/JsonOutput-NVH7GWyC.js">
211
211
  <link rel="modulepreload" crossorigin href="./assets/chart-no-axes-column-B6FT5Xvu.js">
212
212
  <link rel="modulepreload" crossorigin href="./assets/square-function-DyFIOFp5.js">
213
213
  <link rel="modulepreload" crossorigin href="./assets/spec-D9d9nT0z.js">
214
214
  <link rel="modulepreload" crossorigin href="./assets/semaphore-BjoL5P0h.js">
215
215
  <link rel="modulepreload" crossorigin href="./assets/fileToBase64-aqhlf6Jj.js">
216
- <link rel="modulepreload" crossorigin href="./assets/useBoolean-BofUVeKg.js">
216
+ <link rel="modulepreload" crossorigin href="./assets/useBoolean-Co-_MyFz.js">
217
217
  <link rel="modulepreload" crossorigin href="./assets/code-xml-CW65k2pN.js">
218
218
  <link rel="modulepreload" crossorigin href="./assets/file-headphone-DKocX1z0.js">
219
219
  <link rel="modulepreload" crossorigin href="./assets/file-mCR_SMtq.js">
@@ -221,11 +221,11 @@
221
221
  <link rel="modulepreload" crossorigin href="./assets/file-icons-e7tmeyP-.js">
222
222
  <link rel="modulepreload" crossorigin href="./assets/globe-CmFhHoL1.js">
223
223
  <link rel="modulepreload" crossorigin href="./assets/esm-3WkPrffD.js">
224
- <link rel="modulepreload" crossorigin href="./assets/useAddCell-DesMfnE4.js">
225
- <link rel="modulepreload" crossorigin href="./assets/readonly-python-code-D4YGmSvB.js">
224
+ <link rel="modulepreload" crossorigin href="./assets/useAddCell-Bhv6GT3m.js">
225
+ <link rel="modulepreload" crossorigin href="./assets/readonly-python-code-DcYhdd1B.js">
226
226
  <link rel="modulepreload" crossorigin href="./assets/data-grid-types-DgHVN_Zz.js">
227
227
  <link rel="modulepreload" crossorigin href="./assets/glide-utils-BzwA3q-e.js">
228
- <link rel="modulepreload" crossorigin href="./assets/column-preview-DtrgJzVI.js">
228
+ <link rel="modulepreload" crossorigin href="./assets/column-preview-sL_Jo0hX.js">
229
229
  <link rel="modulepreload" crossorigin href="./assets/square-DvOKKLHZ.js">
230
230
  <link rel="modulepreload" crossorigin href="./assets/triangle-alert-BeRqoThc.js">
231
231
  <link rel="modulepreload" crossorigin href="./assets/prop-types-Djf4O40e.js">
@@ -237,11 +237,11 @@
237
237
  <link rel="modulepreload" crossorigin href="./assets/icons-CVdkfEA3.js">
238
238
  <link rel="modulepreload" crossorigin href="./assets/useDeepCompareMemoize-DSlTt6u_.js">
239
239
  <link rel="modulepreload" crossorigin href="./assets/pathUtils-BKesuhdv.js">
240
- <link rel="modulepreload" crossorigin href="./assets/floating-outline-3PlTr0K1.js">
240
+ <link rel="modulepreload" crossorigin href="./assets/floating-outline-K7cVdOlC.js">
241
241
  <link rel="stylesheet" crossorigin href="./assets/cells-0PFKL3SH.css">
242
242
  <link rel="stylesheet" crossorigin href="./assets/markdown-renderer-DjIHoF9Z.css">
243
243
  <link rel="stylesheet" crossorigin href="./assets/JsonOutput-B0GmlMnR.css">
244
- <link rel="stylesheet" crossorigin href="./assets/index-CF8Gfz1R.css">
244
+ <link rel="stylesheet" crossorigin href="./assets/index-B7ZZVUcj.css">
245
245
  </head>
246
246
  <body>
247
247
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/frontend",
3
- "version": "0.25.2-dev66",
3
+ "version": "0.25.2-dev89",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -7,7 +7,7 @@ import { kioskModeAtom } from "@/core/mode";
7
7
  import { connectionAtom } from "@/core/network/connection";
8
8
  import { store } from "@/core/state/jotai";
9
9
  import { isStaticNotebook } from "@/core/static/static-state";
10
- import { WebSocketState } from "@/core/websocket/types";
10
+ import { ConnectionState } from "@/core/websocket/types";
11
11
  import { pairPreviewAtom } from "@/core/config/pair";
12
12
  import { PAIR_PREVIEW } from "./fixtures/pair-preview";
13
13
  import { mount, visibleForTesting } from "../mount";
@@ -59,7 +59,7 @@ describe("mount", () => {
59
59
  store.set(layoutStateAtom, initialLayoutState());
60
60
  store.set(kioskModeAtom, false);
61
61
  // Reset connection atom to initial state
62
- store.set(connectionAtom, { state: WebSocketState.NOT_STARTED });
62
+ store.set(connectionAtom, { state: ConnectionState.NOT_STARTED });
63
63
  });
64
64
 
65
65
  afterEach(() => {
@@ -111,7 +111,7 @@ describe("mount", () => {
111
111
  );
112
112
 
113
113
  const connection = store.get(connectionAtom);
114
- expect(connection.state).toBe(WebSocketState.CONNECTING);
114
+ expect(connection.state).toBe(ConnectionState.CONNECTING);
115
115
  });
116
116
 
117
117
  it("should keep connection as NOT_STARTED when runtimeConfig has lazy=true", () => {
@@ -124,7 +124,7 @@ describe("mount", () => {
124
124
  );
125
125
 
126
126
  const connection = store.get(connectionAtom);
127
- expect(connection.state).toBe(WebSocketState.NOT_STARTED);
127
+ expect(connection.state).toBe(ConnectionState.NOT_STARTED);
128
128
  });
129
129
 
130
130
  it("should keep connection as NOT_STARTED when no runtimeConfig is provided", () => {
@@ -137,7 +137,7 @@ describe("mount", () => {
137
137
  );
138
138
 
139
139
  const connection = store.get(connectionAtom);
140
- expect(connection.state).toBe(WebSocketState.NOT_STARTED);
140
+ expect(connection.state).toBe(ConnectionState.NOT_STARTED);
141
141
  });
142
142
 
143
143
  it("should keep connection as NOT_STARTED for static notebooks even with lazy=false", () => {
@@ -155,7 +155,7 @@ describe("mount", () => {
155
155
  );
156
156
 
157
157
  const connection = store.get(connectionAtom);
158
- expect(connection.state).toBe(WebSocketState.NOT_STARTED);
158
+ expect(connection.state).toBe(ConnectionState.NOT_STARTED);
159
159
  });
160
160
  });
161
161
 
@@ -5,7 +5,7 @@ import { useImperativeModal } from "@/components/modal/ImperativeModal";
5
5
  import { AlertDialogDestructiveAction } from "@/components/ui/alert-dialog";
6
6
  import { connectionAtom } from "@/core/network/connection";
7
7
  import { useRequestClient } from "@/core/network/requests";
8
- import { WebSocketState } from "@/core/websocket/types";
8
+ import { ConnectionState } from "@/core/websocket/types";
9
9
  import { reloadSafe } from "@/utils/reload-safe";
10
10
 
11
11
  export function useRestartKernel() {
@@ -22,7 +22,7 @@ export function useRestartKernel() {
22
22
  confirmAction: (
23
23
  <AlertDialogDestructiveAction
24
24
  onClick={async () => {
25
- setConnection({ state: WebSocketState.CLOSING });
25
+ setConnection({ state: ConnectionState.CLOSING });
26
26
  await sendRestart();
27
27
  reloadSafe();
28
28
  }}
@@ -8,16 +8,22 @@ import { alertAtom, getPackageAlert } from "@/core/alerts/state";
8
8
  import { notebookAtom } from "@/core/cells/cells";
9
9
  import { CellId } from "@/core/cells/ids";
10
10
  import { AppConfigSchema } from "@/core/config/config-schema";
11
+ import { kernelStartupErrorAtom } from "@/core/errors/state";
11
12
  import { connectionAtom } from "@/core/network/connection";
12
13
  import { sandboxAtom, sandboxSyncAtom } from "@/core/packages/sandbox-state";
13
- import { WebSocketClosedReason, WebSocketState } from "@/core/websocket/types";
14
+ import { WebSocketClosedReason, ConnectionState } from "@/core/websocket/types";
14
15
  import { chromeAtom } from "../../chrome/state";
16
+ import { runtimeDetailsExpandedAtom } from "../../chrome/panels/runtime-details-state";
15
17
  import { ConnectionNotice } from "../connection-notice";
16
18
 
17
19
  beforeEach(() => vi.useFakeTimers());
18
20
  afterEach(() => vi.useRealTimers());
19
21
 
20
- function mount(existingCells = false) {
22
+ function mount({
23
+ existingCells = false,
24
+ onRetry = vi.fn(),
25
+ canOpenPackages = true,
26
+ } = {}) {
21
27
  const store = createStore();
22
28
  store.set(sandboxAtom, {
23
29
  backend: "pixi",
@@ -25,7 +31,7 @@ function mount(existingCells = false) {
25
31
  filename: "notebook.py",
26
32
  });
27
33
  store.set(connectionAtom, {
28
- state: WebSocketState.CONNECTING,
34
+ state: ConnectionState.CONNECTING,
29
35
  phase: "preparing-environment",
30
36
  });
31
37
  if (existingCells) {
@@ -40,7 +46,8 @@ function mount(existingCells = false) {
40
46
  <Provider store={store}>
41
47
  <ConnectionNotice
42
48
  appConfig={AppConfigSchema.parse({})}
43
- onRetry={vi.fn()}
49
+ onRetry={onRetry}
50
+ canOpenPackages={canOpenPackages}
44
51
  />
45
52
  </Provider>,
46
53
  );
@@ -57,13 +64,13 @@ it("shows both stages in an empty notebook, checks them off, then dismisses Read
57
64
  expect(steps.getByText("Start kernel")).toBeInTheDocument();
58
65
  act(() =>
59
66
  store.set(connectionAtom, {
60
- state: WebSocketState.CONNECTING,
67
+ state: ConnectionState.CONNECTING,
61
68
  phase: "starting-kernel",
62
69
  }),
63
70
  );
64
71
  expect(steps.getByText("Environment prepared")).toBeInTheDocument();
65
72
  expect(steps.getByText("Starting kernel")).toBeInTheDocument();
66
- act(() => store.set(connectionAtom, { state: WebSocketState.OPEN }));
73
+ act(() => store.set(connectionAtom, { state: ConnectionState.OPEN }));
67
74
  expect(
68
75
  screen.getByRole("heading", { name: "Your notebook is ready" }),
69
76
  ).toBeInTheDocument();
@@ -78,8 +85,122 @@ it("shows both stages in an empty notebook, checks them off, then dismisses Read
78
85
  ).not.toBeInTheDocument();
79
86
  });
80
87
 
88
+ it("uses the shared kernel stage for an ordinary connection and dismisses it when connected", () => {
89
+ const store = mount();
90
+ act(() => {
91
+ store.set(sandboxAtom, null);
92
+ store.set(connectionAtom, { state: ConnectionState.CONNECTING });
93
+ });
94
+ act(() => vi.advanceTimersByTime(500));
95
+ const stages = within(
96
+ screen.getByRole("list", {
97
+ name: "Notebook startup stages",
98
+ }),
99
+ );
100
+ expect(stages.getAllByRole("listitem")).toHaveLength(1);
101
+ expect(stages.getByText("Starting kernel")).toBeVisible();
102
+ act(() => store.set(connectionAtom, { state: ConnectionState.OPEN }));
103
+ expect(screen.queryByRole("region", { name: "Notebook startup" })).toBeNull();
104
+ });
105
+
106
+ it("shows connection status until a sandbox reports its startup phase", () => {
107
+ const store = mount();
108
+ act(() => store.set(connectionAtom, { state: ConnectionState.CONNECTING }));
109
+ act(() => vi.advanceTimersByTime(500));
110
+ expect(screen.getByRole("heading", { name: "Connecting…" })).toBeVisible();
111
+ expect(screen.queryByRole("list")).not.toBeInTheDocument();
112
+
113
+ act(() =>
114
+ store.set(connectionAtom, {
115
+ state: ConnectionState.CLOSED,
116
+ code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
117
+ reason: "Kernel startup failed",
118
+ }),
119
+ );
120
+ expect(
121
+ screen.getByRole("heading", { name: "Kernel failed to start" }),
122
+ ).toBeVisible();
123
+ expect(screen.queryByRole("list")).not.toBeInTheDocument();
124
+
125
+ act(() =>
126
+ store.set(connectionAtom, {
127
+ state: ConnectionState.CONNECTING,
128
+ phase: "preparing-environment",
129
+ }),
130
+ );
131
+ act(() => vi.advanceTimersByTime(500));
132
+ expect(screen.getByRole("list")).toHaveTextContent("Preparing environment");
133
+ });
134
+
135
+ it("shows kernel startup while sandbox metadata is loading, then adds environment preparation", () => {
136
+ const store = mount();
137
+ const sandbox = store.get(sandboxAtom);
138
+ act(() => store.set(sandboxAtom, null));
139
+ act(() => vi.advanceTimersByTime(500));
140
+ expect(screen.getByText("Starting kernel")).toBeVisible();
141
+ expect(screen.getAllByRole("listitem")).toHaveLength(1);
142
+
143
+ act(() => store.set(sandboxAtom, sandbox));
144
+ const stages = within(screen.getByRole("list"));
145
+ expect(stages.getByText("Preparing environment")).toBeVisible();
146
+ expect(stages.getByText("Start kernel")).toBeVisible();
147
+ });
148
+
149
+ it("shows ordinary environment preparation failures in the kernel stage", () => {
150
+ const store = mount();
151
+ act(() => store.set(sandboxAtom, null));
152
+ act(() => vi.advanceTimersByTime(500));
153
+ expect(screen.getByText("Starting kernel")).toBeVisible();
154
+ expect(screen.getAllByRole("listitem")).toHaveLength(1);
155
+ act(() => {
156
+ store.set(
157
+ kernelStartupErrorAtom,
158
+ "Configured Python environment is missing",
159
+ );
160
+ store.set(connectionAtom, {
161
+ state: ConnectionState.CLOSED,
162
+ phase: "preparing-environment",
163
+ code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
164
+ reason: "Kernel startup failed",
165
+ });
166
+ });
167
+ expect(screen.getByRole("listitem")).toHaveTextContent(
168
+ "Kernel failed to start",
169
+ );
170
+ expect(screen.getByRole("status")).toHaveTextContent(
171
+ "Kernel failed to start",
172
+ );
173
+ expect(screen.getByLabelText("Error details")).toHaveTextContent(
174
+ "Configured Python environment is missing",
175
+ );
176
+ });
177
+
178
+ it("reports the inline disclosure as expanded only when Packages and runtime details are open", () => {
179
+ const store = mount({ existingCells: true });
180
+ act(() => {
181
+ store.set(chromeAtom, (value) => ({
182
+ ...value,
183
+ isSidebarOpen: true,
184
+ selectedPanel: "packages",
185
+ }));
186
+ store.set(runtimeDetailsExpandedAtom, false);
187
+ });
188
+ act(() => vi.advanceTimersByTime(500));
189
+ const toggle = screen.getByRole("button", { name: /Open Packages/ });
190
+ expect(toggle).toHaveAttribute("aria-expanded", "false");
191
+ fireEvent.click(toggle);
192
+ expect(toggle).toHaveAttribute("aria-expanded", "true");
193
+ act(() => store.set(runtimeDetailsExpandedAtom, false));
194
+ expect(toggle).toHaveAttribute("aria-expanded", "false");
195
+ act(() => {
196
+ store.set(runtimeDetailsExpandedAtom, true);
197
+ store.set(chromeAtom, (value) => ({ ...value, isSidebarOpen: false }));
198
+ });
199
+ expect(toggle).toHaveAttribute("aria-expanded", "false");
200
+ });
201
+
81
202
  it("opens Packages from the minimal inline status when cells exist", () => {
82
- const store = mount(true);
203
+ const store = mount({ existingCells: true });
83
204
  act(() => vi.advanceTimersByTime(500));
84
205
  expect(screen.queryByRole("list")).not.toBeInTheDocument();
85
206
  fireEvent.click(screen.getByRole("button", { name: /Open Packages/ }));
@@ -87,14 +208,100 @@ it("opens Packages from the minimal inline status when cells exist", () => {
87
208
  isSidebarOpen: true,
88
209
  selectedPanel: "packages",
89
210
  });
90
- act(() => store.set(connectionAtom, { state: WebSocketState.OPEN }));
211
+ act(() => store.set(connectionAtom, { state: ConnectionState.OPEN }));
91
212
  expect(screen.getByRole("status")).toHaveTextContent(/^Ready$/);
92
213
  });
93
214
 
215
+ it("uses an inline notice for an existing ordinary notebook, opens collapsed details, and offers retry on failure", () => {
216
+ const onRetry = vi.fn();
217
+ const store = mount({ existingCells: true, onRetry });
218
+ act(() => {
219
+ store.set(sandboxAtom, null);
220
+ store.set(connectionAtom, { state: ConnectionState.CONNECTING });
221
+ store.set(runtimeDetailsExpandedAtom, false);
222
+ });
223
+ act(() => vi.advanceTimersByTime(500));
224
+ const statusRow = screen.getByRole("region", {
225
+ name: "Notebook startup",
226
+ }).parentElement;
227
+ fireEvent.click(screen.getByRole("button", { name: /Open Packages/ }));
228
+ expect(store.get(chromeAtom)).toMatchObject({
229
+ isSidebarOpen: true,
230
+ selectedPanel: "packages",
231
+ });
232
+ expect(store.get(runtimeDetailsExpandedAtom)).toBe(true);
233
+ act(() =>
234
+ store.set(connectionAtom, {
235
+ state: ConnectionState.CLOSED,
236
+ code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
237
+ reason: "Kernel startup failed",
238
+ }),
239
+ );
240
+ expect(
241
+ screen.getByRole("button", {
242
+ name: /Kernel failed to start Open Packages/,
243
+ }),
244
+ ).toBeVisible();
245
+ fireEvent.click(screen.getByRole("button", { name: "Try again" }));
246
+ expect(onRetry).toHaveBeenCalledOnce();
247
+ act(() => store.set(connectionAtom, { state: ConnectionState.OPEN }));
248
+ expect(screen.queryByRole("region", { name: "Notebook startup" })).toBeNull();
249
+ expect(statusRow).not.toBeInTheDocument();
250
+ });
251
+
252
+ it.each([
253
+ { existingCells: false, sandbox: false },
254
+ { existingCells: true, sandbox: false },
255
+ { existingCells: false, sandbox: true },
256
+ { existingCells: true, sandbox: true },
257
+ ])(
258
+ "keeps errors in the notebook without chrome (cells=$existingCells, sandbox=$sandbox)",
259
+ ({ existingCells, sandbox }) => {
260
+ const onRetry = vi.fn();
261
+ const store = mount({ existingCells, onRetry, canOpenPackages: false });
262
+ act(() => {
263
+ if (!sandbox) {
264
+ store.set(sandboxAtom, null);
265
+ }
266
+ store.set(connectionAtom, {
267
+ state: ConnectionState.CONNECTING,
268
+ phase: "starting-kernel",
269
+ });
270
+ });
271
+ act(() => vi.advanceTimersByTime(500));
272
+ expect(screen.getByText("Starting kernel")).toBeVisible();
273
+ expect(screen.getByRole("status")).toHaveTextContent("Starting kernel…");
274
+ expect(screen.queryByRole("button")).not.toBeInTheDocument();
275
+
276
+ act(() => {
277
+ store.set(kernelStartupErrorAtom, "Could not import the runtime");
278
+ store.set(connectionAtom, {
279
+ state: ConnectionState.CLOSED,
280
+ phase: "starting-kernel",
281
+ code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
282
+ reason: "Kernel startup failed",
283
+ });
284
+ });
285
+ expect(screen.getByLabelText("Error details")).toHaveTextContent(
286
+ "Could not import the runtime",
287
+ );
288
+ expect(screen.getByRole("status")).toHaveTextContent(
289
+ "Kernel failed to start",
290
+ );
291
+ expect(
292
+ screen.queryByRole("button", { name: /Open Packages/ }),
293
+ ).not.toBeInTheDocument();
294
+ if (!sandbox) {
295
+ fireEvent.click(screen.getByRole("button", { name: "Try again" }));
296
+ }
297
+ expect(onRetry).toHaveBeenCalledTimes(sandbox ? 0 : 1);
298
+ },
299
+ );
300
+
94
301
  it("does not flash Ready for a startup that finished before the notice appeared", () => {
95
- const store = mount(true);
302
+ const store = mount({ existingCells: true });
96
303
  act(() => vi.advanceTimersByTime(200));
97
- act(() => store.set(connectionAtom, { state: WebSocketState.OPEN }));
304
+ act(() => store.set(connectionAtom, { state: ConnectionState.OPEN }));
98
305
  expect(screen.queryByRole("status")).not.toBeInTheDocument();
99
306
  act(() => vi.advanceTimersByTime(2000));
100
307
  expect(screen.queryByRole("status")).not.toBeInTheDocument();
@@ -103,11 +310,11 @@ it("does not flash Ready for a startup that finished before the notice appeared"
103
310
  it("replaces Ready with a new attempt and never dismisses a failure", () => {
104
311
  const store = mount();
105
312
  act(() => vi.advanceTimersByTime(500));
106
- act(() => store.set(connectionAtom, { state: WebSocketState.OPEN }));
313
+ act(() => store.set(connectionAtom, { state: ConnectionState.OPEN }));
107
314
  act(() => vi.advanceTimersByTime(1000));
108
315
  act(() =>
109
316
  store.set(connectionAtom, {
110
- state: WebSocketState.CONNECTING,
317
+ state: ConnectionState.CONNECTING,
111
318
  phase: "starting-kernel",
112
319
  }),
113
320
  );
@@ -115,7 +322,7 @@ it("replaces Ready with a new attempt and never dismisses a failure", () => {
115
322
  expect(screen.getByText("Starting kernel")).toBeInTheDocument();
116
323
  act(() =>
117
324
  store.set(connectionAtom, {
118
- state: WebSocketState.CLOSED,
325
+ state: ConnectionState.CLOSED,
119
326
  code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
120
327
  phase: "starting-kernel",
121
328
  reason: "Kernel startup failed",
@@ -128,9 +335,9 @@ it("replaces Ready with a new attempt and never dismisses a failure", () => {
128
335
  });
129
336
 
130
337
  it("shows a sync as a single operation, without pretending to restart the kernel", () => {
131
- const store = mount(true);
338
+ const store = mount({ existingCells: true });
132
339
  act(() => {
133
- store.set(connectionAtom, { state: WebSocketState.OPEN });
340
+ store.set(connectionAtom, { state: ConnectionState.OPEN });
134
341
  store.set(sandboxSyncAtom, { kind: "running" });
135
342
  });
136
343
  act(() => vi.advanceTimersByTime(500));
@@ -141,7 +348,7 @@ it("shows a sync as a single operation, without pretending to restart the kernel
141
348
  });
142
349
 
143
350
  it("restores syncing in the existing status and stays quiet for a completed snapshot", () => {
144
- const store = mount(true);
351
+ const store = mount({ existingCells: true });
145
352
  const operation: EnvironmentOperation = {
146
353
  operation_id: "sync",
147
354
  action: "sync",
@@ -162,7 +369,7 @@ it("restores syncing in the existing status and stays quiet for a completed snap
162
369
  },
163
370
  }));
164
371
  act(() => {
165
- store.set(connectionAtom, { state: WebSocketState.OPEN });
372
+ store.set(connectionAtom, { state: ConnectionState.OPEN });
166
373
  restore({ kind: "succeeded" });
167
374
  });
168
375
  act(() => vi.advanceTimersByTime(2000));
@@ -0,0 +1,61 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+ import type { PropsWithChildren } from "react";
3
+ import type { DisplayConnectionNotice } from "@/core/network/useConnectionNotice";
4
+ import { cn } from "@/utils/cn";
5
+ import {
6
+ ConnectionStatusIcon,
7
+ hasStartupStages,
8
+ StartupProgress,
9
+ } from "./startup-progress";
10
+
11
+ export function ConnectionErrorOutput({ error }: { error: string }) {
12
+ return (
13
+ <pre
14
+ tabIndex={0}
15
+ aria-label="Error details"
16
+ className="mt-3 p-3 rounded border bg-muted/30 text-xs text-muted-foreground whitespace-pre min-w-0 max-w-full max-h-52 overflow-auto"
17
+ >
18
+ {error}
19
+ </pre>
20
+ );
21
+ }
22
+
23
+ export function ConnectionDetails({
24
+ notice,
25
+ surface = "sidebar",
26
+ children,
27
+ }: PropsWithChildren<{
28
+ notice: DisplayConnectionNotice;
29
+ surface?: "notebook" | "sidebar";
30
+ }>) {
31
+ const showSteps = hasStartupStages(notice);
32
+ const failed = !notice.pending && !notice.ready;
33
+ return (
34
+ <div className="min-w-0 text-sm">
35
+ {showSteps ? (
36
+ <StartupProgress notice={notice} surface={surface} />
37
+ ) : (
38
+ <div className="flex items-center gap-2" role="status">
39
+ <ConnectionStatusIcon notice={notice} />
40
+ <h2
41
+ className={cn(
42
+ surface === "notebook" && "text-base",
43
+ failed ? "font-medium text-(--red-11)" : "text-foreground",
44
+ )}
45
+ >
46
+ {notice.title}
47
+ </h2>
48
+ </div>
49
+ )}
50
+ {(failed || (!showSteps && surface === "notebook")) && (
51
+ <p className={cn("mt-2", failed && "text-foreground")}>
52
+ {notice.description}
53
+ </p>
54
+ )}
55
+ {notice.error && (surface === "sidebar" || !notice.sandbox) && (
56
+ <ConnectionErrorOutput error={notice.error} />
57
+ )}
58
+ {children}
59
+ </div>
60
+ );
61
+ }