@jupyter/chat 0.23.0-alpha.2 → 0.23.0-alpha.4

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.
@@ -8,12 +8,12 @@
8
8
  * Originally adapted from jupyterlab-chat's ChatPanel
9
9
  */
10
10
 
11
- import { InputDialog } from '@jupyterlab/apputils';
11
+ import { InputDialog, ToolbarRegistry } from '@jupyterlab/apputils';
12
+ import { IObservableList } from '@jupyterlab/observables';
12
13
  import { nullTranslator, TranslationBundle } from '@jupyterlab/translation';
13
14
  import {
14
15
  addIcon,
15
16
  closeIcon,
16
- launchIcon,
17
17
  PanelWithToolbar,
18
18
  ReactiveToolbar,
19
19
  ReactWidget,
@@ -37,9 +37,10 @@ import {
37
37
  IInputToolbarRegistryFactory
38
38
  } from '../components';
39
39
  import { TRANSLATION_DOMAIN } from '../context';
40
- import { chatIcon, readIcon } from '../icons';
40
+ import { chatIcon } from '../icons';
41
41
  import { IChatModel } from '../model';
42
- import { IChatPlaceholderFactory } from '../tokens';
42
+ import { IChatPanel, IChatPlaceholderFactory } from '../tokens';
43
+ import { ChatArea } from '../types';
43
44
 
44
45
  const SIDEPANEL_CLASS = 'jp-chat-sidepanel';
45
46
  const ADD_BUTTON_CLASS = 'jp-chat-add';
@@ -86,10 +87,10 @@ export class MultiChatPanel extends PanelWithToolbar {
86
87
 
87
88
  this._chatOptions = options;
88
89
  this._inputToolbarFactory = options.inputToolbarFactory;
90
+ this._chatToolbarFactory = options.chatToolbarFactory;
89
91
 
90
92
  this._getChatNames = options.getChatNames;
91
93
  this._createModel = options.createModel;
92
- this._openInMain = options.openInMain;
93
94
  this._renameChat = options.renameChat;
94
95
  this._placeholderFactory = options.placeholderFactory;
95
96
 
@@ -101,6 +102,7 @@ export class MultiChatPanel extends PanelWithToolbar {
101
102
  this.open(addChatArgs);
102
103
  },
103
104
  icon: addIcon,
105
+ label: this._trans.__('New chat'),
104
106
  tooltip: this._trans.__('Create a new chat')
105
107
  });
106
108
  addChat.addClass(ADD_BUTTON_CLASS);
@@ -149,9 +151,9 @@ export class MultiChatPanel extends PanelWithToolbar {
149
151
  }
150
152
 
151
153
  /**
152
- * A signal emitting when a chat widget is opened in the panel.
154
+ * A signal emitting when a chat panel is opened in the sidepanel.
153
155
  */
