Skip to content

Commit

Permalink
Use the jupyter events sytem to update the chat list
Browse files Browse the repository at this point in the history
  • Loading branch information
brichet committed Apr 15, 2024
1 parent 5b75c19 commit c554209
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 32 deletions.
13 changes: 12 additions & 1 deletion packages/jupyterlab-collaborative-chat/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,18 @@ const chatPanel: JupyterFrontEndPlugin<ChatPanel> = {
restorer.add(chatPanel, 'jupyter-chat');
}

console.log('Collaborative chat initialized');
// Use events system to watch changes on files.
const schemaID =
'https://events.jupyter.org/jupyter_server/contents_service/v1';
const actions = ['create', 'delete', 'rename'];
app.serviceManager.events.stream.connect((_, emission) => {
if (emission.schema_id === schemaID) {
const action = emission.action as string;
if (actions.includes(action)) {
chatPanel.updateChatNames();
}
}
});

return chatPanel;
}
Expand Down
59 changes: 28 additions & 31 deletions packages/jupyterlab-collaborative-chat/src/widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ import {
import { CommandRegistry } from '@lumino/commands';
import { AccordionPanel, Panel } from '@lumino/widgets';
import { ChatWidget, IChatModel, IConfig } from 'chat-jupyter';
import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';

import { CollaborativeChatModel } from './model';
import { CommandIDs } from './token';
import { ISignal, Signal } from '@lumino/signaling';

const SIDEPANEL_CLASS = 'jp-collab-chat-sidepanel';
const ADD_BUTTON_CLASS = 'jp-collab-chat-add';
Expand Down Expand Up @@ -72,6 +73,7 @@ export class ChatPanel extends SidePanel {
super(options);
this.addClass(SIDEPANEL_CLASS);
this._commands = options.commands;
this._drive = options.drive;
this._rmRegistry = options.rmRegistry;
this._themeManager = options.themeManager;

Expand All @@ -84,13 +86,14 @@ export class ChatPanel extends SidePanel {
addChat.addClass(ADD_BUTTON_CLASS);
this.toolbar.addItem('createChat', addChat);

const { drive } = options;
const openChat = ReactWidget.create(
<ChatSelect
drive={drive}
chatNamesChanged={this._chatNamesChanged}
handleChange={this._chatSelected.bind(this)}
></ChatSelect>
);
this.updateChatNames();

openChat.addClass(OPEN_SELECT_CLASS);
this.toolbar.addItem('openChat', openChat);

Expand Down Expand Up @@ -133,6 +136,18 @@ export class ChatPanel extends SidePanel {
this.addWidget(new ChatSection({ widget, name }));
}

updateChatNames = async () => {
this._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'));
this._chatNamesChanged.emit(chatsName);
})
.catch(e => console.error('Error getting the chat files from drive', e));
};

/**
* Handle `change` events for the HTMLSelect component.
*/
Expand Down Expand Up @@ -173,8 +188,10 @@ export class ChatPanel extends SidePanel {
}
}

private _chatNamesChanged = new Signal<this, string[]>(this);
private _commands: CommandRegistry;
private _config: IConfig = {};
private _drive: ICollaborativeDrive;
private _rmRegistry: IRenderMimeRegistry;
private _themeManager: IThemeManager | null;
}
Expand Down Expand Up @@ -254,42 +271,22 @@ export namespace ChatSection {
}

type ChatSelectProps = {
drive: ICollaborativeDrive;
chatNamesChanged: ISignal<ChatPanel, string[]>;
handleChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;
};

/**
* A component to select a chat from the drive.
*/
function ChatSelect({ drive, handleChange }: ChatSelectProps): JSX.Element {
function ChatSelect({
chatNamesChanged,
handleChange
}: ChatSelectProps): JSX.Element {
const [chatNames, setChatNames] = useState<string[]>([]);

/**
* Get chats list on initial render.
*/
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'));
}

// Listen for changes in drive.
drive.fileChanged.connect((_, change) => {
getChats();
});

// Initialize the chats list.
getChats();
}, [drive]);
chatNamesChanged.connect((_, chatNames) => {
setChatNames(chatNames);
});

return (
<HTMLSelect onChange={handleChange}>
Expand Down

0 comments on commit c554209

Please sign in to comment.