diff --git a/packages/jupyterlab-collaborative-chat/package.json b/packages/jupyterlab-collaborative-chat/package.json index c51e403..a7cfd59 100644 --- a/packages/jupyterlab-collaborative-chat/package.json +++ b/packages/jupyterlab-collaborative-chat/package.json @@ -67,6 +67,7 @@ "@jupyterlab/rendermime": "^4.0.0", "@jupyterlab/services": "^7.0.0", "@jupyterlab/settingregistry": "^4.0.0", + "@jupyterlab/translation": "^4.0.0", "@lumino/coreutils": "^2.0.0", "@lumino/signaling": "^2.0.0", "chat-jupyter": "0.1.0", @@ -122,7 +123,13 @@ }, "extension": true, "outputDir": "jupyterlab_collaborative_chat/labextension", - "schemaDir": "schema" + "schemaDir": "schema", + "sharedPackages": { + "@jupyter/docprovider": { + "bundled": true, + "singleton": true + } + } }, "eslintIgnore": [ "node_modules", diff --git a/packages/jupyterlab-collaborative-chat/schema/chat-document.json b/packages/jupyterlab-collaborative-chat/schema/chat-document.json deleted file mode 100644 index 18a2bbb..0000000 --- a/packages/jupyterlab-collaborative-chat/schema/chat-document.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "title": "Chat", - "description": "Configuration for the chat widgets", - "type": "object", - "properties": { - "sendWithShiftEnter": { - "description": "Whether to send a message via Shift-Enter instead of Enter.", - "type": "boolean", - "default": false, - "readOnly": false - } - }, - "additionalProperties": false -} diff --git a/packages/jupyterlab-collaborative-chat/schema/factories.json b/packages/jupyterlab-collaborative-chat/schema/factories.json new file mode 100644 index 0000000..8fc2695 --- /dev/null +++ b/packages/jupyterlab-collaborative-chat/schema/factories.json @@ -0,0 +1,80 @@ +{ + "title": "Chat", + "description": "Configuration for the chat widgets", + "type": "object", + "jupyter.lab.toolbars": { + "Chat": [] + }, + "jupyter.lab.transform": true, + "properties": { + "toolbar": { + "title": "File browser toolbar items", + "description": "Note: To disable a toolbar item,\ncopy it to User Preferences and add the\n\"disabled\" key. The following example will disable the uploader button:\n{\n \"toolbar\": [\n {\n \"name\": \"uploader\",\n \"disabled\": true\n }\n ]\n}\n\nToolbar description:", + "items": { + "$ref": "#/definitions/toolbarItem" + }, + "type": "array", + "default": [] + }, + "sendWithShiftEnter": { + "description": "Whether to send a message via Shift-Enter instead of Enter.", + "type": "boolean", + "default": false, + "readOnly": false + } + }, + "additionalProperties": false, + "definitions": { + "toolbarItem": { + "properties": { + "name": { + "title": "Unique name", + "type": "string" + }, + "args": { + "title": "Command arguments", + "type": "object" + }, + "command": { + "title": "Command id", + "type": "string", + "default": "" + }, + "disabled": { + "title": "Whether the item is ignored or not", + "type": "boolean", + "default": false + }, + "icon": { + "title": "Item icon id", + "description": "If defined, it will override the command icon", + "type": "string" + }, + "label": { + "title": "Item label", + "description": "If defined, it will override the command label", + "type": "string" + }, + "caption": { + "title": "Item caption", + "description": "If defined, it will override the command caption", + "type": "string" + }, + "type": { + "title": "Item type", + "type": "string", + "enum": ["command", "spacer"] + }, + "rank": { + "title": "Item rank", + "type": "number", + "minimum": 0, + "default": 50 + } + }, + "required": ["name"], + "additionalProperties": false, + "type": "object" + } + } +} diff --git a/packages/jupyterlab-collaborative-chat/src/factory.ts b/packages/jupyterlab-collaborative-chat/src/factory.ts index 7fbaa99..e7f5445 100644 --- a/packages/jupyterlab-collaborative-chat/src/factory.ts +++ b/packages/jupyterlab-collaborative-chat/src/factory.ts @@ -48,7 +48,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; @@ -84,7 +84,8 @@ export namespace ChatWidgetFactory { rmRegistry: IRenderMimeRegistry; } - export interface IOptions extends DocumentRegistry.IWidgetFactoryOptions { + 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 da54c8b..7453acf 100644 --- a/packages/jupyterlab-collaborative-chat/src/index.ts +++ b/packages/jupyterlab-collaborative-chat/src/index.ts @@ -13,14 +13,19 @@ import { import { ICommandPalette, IThemeManager, + IToolbarWidgetRegistry, InputDialog, WidgetTracker, + createToolbarFactory, showErrorMessage } from '@jupyterlab/apputils'; import { ILauncher } from '@jupyterlab/launcher'; +import { DocumentRegistry } from '@jupyterlab/docregistry'; +import { IObservableList } from '@jupyterlab/observables'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { Contents } from '@jupyterlab/services'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; +import { ITranslator, nullTranslator } from '@jupyterlab/translation'; import { chatIcon } from 'chat-jupyter'; import { Awareness } from 'y-protocols/awareness'; @@ -33,24 +38,28 @@ import { chatFileType, CommandIDs, IWidgetConfig } from './token'; import { CollaborativeChatWidget } from './widget'; import { YChat } from './ychat'; +const FACTORY = 'Chat'; + const pluginIds = { chatCommands: 'jupyterlab-collaborative-chat:commands', - chatDocument: 'jupyterlab-collaborative-chat:chat-document' + docFactories: 'jupyterlab-collaborative-chat:factories' }; /** * Extension registering the chat file type. */ -export const chatDocument: JupyterFrontEndPlugin = { - id: pluginIds.chatDocument, - description: 'A document registration for collaborative chat', +export const docFactories: JupyterFrontEndPlugin = { + id: pluginIds.docFactories, + description: 'A document factories for collaborative chat', autoStart: true, requires: [IGlobalAwareness, IRenderMimeRegistry], optional: [ ICollaborativeDrive, ILayoutRestorer, ISettingRegistry, - IThemeManager + IThemeManager, + IToolbarWidgetRegistry, + ITranslator ], provides: IWidgetConfig, activate: ( @@ -60,18 +69,26 @@ export const chatDocument: JupyterFrontEndPlugin = { drive: ICollaborativeDrive | null, restorer: ILayoutRestorer | null, settingRegistry: ISettingRegistry | null, - themeManager: IThemeManager | null + themeManager: IThemeManager | null, + toolbarRegistry: IToolbarWidgetRegistry | null, + translator_: ITranslator | null ): IWidgetConfig => { + const translator = translator_ ?? nullTranslator; + + // Declare the toolbar factory. + let toolbarFactory: + | (( + widget: CollaborativeChatWidget + ) => + | DocumentRegistry.IToolbarItem[] + | IObservableList) + | undefined; + /** * Load the settings for the chat widgets. */ let sendWithShiftEnter = false; - /** - * The ChatDocument object. - */ - const widgetConfig = new WidgetConfig({ sendWithShiftEnter }); - function loadSetting(setting: ISettingRegistry.ISettings): void { // Read the settings and convert to the correct type sendWithShiftEnter = setting.get('sendWithShiftEnter') @@ -80,9 +97,21 @@ export const chatDocument: JupyterFrontEndPlugin = { } if (settingRegistry) { + // Create the main area widget toolbar factory. + if (toolbarRegistry) { + toolbarFactory = createToolbarFactory( + toolbarRegistry, + settingRegistry, + FACTORY, + pluginIds.docFactories, + translator + ); + console.log('Create toolbarFactory', toolbarFactory); + } + // Wait for the application to be restored and // for the settings to be loaded - Promise.all([app.restored, settingRegistry.load(pluginIds.chatDocument)]) + Promise.all([app.restored, settingRegistry.load(pluginIds.docFactories)]) .then(([, setting]) => { // Read the settings loadSetting(setting); @@ -97,6 +126,11 @@ export const chatDocument: JupyterFrontEndPlugin = { }); } + /** + * The chat config object. + */ + const widgetConfig = new WidgetConfig({ sendWithShiftEnter }); + // Namespace for the tracker const namespace = 'chat'; @@ -122,12 +156,15 @@ export const chatDocument: JupyterFrontEndPlugin = { // Creating the widget factory to register it so the document manager knows about // our new DocumentWidget const widgetFactory = new ChatWidgetFactory({ - name: 'chat-factory', + name: FACTORY, + label: 'Chat', modelName: 'chat', fileTypes: ['chat'], defaultFor: ['chat'], themeManager, - rmRegistry + rmRegistry, + toolbarFactory, + translator }); // Add the widget to the tracker when it's created @@ -146,7 +183,7 @@ export const chatDocument: JupyterFrontEndPlugin = { if (restorer) { void restorer.restore(tracker, { command: 'docmanager:open', - args: panel => ({ path: panel.context.path, factory: 'chat-factory' }), + args: panel => ({ path: panel.context.path, factory: FACTORY }), name: panel => panel.context.path, when: app.serviceManager.ready }); @@ -282,7 +319,7 @@ export const chatCommands: JupyterFrontEndPlugin = { commands.execute('docmanager:open', { path: `RTC:${filepath}`, - factory: 'chat-factory' + factory: FACTORY }); } }); @@ -311,4 +348,4 @@ export const chatCommands: JupyterFrontEndPlugin = { } }; -export default [chatDocument, chatCommands]; +export default [chatCommands, docFactories]; diff --git a/packages/jupyterlab-collaborative-chat/src/widget.ts b/packages/jupyterlab-collaborative-chat/src/widget.ts index 3aa4e07..0b2f20e 100644 --- a/packages/jupyterlab-collaborative-chat/src/widget.ts +++ b/packages/jupyterlab-collaborative-chat/src/widget.ts @@ -8,6 +8,8 @@ import { DocumentWidget } from '@jupyterlab/docregistry'; import { CollaborativeChatModel } from './model'; +const MAIN_PANEL_CLASS = 'jp-collab-chat_main-panel'; + /** * DocumentWidget: widget that represents the view or editor for a file type. */ @@ -19,6 +21,7 @@ export class CollaborativeChatWidget extends DocumentWidget< options: DocumentWidget.IOptions ) { super(options); + this.addClass(MAIN_PANEL_CLASS); } /** 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 868486b..0f60862 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 @@ -237,7 +237,7 @@ test.describe('#settings', () => { const settings = await openSettings(page, true); await expect( settings.locator( - '.jp-PluginList-entry[data-id="jupyterlab-collaborative-chat:chat-document"]' + '.jp-PluginList-entry[data-id="jupyterlab-collaborative-chat:factories"]' ) ).toBeVisible(); }); diff --git a/yarn.lock b/yarn.lock index b4febb9..ae0c746 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2952,7 +2952,7 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/translation@npm:^4.1.6": +"@jupyterlab/translation@npm:^4.0.0, @jupyterlab/translation@npm:^4.1.6": version: 4.1.6 resolution: "@jupyterlab/translation@npm:4.1.6" dependencies: @@ -9842,6 +9842,7 @@ __metadata: "@jupyterlab/services": ^7.0.0 "@jupyterlab/settingregistry": ^4.0.0 "@jupyterlab/testutils": ^4.0.0 + "@jupyterlab/translation": ^4.0.0 "@lumino/coreutils": ^2.0.0 "@lumino/signaling": ^2.0.0 "@types/jest": ^29.2.0