From f3ba6e06ea09740303a9c9ceeeea494e5fcc63f7 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet <32258950+brichet@users.noreply.github.com> Date: Fri, 7 Jun 2024 13:58:31 +0200 Subject: [PATCH] Add the panel tracker to the chat factory token (#47) * Add the panel tracker to the factory token, and make some refactoring * Fix tests --- packages/jupyter-chat/src/components/chat.tsx | 24 ++++++++--------- .../schema/{factories.json => factory.json} | 6 +++++ .../src/factory.ts | 12 ++++----- .../src/index.ts | 27 ++++++++++--------- .../src/token.ts | 27 ++++++++++++++----- .../src/widget.tsx | 2 +- .../jupyterlab_collaborative_chat.spec.ts | 2 +- 7 files changed, 60 insertions(+), 40 deletions(-) rename packages/jupyterlab-collaborative-chat/schema/{factories.json => factory.json} (92%) diff --git a/packages/jupyter-chat/src/components/chat.tsx b/packages/jupyter-chat/src/components/chat.tsx index 175cbbd..f7f2c70 100644 --- a/packages/jupyter-chat/src/components/chat.tsx +++ b/packages/jupyter-chat/src/components/chat.tsx @@ -51,9 +51,7 @@ function ChatBody({ } export function Chat(props: Chat.IOptions): JSX.Element { - const [view, setView] = useState( - props.chatView || Chat.ChatView.Chat - ); + const [view, setView] = useState(props.chatView || Chat.View.chat); return ( {/* top bar */} - {view !== Chat.ChatView.Chat ? ( - setView(Chat.ChatView.Chat)}> + {view !== Chat.View.chat ? ( + setView(Chat.View.chat)}> ) : ( )} - {view === Chat.ChatView.Chat && props.settingsPanel ? ( - setView(Chat.ChatView.Settings)}> + {view !== Chat.View.settings && props.settingsPanel ? ( + setView(Chat.View.settings)}> ) : ( @@ -86,10 +84,10 @@ export function Chat(props: Chat.IOptions): JSX.Element { )} {/* body */} - {view === Chat.ChatView.Chat && ( + {view === Chat.View.chat && ( )} - {view === Chat.ChatView.Settings && props.settingsPanel && ( + {view === Chat.View.settings && props.settingsPanel && ( )} @@ -120,7 +118,7 @@ export namespace Chat { /** * The view to render. */ - chatView?: ChatView; + chatView?: View; /** * A settings panel that can be used for dedicated settings (e.g. jupyter-ai) */ @@ -131,8 +129,8 @@ export namespace Chat { * The view to render. * The settings view is available only if the settings panel is provided in options. */ - export enum ChatView { - Chat, - Settings + export enum View { + chat, + settings } } diff --git a/packages/jupyterlab-collaborative-chat/schema/factories.json b/packages/jupyterlab-collaborative-chat/schema/factory.json similarity index 92% rename from packages/jupyterlab-collaborative-chat/schema/factories.json rename to packages/jupyterlab-collaborative-chat/schema/factory.json index 1f00f83..5608cc7 100644 --- a/packages/jupyterlab-collaborative-chat/schema/factories.json +++ b/packages/jupyterlab-collaborative-chat/schema/factory.json @@ -27,6 +27,12 @@ "type": "boolean", "default": true, "readOnly": false + }, + "unreadNotifications": { + "description": "Whether to enable or not the notifications on unread messages.", + "type": "boolean", + "default": true, + "readOnly": false } }, "additionalProperties": false, diff --git a/packages/jupyterlab-collaborative-chat/src/factory.ts b/packages/jupyterlab-collaborative-chat/src/factory.ts index a68444f..bf1dab2 100644 --- a/packages/jupyterlab-collaborative-chat/src/factory.ts +++ b/packages/jupyterlab-collaborative-chat/src/factory.ts @@ -11,7 +11,7 @@ import { Contents, User } from '@jupyterlab/services'; import { Signal } from '@lumino/signaling'; import { CollaborativeChatModel } from './model'; -import { CollaborativeChatWidget } from './widget'; +import { CollaborativeChatPanel } from './widget'; import { YChat } from './ychat'; import { IWidgetConfig } from './token'; @@ -39,7 +39,7 @@ export class WidgetConfig implements IWidgetConfig { * A widget factory to create new instances of CollaborativeChatWidget. */ export class ChatWidgetFactory extends ABCWidgetFactory< - CollaborativeChatWidget, + CollaborativeChatPanel, CollaborativeChatModel > { /** @@ -47,7 +47,7 @@ export class ChatWidgetFactory extends ABCWidgetFactory< * * @param options Constructor options */ - constructor(options: ChatWidgetFactory.IOptions) { + constructor(options: ChatWidgetFactory.IOptions) { super(options); this._themeManager = options.themeManager; this._rmRegistry = options.rmRegistry; @@ -61,11 +61,11 @@ export class ChatWidgetFactory extends ABCWidgetFactory< */ protected createNewWidget( context: ChatWidgetFactory.IContext - ): CollaborativeChatWidget { + ): CollaborativeChatPanel { context.chatModel = context.model; context.rmRegistry = this._rmRegistry; context.themeManager = this._themeManager; - return new CollaborativeChatWidget({ + return new CollaborativeChatPanel({ context, content: new ChatWidget(context) }); @@ -83,7 +83,7 @@ export namespace ChatWidgetFactory { rmRegistry: IRenderMimeRegistry; } - export interface IOptions + export interface IOptions extends DocumentRegistry.IWidgetFactoryOptions { themeManager: IThemeManager | null; rmRegistry: IRenderMimeRegistry; diff --git a/packages/jupyterlab-collaborative-chat/src/index.ts b/packages/jupyterlab-collaborative-chat/src/index.ts index fa58c88..9e16e9d 100644 --- a/packages/jupyterlab-collaborative-chat/src/index.ts +++ b/packages/jupyterlab-collaborative-chat/src/index.ts @@ -35,22 +35,22 @@ import { CollaborativeChatModelFactory } from './factory'; import { CollaborativeChatModel } from './model'; -import { chatFileType, CommandIDs, IChatPanel, IWidgetConfig } from './token'; -import { ChatPanel, CollaborativeChatWidget } from './widget'; +import { chatFileType, CommandIDs, IChatPanel, IChatFactory } from './token'; +import { ChatPanel, CollaborativeChatPanel } from './widget'; import { YChat } from './ychat'; const FACTORY = 'Chat'; const pluginIds = { chatCommands: 'jupyterlab-collaborative-chat:commands', - docFactories: 'jupyterlab-collaborative-chat:factories', + docFactories: 'jupyterlab-collaborative-chat:factory', chatPanel: 'jupyterlab-collaborative-chat:chat-panel' }; /** * Extension registering the chat file type. */ -export const docFactories: JupyterFrontEndPlugin = { +const docFactories: JupyterFrontEndPlugin = { id: pluginIds.docFactories, description: 'A document factories for collaborative chat', autoStart: true, @@ -63,7 +63,7 @@ export const docFactories: JupyterFrontEndPlugin = { IToolbarWidgetRegistry, ITranslator ], - provides: IWidgetConfig, + provides: IChatFactory, activate: ( app: JupyterFrontEnd, rmRegistry: IRenderMimeRegistry, @@ -73,13 +73,13 @@ export const docFactories: JupyterFrontEndPlugin = { themeManager: IThemeManager | null, toolbarRegistry: IToolbarWidgetRegistry | null, translator_: ITranslator | null - ): IWidgetConfig => { + ): IChatFactory => { const translator = translator_ ?? nullTranslator; // Declare the toolbar factory. let toolbarFactory: | (( - widget: CollaborativeChatWidget + widget: CollaborativeChatPanel ) => | DocumentRegistry.IToolbarItem[] | IObservableList) @@ -136,7 +136,7 @@ export const docFactories: JupyterFrontEndPlugin = { const namespace = 'chat'; // Creating the tracker for the document - const tracker = new WidgetTracker({ namespace }); + const tracker = new WidgetTracker({ namespace }); app.docRegistry.addFileType(chatFileType); @@ -200,7 +200,7 @@ export const docFactories: JupyterFrontEndPlugin = { }); } - return widgetConfig; + return { widgetConfig, tracker }; } }; @@ -211,17 +211,18 @@ const chatCommands: JupyterFrontEndPlugin = { id: pluginIds.chatCommands, description: 'The commands to create or open a chat', autoStart: true, - requires: [ICollaborativeDrive, IWidgetConfig], + requires: [ICollaborativeDrive, IChatFactory], optional: [IChatPanel, ICommandPalette, ILauncher], activate: ( app: JupyterFrontEnd, drive: ICollaborativeDrive, - widgetConfig: IWidgetConfig, + factory: IChatFactory, chatPanel: ChatPanel | null, commandPalette: ICommandPalette | null, launcher: ILauncher | null ) => { const { commands } = app; + const { widgetConfig } = factory; /** * Command to create a new chat. @@ -487,10 +488,10 @@ const chatPanel: JupyterFrontEndPlugin = { isEnabled: () => commands.hasCommand(CommandIDs.openChat), execute: async () => { const widget = app.shell.currentWidget; - // Ensure widget is a CollaborativeChatWidget and is in main area + // Ensure widget is a CollaborativeChatPanel and is in main area if ( !widget || - !(widget instanceof CollaborativeChatWidget) || + !(widget instanceof CollaborativeChatPanel) || !Array.from(app.shell.widgets('main')).includes(widget) ) { console.error( diff --git a/packages/jupyterlab-collaborative-chat/src/token.ts b/packages/jupyterlab-collaborative-chat/src/token.ts index e7d122e..b59ba13 100644 --- a/packages/jupyterlab-collaborative-chat/src/token.ts +++ b/packages/jupyterlab-collaborative-chat/src/token.ts @@ -4,10 +4,11 @@ */ import { IConfig, chatIcon } from '@jupyter/chat'; +import { IWidgetTracker } from '@jupyterlab/apputils'; +import { DocumentRegistry } from '@jupyterlab/docregistry'; import { Token } from '@lumino/coreutils'; import { ISignal } from '@lumino/signaling'; -import { DocumentRegistry } from '@jupyterlab/docregistry'; -import { ChatPanel } from './widget'; +import { ChatPanel, CollaborativeChatPanel } from './widget'; /** * The file type for a chat document. @@ -23,14 +24,28 @@ export const chatFileType: DocumentRegistry.IFileType = { }; /** - * The token for the chat widget config + * The token for the chat widget factory. */ -export const IWidgetConfig = new Token( - 'jupyter-collaborative-chat:IWidgetConfig' +export const IChatFactory = new Token( + 'jupyter-collaborative-chat:IChatFactory' ); /** - * Chat widget config + * The interface for the chat factory objects. + */ +export interface IChatFactory { + /** + * The chat widget config. + */ + widgetConfig: IWidgetConfig; + /** + * The chat panel tracker. + */ + tracker: IWidgetTracker; +} + +/** + * The interface for the chats config. */ export interface IWidgetConfig { /** diff --git a/packages/jupyterlab-collaborative-chat/src/widget.tsx b/packages/jupyterlab-collaborative-chat/src/widget.tsx index 1b2fed5..c60d6b8 100644 --- a/packages/jupyterlab-collaborative-chat/src/widget.tsx +++ b/packages/jupyterlab-collaborative-chat/src/widget.tsx @@ -39,7 +39,7 @@ const TOOLBAR_CLASS = 'jp-collab-chat-toolbar'; /** * DocumentWidget: widget that represents the view or editor for a file type. */ -export class CollaborativeChatWidget extends DocumentWidget< +export class CollaborativeChatPanel extends DocumentWidget< ChatWidget, CollaborativeChatModel > { diff --git a/packages/jupyterlab-collaborative-chat/ui-tests/tests/jupyterlab_collaborative_chat.spec.ts b/packages/jupyterlab-collaborative-chat/ui-tests/tests/jupyterlab_collaborative_chat.spec.ts index ce692e6..2ac0554 100644 --- a/packages/jupyterlab-collaborative-chat/ui-tests/tests/jupyterlab_collaborative_chat.spec.ts +++ b/packages/jupyterlab-collaborative-chat/ui-tests/tests/jupyterlab_collaborative_chat.spec.ts @@ -239,7 +239,7 @@ test.describe('#settings', () => { const settings = await openSettings(page, true); await expect( settings.locator( - '.jp-PluginList-entry[data-id="jupyterlab-collaborative-chat:factories"]' + '.jp-PluginList-entry[data-id="jupyterlab-collaborative-chat:factory"]' ) ).toBeVisible(); });