Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

default errors from server should be connection related only #701

Merged
merged 15 commits into from
Nov 21, 2023
Merged
6 changes: 6 additions & 0 deletions .changeset/purple-lobsters-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'thebe-react': minor
'thebe-core': minor
---

Improved handling of connection errors for local server and binder during the connection attempt and if the kernel or server connection fails. Also simplified the binder connection functionality.
5 changes: 5 additions & 0 deletions .changeset/tiny-trees-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'demo-react': patch
---

Updated the demo to add examples of curfacing the different status and error feeds available; connection (server, session, kernel) vs execution (notebook, cell)
2 changes: 0 additions & 2 deletions apps/demo-react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { NavLink, Outlet, useLocation } from 'react-router-dom';
import './App.css';
import { Connect } from './Connect';
import { ServerMode, ServerModeType } from './ServerMode';
import { ThebeStatusTray } from './ThebeStatusTray';

function App() {
const [mode, setMode] = useState<ServerModeType>('local');
Expand Down Expand Up @@ -54,7 +53,6 @@ function App() {
>
<ServerMode mode={mode} setMode={setMode} />
<Connect />
<ThebeStatusTray />
<Outlet />
</ThebeServerProvider>
</ThebeBundleLoaderProvider>
Expand Down
17 changes: 17 additions & 0 deletions apps/demo-react/src/ConnectionErrorTray.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useThebeLoader, useThebeServer, useThebeSession } from 'thebe-react';

export function ConnectionErrorTray() {
const { error: loaderError } = useThebeLoader();
const { error: serverError } = useThebeServer();
const { error: sessionError } = useThebeSession();
const errors = loaderError || serverError || sessionError;

if (!errors) return null;

return (
<div className="mono not-prose max-w-[80%] m-auto min-h-[3em] border-[1px] border-red-500 relative text-red-500 mt-2">
<div className="absolute px-1 py-[1px] text-xs text-white bg-red-500">connection error</div>
<div className="mt-3 whitespace-pre-wrap">{errors}</div>
</div>
);
}
29 changes: 29 additions & 0 deletions apps/demo-react/src/ConnectionStatusTray.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useState, useEffect } from 'react';
import { ThebeEventData } from 'thebe-core';
import { useThebeServer } from 'thebe-react';

