diff --git a/packages/jupyterlab-collaborative-chat/src/factory.ts b/packages/jupyterlab-collaborative-chat/src/factory.ts index 778914cb..2e9214e1 100644 --- a/packages/jupyterlab-collaborative-chat/src/factory.ts +++ b/packages/jupyterlab-collaborative-chat/src/factory.ts @@ -7,7 +7,6 @@ import { ChatWidget, IActiveCellManager, IAutocompletionRegistry, - IConfig, ISelectionWatcher } from '@jupyter/chat'; import { IThemeManager } from '@jupyterlab/apputils'; @@ -20,7 +19,7 @@ import { ISignal, Signal } from '@lumino/signaling'; import { CollaborativeChatModel } from './model'; import { CollaborativeChatPanel } from './widget'; import { YChat } from './ychat'; -import { IWidgetConfig } from './token'; +import { ICollaborativeChatConfig, IWidgetConfig } from './token'; /** * The object provided by the chatDocument extension. @@ -31,17 +30,17 @@ export class WidgetConfig implements IWidgetConfig { /** * The constructor of the WidgetConfig. */ - constructor(config: Partial) { + constructor(config: Partial) { this._config = config; } /** * Getter and setter for the config. */ - get config(): Partial { + get config(): Partial { return this._config; } - set config(value: Partial) { + set config(value: Partial) { this._config = { ...this._config, ...value }; this._configChanged.emit(value); } @@ -49,12 +48,18 @@ export class WidgetConfig implements IWidgetConfig { /** * Getter for the configChanged signal */ - get configChanged(): ISignal> { + get configChanged(): ISignal< + WidgetConfig, + Partial + > { return this._configChanged; } - private _config: Partial; - private _configChanged = new Signal>(this); + private _config: Partial; + private _configChanged = new Signal< + WidgetConfig, + Partial + >(this); } /** diff --git a/packages/jupyterlab-collaborative-chat/src/token.ts b/packages/jupyterlab-collaborative-chat/src/token.ts index 30c26c4c..cd1b1c52 100644 --- a/packages/jupyterlab-collaborative-chat/src/token.ts +++ b/packages/jupyterlab-collaborative-chat/src/token.ts @@ -35,6 +35,16 @@ export const IChatFactory = new Token( 'jupyter-collaborative-chat:IChatFactory' ); +/** + * The collaborative chat configs. + */ +export interface ICollaborativeChatConfig extends IConfig { + /** + * The default directory where to create and look for chat. + */ + defaultDirectory: string; +} + /** * The interface for the chat factory objects. */ @@ -56,7 +66,7 @@ export interface IWidgetConfig { /** * The widget config */ - config: Partial; + config: Partial; /** * A signal emitting when the configuration for the chats has changed. diff --git a/python/jupyterlab-collaborative-chat/schema/factory.json b/python/jupyterlab-collaborative-chat/schema/factory.json index 496c1177..3f32a5f8 100644 --- a/python/jupyterlab-collaborative-chat/schema/factory.json +++ b/python/jupyterlab-collaborative-chat/schema/factory.json @@ -37,6 +37,12 @@ "default": true, "readOnly": false }, + "defaultDirectory": { + "description": "Default directory where to create and look for chat.", + "type": "string", + "default": ".", + "readOnly": false + }, "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:", diff --git a/python/jupyterlab-collaborative-chat/src/index.ts b/python/jupyterlab-collaborative-chat/src/index.ts index 0d9143ab..5d1aabdc 100644 --- a/python/jupyterlab-collaborative-chat/src/index.ts +++ b/python/jupyterlab-collaborative-chat/src/index.ts @@ -136,6 +136,31 @@ const docFactories: JupyterFrontEndPlugin = { * Load the settings for the chat widgets. */ function loadSetting(setting: ISettingRegistry.ISettings): void { + // Remove the previous directory if it is empty and has changed. + const previousDirectory = widgetConfig.config.defaultDirectory; + const currentDirectory = setting.get('defaultDirectory') + .composite as string; + + if ( + drive && + previousDirectory && + previousDirectory !== currentDirectory && + previousDirectory !== '.' + ) { + drive + .get(previousDirectory) + .then(contentModel => { + if (contentModel.content.length === 0) { + drive.delete(previousDirectory).catch(e => { + // no-op, the directory might not be empty + }); + } + }) + .catch(() => { + // no-op, the directory does not exists. + }); + } + // Read the settings and convert to the correct type widgetConfig.config = { sendWithShiftEnter: setting.get('sendWithShiftEnter') @@ -146,8 +171,33 @@ const docFactories: JupyterFrontEndPlugin = { enableCodeToolbar: setting.get('enableCodeToolbar') .composite as boolean, sendTypingNotification: setting.get('sendTypingNotification') - .composite as boolean + .composite as boolean, + defaultDirectory: currentDirectory }; + + // Create the new directory if necessary. + if ( + drive && + currentDirectory && + previousDirectory !== currentDirectory && + currentDirectory !== '.' + ) { + drive.get(currentDirectory, { content: false }).catch(() => { + drive + .newUntitled({ + type: 'directory' + }) + .then(contentModel => { + drive.rename(contentModel.path, currentDirectory).catch(e => { + drive.delete(contentModel.path); + throw e; + }); + }) + .catch(e => { + throw e; + }); + }); + } } if (settingRegistry) { @@ -326,6 +376,11 @@ const chatCommands: JupyterFrontEndPlugin = { } else { filepath = `${name}${chatFileType.extensions[0]}`; } + // Add the default directory to the path. + filepath = PathExt.join( + widgetConfig.config.defaultDirectory || '.', + filepath + ); } let fileExist = true;