@jupyter/chat 0.25.0-alpha.5 → 0.25.0-alpha.6

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.
package/lib/model.d.ts CHANGED
@@ -270,6 +270,15 @@ export declare abstract class AbstractChatModel implements IChatModel {
270
270
  * shared-document metadata under RTC).
271
271
  */
272
272
  protected setReady(id: string): void;
273
+ /**
274
+ * Mark the chat as failed to become ready, rejecting `ready`.
275
+ *
276
+ * Used when the chat can never become usable - e.g. the WebSocket connection
277
+ * was closed by the server before the connection frame arrived. Consumers of
278
+ * `ready` (such as the widgets that show a loading spinner) can then react to
279
+ * the failure instead of hanging forever.
280
+ */
281
+ protected setError(reason: unknown): void;
273
282
  /**
274
283
  * The chat settings.
275
284
  */
package/lib/model.js CHANGED
@@ -64,8 +64,13 @@ export class AbstractChatModel {
64
64
  this._selectionWatcher = (_d = options.selectionWatcher) !== null && _d !== void 0 ? _d : null;
65
65
  this._documentManager = (_e = options.documentManager) !== null && _e !== void 0 ? _e : null;
66
66
  this._readyDelegate = new PromiseDelegate();
67
- this.ready.then(() => {
67
+ this.ready
68
+ .then(() => {
68
69
  this._inputModel.chatContext = this.createChatContext();
70
+ })
71
+ .catch(() => {
72
+ // `ready` was rejected (the chat failed to open); no context is created.
73
+ // The failure is surfaced to the user by the hosting widget.
69
74
  });
70
75
  }
71
76
  /**
@@ -166,6 +171,17 @@ export class AbstractChatModel {
166
171
  setReady(id) {
167
172
  this._readyDelegate.resolve(id);
168
173
  }
174
+ /**
175
+ * Mark the chat as failed to become ready, rejecting `ready`.
176
+ *
177
+ * Used when the chat can never become usable - e.g. the WebSocket connection
178
+ * was closed by the server before the connection frame arrived. Consumers of
179
+ * `ready` (such as the widgets that show a loading spinner) can then react to
180
+ * the failure instead of hanging forever.
181
+ */
182
+ setError(reason) {
183
+ this._readyDelegate.reject(reason);
184
+ }
169
185
  /**
170
186
  * The chat settings.
171
187
  */
@@ -6,7 +6,7 @@
6
6
  * Multi-chat panel for @jupyter/chat
7
7
  * Originally adapted from jupyterlab-chat's ChatPanel
8
8
  */
9
- import { InputDialog } from '@jupyterlab/apputils';
9
+ import { InputDialog, Notification } from '@jupyterlab/apputils';
10
10
  import { nullTranslator } from '@jupyterlab/translation';
11
11
  import { addIcon, closeIcon, PanelWithToolbar, ReactiveToolbar, ReactWidget, Spinner, Toolbar, ToolbarButton } from '@jupyterlab/ui-components';
12
12
  import { ArrayExt } from '@lumino/algorithm';
@@ -389,8 +389,17 @@ class SidePanelWidget extends ReactivePanelWithToolbar {
389
389
  // Add spinner while loading
390
390
  const spinner = new Spinner();
391
391
  this.addWidget(spinner);
392
- this._chatWidget.model.ready.then(() => {
392
+ this._chatWidget.model.ready
393
+ .then(() => {
393
394
  spinner.dispose();
395
+ })
396
+ .catch(() => {
397
+ // The chat could not be opened (e.g. the server closed the WebSocket
398
+ // because the path was invalid). Dispose the spinner and close this
399
+ // chat so no loading spinner is left hanging; the side panel stays open.
400
+ spinner.dispose();
401
+ Notification.error(trans.__("Unable to open chat at given path: '%1'.", this._chatWidget.model.name));
402
+ options.onClose(this._displayName);
394
403
  });
395
404
  // Add the chat widget
396
405
  this.addWidget(this._chatWidget);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyter/chat",
3
- "version": "0.25.0-alpha.5",
3
+ "version": "0.25.0-alpha.6",
4
4
  "description": "A package that provides UI components that can be used to create a chat in a Jupyterlab extension.",
5
5
  "keywords": [
6
6
  "jupyter",
package/src/model.ts CHANGED
@@ -318,9 +318,14 @@ export abstract class AbstractChatModel implements IChatModel {
318
318
 
319
319
  this._readyDelegate = new PromiseDelegate<string>();
320
320
 
321
- this.ready.then(() => {
322
- this._inputModel.chatContext = this.createChatContext();
323
- });
321
+ this.ready
322
+ .then(() => {
323
+ this._inputModel.chatContext = this.createChatContext();
324
+ })
325
+ .catch(() => {
326
+ // `ready` was rejected (the chat failed to open); no context is created.
327
+ // The failure is surfaced to the user by the hosting widget.
328
+ });
324
329
  }
325
330
 
326
331
  /**
@@ -441,6 +446,18 @@ export abstract class AbstractChatModel implements IChatModel {
441
446
  this._readyDelegate.resolve(id);
442
447
  }
443
448
 
449
+ /**
450
+ * Mark the chat as failed to become ready, rejecting `ready`.
451
+ *
452
+ * Used when the chat can never become usable - e.g. the WebSocket connection
453
+ * was closed by the server before the connection frame arrived. Consumers of
454
+ * `ready` (such as the widgets that show a loading spinner) can then react to
455
+ * the failure instead of hanging forever.
456
+ */
457
+ protected setError(reason: unknown): void {
458
+ this._readyDelegate.reject(reason);
459
+ }
460
+
444
461
  /**
445
462
  * The chat settings.
446
463
  */
@@ -8,7 +8,11 @@
8
8
  * Originally adapted from jupyterlab-chat's ChatPanel
9
9
  */
10
10
 
11
- import { InputDialog, ToolbarRegistry } from '@jupyterlab/apputils';
11
+ import {
12
+ InputDialog,
13
+ Notification,
14
+ ToolbarRegistry
15
+ } from '@jupyterlab/apputils';
12
16
  import { IObservableList } from '@jupyterlab/observables';
13
17
  import { nullTranslator, TranslationBundle } from '@jupyterlab/translation';
14
18
  import {
@@ -554,9 +558,23 @@ class SidePanelWidget extends ReactivePanelWithToolbar implements IChatPanel {
554
558
  // Add spinner while loading
555
559
  const spinner = new Spinner();
556
560
  this.addWidget(spinner);
557
- this._chatWidget.model.ready.then(() => {
558
- spinner.dispose();
559
- });
561
+ this._chatWidget.model.ready
562
+ .then(() => {
563
+ spinner.dispose();
564
+ })
565
+ .catch(() => {
566
+ // The chat could not be opened (e.g. the server closed the WebSocket
567
+ // because the path was invalid). Dispose the spinner and close this
568
+ // chat so no loading spinner is left hanging; the side panel stays open.
569
+ spinner.dispose();
570
+ Notification.error(
571
+ trans.__(
572
+ "Unable to open chat at given path: '%1'.",
573
+ this._chatWidget.model.name
574
+ )
575
+ );
576
+ options.onClose(this._displayName);
577
+ });
560
578
 
561
579
  // Add the chat widget
562
580
  this.addWidget(this._chatWidget);