export function ConnectionStatusTray() {
const { connecting, subscribe } = useThebeServer();
const [status, setStatus] = useState<ThebeEventData | null>(null);

useEffect(() => {
if (!subscribe) return;
subscribe((data: ThebeEventData) => {
setStatus(data);
});
}, [subscribe]);

return (
<div className="mono not-prose max-w-[80%] m-auto min-h-[3em] border-[1px] border-blue-500 relative pb-1">
<div className="absolute px-1 py-[1px] text-xs text-white bg-blue-500">connection status</div>
{connecting && <div className="text-blue-500">connecting to server...</div>}
{status && (
<details className="flex justify-center text-center mono" open>
<summary>last status: {`[${status.subject}] ${status.status}`}</summary>
<div className="text-xs whitespace-pre-wrap">{status.message}</div>
</details>
)}
<div></div>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ function ErrorTrayMessage({ errors }: { errors: IThebeNotebookError[] }) {
);
}

export function ErrorTray({ errors }: { errors: IThebeNotebookError[] }) {
export function ExecuteErrorTray({ errors }: { errors: IThebeNotebookError[] }) {
return (
<div className="mt-8 text-sm border border-red-400 text-red-600 px-4 pt-3 rounded relative border-1">
<div className="relative px-4 pt-3 mt-8 text-sm text-red-600 border border-red-400 rounded border-1">
<div>
<span className="font-bold">Error</span> - a page refresh may resolve this. If not, shutdown
this simulation and start another. If the error persists please contact support with a
screenshot of this page, including the error message below.
</div>
<ErrorTrayMessage errors={errors} />
<ErrorTrayMessage errors={errors ?? []} />
</div>
);
}
34 changes: 34 additions & 0 deletions apps/demo-react/src/NotebookErrorTray.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useEffect, useState } from 'react';
import { EventSubject, ThebeEventData, ThebeEventType } from 'thebe-core';
import { useThebeConfig } from 'thebe-react';

export function NotebookErrorTray() {
const { config } = useThebeConfig();
const [errorEvent, setErrorEvent] = useState<ThebeEventData | null>(null);

useEffect(() => {
if (!config) return;
config?.events.on('error' as ThebeEventType, (event: any, data: ThebeEventData) => {
// report execution error events
if ([EventSubject.notebook, EventSubject.cell].includes(data.subject as EventSubject)) {
setErrorEvent(data);
}
});
}, [config]);

if (!errorEvent) return null;

return (
<div className="mono not-prose max-w-[80%] m-auto min-h-[3em] border-[1px] border-red-500 relative text-red-500 mt-2">
<div className="absolute px-1 py-[1px] text-xs text-white bg-red-500">
notebook/cell error
</div>
<details className="flex justify-center text-center mono" open>
<summary>
last status: {`[${errorEvent.subject}] ${errorEvent.status} ${errorEvent.id}`}
</summary>
<div className="text-xs whitespace-pre-wrap">{errorEvent.message}</div>
</details>
</div>
);
}
12 changes: 11 additions & 1 deletion apps/demo-react/src/NotebookPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { ThebeSessionProvider, ThebeRenderMimeRegistryProvider, useThebeServer } from 'thebe-react';
import { ConnectionStatusTray } from './ConnectionStatusTray';
import { ConnectionErrorTray } from './ConnectionErrorTray';
import { NotebookStatusTray } from './NotebookStatusTray';
import { NotebookErrorTray } from './NotebookErrorTray';

export function NotebookPage({ children }: React.PropsWithChildren) {
const { ready, config } = useThebeServer();
Expand All @@ -7,7 +11,13 @@ export function NotebookPage({ children }: React.PropsWithChildren) {
return (
<ThebeRenderMimeRegistryProvider>
<ThebeSessionProvider start path={config?.kernels.path}>
{children}
<>
<ConnectionStatusTray />
<ConnectionErrorTray />
<NotebookStatusTray />
<NotebookErrorTray />
{children}
</>
</ThebeSessionProvider>
</ThebeRenderMimeRegistryProvider>
);
Expand Down
33 changes: 33 additions & 0 deletions apps/demo-react/src/NotebookStatusTray.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useState, useEffect } from 'react';
import { ThebeEventData, ThebeEventType, EventSubject } from 'thebe-core';
import { useThebeConfig } from 'thebe-react';

export function NotebookStatusTray() {
const { config } = useThebeConfig();
const [status, setStatus] = useState<ThebeEventData | null>(null);

useEffect(() => {
if (!config?.events) return;
config?.events?.on('status' as ThebeEventType, (event: any, data: ThebeEventData) => {
// report status events related to execution only
if ([EventSubject.notebook, EventSubject.cell].includes(data.subject as EventSubject)) {
setStatus(data);
}
});
}, [config]);

return (
<div className="mono not-prose max-w-[80%] m-auto min-h-[3em] border-[1px] border-blue-500 relative pb-1 mt-2">
<div className="absolute px-1 py-[1px] text-xs text-white bg-blue-500">
notebook/cell status
</div>
{status && (
<details className="flex justify-center text-center mono" open>
<summary>last status: {`[${status.subject}] ${status.status} ${status.id}`}</summary>
<div className="text-xs whitespace-pre-wrap">{status.message}</div>
</details>
)}
<div></div>
</div>
);
}
31 changes: 0 additions & 31 deletions apps/demo-react/src/ThebeStatusTray.tsx

This file was deleted.

9 changes: 4 additions & 5 deletions apps/demo-react/src/WidgetsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useNotebook } from 'thebe-react';
import JupyterOutputDecoration from './JupyterOutputDecoration';
import { useParams } from 'react-router-dom';
import { ErrorTray } from './ErrorTray';

export function WidgetsPage() {
const { notebookName } = useParams<{ notebookName: string }>();
const { ready, executing, executeAll, errors, cellRefs, cellIds } = useNotebook(
const { ready, executing, executeAll, cellRefs, cellIds } = useNotebook(
notebookName ?? 'widget-test',
async (n) => {
const url = `/${n}.ipynb`;
Expand All @@ -28,7 +27,7 @@ export function WidgetsPage() {
<h4 className="text-sm">
notebook: <code>{notebookName}.ipynb</code>
</h4>
<div className="mt-3 inline-block bg-green-500 text-white text-sm font-bold py-2 px-4 rounded-full">
<div className="inline-block px-4 py-2 mt-3 text-sm font-bold text-white bg-green-500 rounded-full">
{ready ? 'ready' : 'not ready'}
</div>
<div className="mt-4">
Expand All @@ -39,8 +38,8 @@ export function WidgetsPage() {
)}
{executing && 'EXECUTING...'}
</div>
<div className="m-auto max-w-3xl">
{errors && <ErrorTray errors={errors} />}
<div className="max-w-3xl m-auto">
{/* {errors && <ConnectionErrorTray />} */}
{cellRefs.map((ref, idx) => {
return (
<JupyterOutputDecoration key={cellIds[idx]}>
Expand Down
9 changes: 6 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/core/src/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class EventEmitter {
}

triggerError({ status, message }: { status: ErrorStatusEvent; message: string }) {
console.debug(`Error ${message}`);
console.debug(`Error [${this._subject}][${this._id}] ${message}`);

this._config.events.trigger(ThebeEventType.error, {
subject: this._subject,
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export enum ErrorStatusEvent {
'warning' = 'warning',
'executeError' = 'execute-error',
'error' = 'error',
'server' = 'server-error',
'session' = 'session-error',
}

export function errorToMessage(json: IError): string {
Expand Down
Loading
Loading