|
5 | 5 | SuspenseSpinner, |
6 | 6 | ExecutionCount, |
7 | 7 | SyntaxHighlighter, |
| 8 | + ErrorBoundary, |
8 | 9 | } from "@runtimed/components"; |
9 | 10 |
|
10 | 11 | // Jupyter notebook types |
@@ -158,25 +159,31 @@ function CodeCell({ cell, language }: { cell: JupyterCell; language: string }) { |
158 | 159 | <div className="min-w-0 flex-1"> |
159 | 160 | {/* Input */} |
160 | 161 | <div className="overflow-hidden rounded border border-gray-200"> |
161 | | - <SyntaxHighlighter |
162 | | - language={language} |
163 | | - enableCopy={true} |
164 | | - customStyle={{ fontSize: "0.8rem" }} |
| 162 | + <ErrorBoundary |
| 163 | + fallback={<div>Error rendering syntax highlighter</div>} |
165 | 164 | > |
166 | | - {source} |
167 | | - </SyntaxHighlighter> |
| 165 | + <SyntaxHighlighter |
| 166 | + language={language} |
| 167 | + enableCopy={true} |
| 168 | + customStyle={{ fontSize: "0.8rem" }} |
| 169 | + > |
| 170 | + {source} |
| 171 | + </SyntaxHighlighter> |
| 172 | + </ErrorBoundary> |
168 | 173 | </div> |
169 | 174 |
|
170 | 175 | {/* Outputs */} |
171 | 176 | {outputs.length > 0 && ( |
172 | 177 | <div className="mt-2 rounded border border-gray-100 bg-white"> |
173 | | - <SuspenseSpinner> |
174 | | - <OutputsContainer> |
175 | | - {outputs.map((output) => ( |
176 | | - <SingleOutput key={output.id} output={output} /> |
177 | | - ))} |
178 | | - </OutputsContainer> |
179 | | - </SuspenseSpinner> |
| 178 | + <ErrorBoundary fallback={<div>Error rendering outputs</div>}> |
| 179 | + <SuspenseSpinner> |
| 180 | + <OutputsContainer> |
| 181 | + {outputs.map((output) => ( |
| 182 | + <SingleOutput key={output.id} output={output} /> |
| 183 | + ))} |
| 184 | + </OutputsContainer> |
| 185 | + </SuspenseSpinner> |
| 186 | + </ErrorBoundary> |
180 | 187 | </div> |
181 | 188 | )} |
182 | 189 | </div> |
@@ -210,9 +217,11 @@ function MarkdownCell({ cell }: { cell: JupyterCell }) { |
210 | 217 | <div className="flex items-start gap-2"> |
211 | 218 | <div className="w-12 flex-shrink-0" /> |
212 | 219 | <div className="min-w-0 flex-1 p-3"> |
213 | | - <SuspenseSpinner> |
214 | | - <SingleOutput output={markdownOutput} /> |
215 | | - </SuspenseSpinner> |
| 220 | + <ErrorBoundary fallback={<div>Error rendering markdown</div>}> |
| 221 | + <SuspenseSpinner> |
| 222 | + <SingleOutput output={markdownOutput} /> |
| 223 | + </SuspenseSpinner> |
| 224 | + </ErrorBoundary> |
216 | 225 | </div> |
217 | 226 | </div> |
218 | 227 | </div> |
@@ -243,24 +252,26 @@ export function NotebookRenderer({ notebook }: { notebook: JupyterNotebook }) { |
243 | 252 |
|
244 | 253 | return ( |
245 | 254 | <div className="notebook-preview py-4 pr-4 pl-2"> |
246 | | - {notebook.cells.map((cell, index) => { |
247 | | - switch (cell.cell_type) { |
248 | | - case "code": |
249 | | - return ( |
250 | | - <CodeCell |
251 | | - key={cell.id || index} |
252 | | - cell={cell} |
253 | | - language={language} |
254 | | - /> |
255 | | - ); |
256 | | - case "markdown": |
257 | | - return <MarkdownCell key={cell.id || index} cell={cell} />; |
258 | | - case "raw": |
259 | | - return <RawCell key={cell.id || index} cell={cell} />; |
260 | | - default: |
261 | | - return null; |
262 | | - } |
263 | | - })} |
| 255 | + <ErrorBoundary fallback={<div>Error rendering notebook</div>}> |
| 256 | + {notebook.cells.map((cell, index) => { |
| 257 | + switch (cell.cell_type) { |
| 258 | + case "code": |
| 259 | + return ( |
| 260 | + <CodeCell |
| 261 | + key={cell.id || index} |
| 262 | + cell={cell} |
| 263 | + language={language} |
| 264 | + /> |
| 265 | + ); |
| 266 | + case "markdown": |
| 267 | + return <MarkdownCell key={cell.id || index} cell={cell} />; |
| 268 | + case "raw": |
| 269 | + return <RawCell key={cell.id || index} cell={cell} />; |
| 270 | + default: |
| 271 | + return null; |
| 272 | + } |
| 273 | + })} |
| 274 | + </ErrorBoundary> |
264 | 275 | </div> |
265 | 276 | ); |
266 | 277 | } |
0 commit comments