154
- get chatOpened(): ISignal<MultiChatPanel, ChatWidget> {
156
+ get chatOpened(): ISignal<MultiChatPanel, IChatPanel> {
155
157
  return this._chatOpened;
156
158
  }
157
159
 
@@ -293,8 +295,8 @@ export class MultiChatPanel extends PanelWithToolbar {
293
295
  const widget = new SidePanelWidget({
294
296
  widget: chatWidget,
295
297
  displayName: name,
296
- openInMain: this._openInMain,
297
298
  renameChat: this._renameChat,
299
+ toolbarFactory: this._chatToolbarFactory,
298
300
  onClose: (name: string, disposeModel = true) => {
299
301
  this.unsetLoadedModel(name, disposeModel);
300
302
  },
@@ -313,7 +315,7 @@ export class MultiChatPanel extends PanelWithToolbar {
313
315
  this._chatSelectorPopup.setCurrentChat(name);
314
316
  }
315
317
 
316
- this._chatOpened.emit(chatWidget);
318
+ this._chatOpened.emit(widget);
317
319
  return chatWidget;
318
320
  }
319
321
 
@@ -437,20 +439,22 @@ export class MultiChatPanel extends PanelWithToolbar {
437
439
  this._chatSelectorPopup?.hide();
438
440
  };
439
441
 
440
- private _chatOpened = new Signal<MultiChatPanel, ChatWidget>(this);
442
+ private _chatOpened = new Signal<MultiChatPanel, IChatPanel>(this);
441
443
  private _chatNamesChanged = new Signal<
442
444
  MultiChatPanel,
443
445
  { [name: string]: string }
444
446
  >(this);
445
447
  private _chatOptions: Omit<Chat.IOptions, 'model' | 'inputToolbarRegistry'>;
446
448
  private _inputToolbarFactory?: IInputToolbarRegistryFactory;
449
+ private _chatToolbarFactory?: (
450
+ panel: IChatPanel
451
+ ) => IObservableList<ToolbarRegistry.IToolbarItem>;
447
452
  private _updateChatListDebouncer: Debouncer;
448
453
 
449
454
  private _createModel?: (
450
455
  name?: string
451
456
  ) => Promise<MultiChatPanel.IOpenChatArgs>;
452
457
  private _getChatNames?: () => Promise<{ [name: string]: string }>;
453
- private _openInMain?: (name: string) => Promise<boolean>;
454
458
  private _renameChat?: boolean | ((oldName: string) => Promise<string | null>);
455
459
  private _placeholderFactory?: IChatPlaceholderFactory;
456
460
  private _openChatWidget?: ReactWidget;
@@ -476,6 +480,12 @@ export namespace MultiChatPanel {
476
480
  * The input toolbar factory;
477
481
  */
478
482
  inputToolbarFactory?: IInputToolbarRegistryFactory;
483
+ /**
484
+ * An optional toolbar factory for each opened chat.
485
+ */
486
+ chatToolbarFactory?: (
487
+ panel: IChatPanel
488
+ ) => IObservableList<ToolbarRegistry.IToolbarItem>;
479
489
  /**
480
490
  * An optional callback to create a chat model.
481
491
  *
@@ -489,12 +499,6 @@ export namespace MultiChatPanel {
489
499
  * @returns an object mapping chat display names to identifiers.
490
500
  */
491
501
  getChatNames?: () => Promise<{ [name: string]: string }>;
492
- /**
493
- * An optional callback to open the chat in the main area.
494
- *
495
- * @param name - the name of the chat to move.
496
- */
497
- openInMain?: (name: string) => Promise<boolean>;
498
502
  /**
499
503
  * An optional callback to rename a chat.
500
504
  *
@@ -531,7 +535,7 @@ export namespace MultiChatPanel {
531
535
  /**
532
536
  * A widget containing the chat and its toolbar.
533
537
  */
534
- class SidePanelWidget extends ReactivePanelWithToolbar {
538
+ class SidePanelWidget extends ReactivePanelWithToolbar implements IChatPanel {
535
539
  constructor(options: SidePanelWidget.IOptions) {
536
540
  super();
537
541
  this._chatWidget = options.widget;
@@ -557,19 +561,6 @@ class SidePanelWidget extends ReactivePanelWithToolbar {
557
561
  // Add the chat widget
558
562
  this.addWidget(this._chatWidget);
559
563
 
560
- // Add toolbar buttons
561
- this._markAsRead = new ToolbarButton({
562
- icon: readIcon,
563
- iconLabel: trans.__('Mark chat as read'),
564
- className: 'jp-mod-styled',
565
- onClick: () => {
566
- if (this.model) {
567
- this.model.unreadMessages = [];
568
- }
569
- }
570
- });
571
- this.toolbar.addItem('markRead', this._markAsRead);
572
-
573
564
  if (options.renameChat) {
574
565
  const renameButton = new ToolbarButton({
575
566
  iconClass: 'jp-EditIcon',
@@ -606,21 +597,6 @@ class SidePanelWidget extends ReactivePanelWithToolbar {
606
597
  this.toolbar.addItem('rename', renameButton);
607
598
  }
608
599
 
609
- if (options.openInMain) {
610
- const moveToMain = new ToolbarButton({
611
- icon: launchIcon,
612
- iconLabel: trans.__('Move the chat to the main area'),
613
- className: 'jp-mod-styled',
614
- onClick: async () => {
615
- const name = this.model.name;
616
- if (await options.openInMain?.(name)) {
617
- options.onClose(this._displayName, false);
618
- }
619
- }
620
- });
621
- this.toolbar.addItem('moveMain', moveToMain);
622
- }
623
-
624
600
  const closeButton = new ToolbarButton({
625
601
  icon: closeIcon,
626
602
  iconLabel: trans.__('Close the chat'),
@@ -631,9 +607,24 @@ class SidePanelWidget extends ReactivePanelWithToolbar {
631
607
  });
632
608
  this.toolbar.addItem('close', closeButton);
633
609
 
634
- // Update mark as read button state
635
- this.model.unreadChanged?.connect(this._unreadChanged);
636
- this._markAsRead.enabled = (this.model?.unreadMessages.length ?? 0) > 0;
610
+ if (options.toolbarFactory) {
611
+ const items = options.toolbarFactory(this);
612
+ for (let i = 0; i < items.length; i++) {
613
+ const { name, widget } = items.get(i);
614
+ this.toolbar.insertBefore('close', name, widget);
615
+ }
616
+ items.changed.connect((_, change) => {
617
+ if (change.type === 'add') {
618
+ for (const { name, widget } of change.newValues) {
619
+ this.toolbar.insertBefore('close', name, widget);
620
+ }
621
+ } else if (change.type === 'remove') {
622
+ for (const { widget } of change.oldValues) {
623
+ widget.dispose();
624
+ }
625
+ }
626
+ });
627
+ }
637
628
  }
638
629
 
639
630
  protected onAfterAttach(msg: Message): void {
@@ -646,6 +637,13 @@ class SidePanelWidget extends ReactivePanelWithToolbar {
646
637
  this._updateReactiveToolbar();
647
638
  }
648
639
 
640
+ /**
641
+ * The area of the widget.
642
+ */
643
+ get area(): ChatArea {
644
+ return 'sidebar';
645
+ }
646
+
649
647
  /**
650
648
  * The chat widget embedded in the sidepanel widget.
651
649
  */
@@ -687,10 +685,6 @@ class SidePanelWidget extends ReactivePanelWithToolbar {
687
685
  * Dispose of the resources held by the widget.
688
686
  */
689
687
  dispose(): void {
690
- const model = this.model;
691
- if (model) {
692
- model.unreadChanged?.disconnect(this._unreadChanged);
693
- }
694
688
  super.dispose();
695
689
  }
696
690
 
@@ -716,13 +710,6 @@ class SidePanelWidget extends ReactivePanelWithToolbar {
716
710
  this.toolbar.insertItem(0, 'title', this._titleWidget);
717
711
  }
718
712
 
719
- /**
720
- * Enable/disable unread icon.
721
- */
722
- private _unreadChanged = (_: IChatModel, unread: number[]) => {
723
- this._markAsRead.enabled = unread.length > 0;
724
- };
725
-
726
713
  /**
727
714
  * Trigger reactive toolbar overflow computation from rendered toolbar size.
728
715
  */
@@ -739,7 +726,6 @@ class SidePanelWidget extends ReactivePanelWithToolbar {
739
726
  }
740
727
 
741
728
  private _chatWidget: ChatWidget;
742
- private _markAsRead: ToolbarButton;
743
729
  private _displayName: string;
744
730
  private _titleWidget: Widget | undefined;
745
731
  private _nameChanged = new Signal<
@@ -768,14 +754,16 @@ namespace SidePanelWidget {
768
754
  * The displayed name of the chat.
769
755
  */
770
756
  displayName?: string;
771
- /**
772
- * The callback to open the chat in main area.
773
- */
774
- openInMain?: (name: string) => Promise<boolean>;
775
757
  /**
776
758
  * The callback to rename the chat.
777
759
  */
778
760
  renameChat?: boolean | ((oldName: string) => Promise<string | null>);
761
+ /**
762
+ * An optional toolbar factory.
763
+ */
764
+ toolbarFactory?: (
765
+ panel: IChatPanel
766
+ ) => IObservableList<ToolbarRegistry.IToolbarItem>;
779
767
  /**
780
768
  * The translation bundle.
781
769
  */
@@ -795,7 +783,7 @@ type ChatSearchInputProps = {
795
783
  /**
796
784
  * Signal emitting when a chat is opened.
797
785
  */
798
- chatOpened: ISignal<MultiChatPanel, ChatWidget>;
786
+ chatOpened: ISignal<MultiChatPanel, IChatPanel>;
799
787
  /**
800
788
  * The translation bundle.
801
789
  */