diff --git a/jupyter_collaboration/handlers.py b/jupyter_collaboration/handlers.py index 4a3639d9..6513ba37 100644 --- a/jupyter_collaboration/handlers.py +++ b/jupyter_collaboration/handlers.py @@ -18,8 +18,6 @@ from pycrdt_websocket.yutils import YMessageType, write_var_uint from tornado import web from tornado.websocket import WebSocketHandler -from jupyter_chat.handlers import ChatHandler -from jupyter_chat.models import ChatUser from .loaders import FileLoaderMapping from .rooms import DocumentRoom, TransientRoom diff --git a/packages/collaboration-extension/src/chat.ts b/packages/collaboration-extension/src/chat.ts index 98fed86f..62c58460 100644 --- a/packages/collaboration-extension/src/chat.ts +++ b/packages/collaboration-extension/src/chat.ts @@ -27,7 +27,6 @@ import { WidgetTracker } from '@jupyterlab/apputils'; import { PathExt } from '@jupyterlab/coreutils'; -import { FileBrowser, IDefaultFileBrowser } from '@jupyterlab/filebrowser'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { Contents } from '@jupyterlab/services'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; @@ -118,7 +117,6 @@ export const chat: JupyterFrontEndPlugin = { requires: [ IChatFileType, ICollaborativeDrive, - IDefaultFileBrowser, IGlobalAwareness, IRenderMimeRegistry ], @@ -127,7 +125,6 @@ export const chat: JupyterFrontEndPlugin = { app: JupyterFrontEnd, chatFileType: IChatFileType, drive: ICollaborativeDrive, - filebrowser: FileBrowser, awareness: Awareness, rmRegistry: IRenderMimeRegistry, restorer: ILayoutRestorer | null, @@ -141,7 +138,7 @@ export const chat: JupyterFrontEndPlugin = { */ const chatPanel = new ChatPanel({ commands, - filebrowser, + drive, rmRegistry, themeManager }); diff --git a/packages/docprovider/src/chat/widget.tsx b/packages/docprovider/src/chat/widget.tsx index 038eacc3..e6256ba3 100644 --- a/packages/docprovider/src/chat/widget.tsx +++ b/packages/docprovider/src/chat/widget.tsx @@ -7,7 +7,6 @@ import { IChatModel, ChatWidget, IConfig } from '@jupyter/chat'; import { IThemeManager } from '@jupyterlab/apputils'; import { PathExt } from '@jupyterlab/coreutils'; import { DocumentWidget } from '@jupyterlab/docregistry'; -import { FileBrowser } from '@jupyterlab/filebrowser'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { addIcon, @@ -21,8 +20,9 @@ import { } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import { AccordionPanel, Panel } from '@lumino/widgets'; -import * as React from 'react'; +import React, { useEffect, useState } from 'react'; +import { ICollaborativeDrive } from '../tokens'; import { CollaborativeChatModel } from './model'; const SIDEPANEL_CLASS = 'jp-collab-chat-sidepanel'; @@ -75,11 +75,13 @@ export class ChatPanel extends SidePanel { addChat.addClass(ADD_BUTTON_CLASS); this.toolbar.addItem('createChat', addChat); - const { filebrowser } = options; - const openChat = new ChatSelect({ - filebrowser, - handleChange: this._chatSelected.bind(this) - }); + const { drive } = options; + const openChat = ReactWidget.create( + + ); openChat.addClass(OPEN_SELECT_CLASS); this.toolbar.addItem('openChat', openChat); @@ -176,7 +178,7 @@ export namespace ChatPanel { */ export interface IOptions extends SidePanel.IOptions { commands: CommandRegistry; - filebrowser: FileBrowser; + drive: ICollaborativeDrive; rmRegistry: IRenderMimeRegistry; themeManager: IThemeManager | null; } @@ -248,37 +250,50 @@ export namespace ChatSection { } } +type ChatSelectProps = { + drive: ICollaborativeDrive; + handleChange: (event: React.ChangeEvent) => void; +}; + /** - * A widget to select a chat + * A component to select a chat from the drive. */ -export class ChatSelect extends ReactWidget { +function ChatSelect({ drive, handleChange }: ChatSelectProps): JSX.Element { + const [chatNames, setChatNames] = useState([]); + /** - * the constructor of the widget. + * Get chats list on initial render. */ - constructor(options: { - filebrowser: FileBrowser; - handleChange: (event: React.ChangeEvent) => void; - }) { - super(); - this._filebrowser = options.filebrowser; - this._handleChange = options.handleChange; - } + useEffect(() => { + // Find chat files in drive (root level only) + // TODO: search in sub-directories ? + async function getChats() { + drive + .get('.') + .then(model => { + const chatsName = (model.content as any[]) + .filter(f => f.type === 'file' && f.name.endsWith('.chat')) + .map(f => PathExt.basename(f.name, '.chat')); + setChatNames(chatsName); + }) + .catch(e => console.error('Error getting the chat file in drive')); + } - render(): JSX.Element { - const items = Array.from(this._filebrowser.model.items()); - const chatNames = items - .filter(f => f.name.endsWith('.chat')) - .map(f => PathExt.basename(f.name, '.chat')); - return ( - - - {chatNames.map(name => ( - - ))} - - ); - } + // Listen for changes in drive. + drive.fileChanged.connect((_, change) => { + getChats(); + }); + + // Initialize the chats list. + getChats(); + }, [drive]); - private _filebrowser: FileBrowser; - private _handleChange: (event: React.ChangeEvent) => void; + return ( + + + {chatNames.map(name => ( + + ))} + + ); }