jupyterlab-chat 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/factory.d.ts +2 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/model.d.ts +0 -4
- package/lib/model.js +3 -12
- package/lib/token.d.ts +11 -15
- package/lib/token.js +9 -5
- package/lib/utils.d.ts +7 -0
- package/lib/utils.js +23 -0
- package/lib/widget.d.ts +1 -110
- package/lib/widget.js +0 -317
- package/package.json +2 -2
- package/src/factory.ts +3 -6
- package/src/index.ts +1 -0
- package/src/model.ts +3 -14
- package/src/token.ts +12 -22
- package/src/utils.ts +32 -0
- package/src/widget.tsx +1 -462
package/lib/factory.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IAttachmentOpenerRegistry, IChatCommandRegistry, IInputToolbarRegistry, IMessageFooterRegistry } from '@jupyter/chat';
|
|
1
|
+
import { IAttachmentOpenerRegistry, IChatCommandRegistry, IInputToolbarRegistry, IMessageFooterRegistry, IInputToolbarRegistryFactory } from '@jupyter/chat';
|
|
2
2
|
import { IThemeManager } from '@jupyterlab/apputils';
|
|
3
3
|
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
4
4
|
import { ABCWidgetFactory, DocumentRegistry } from '@jupyterlab/docregistry';
|
|
@@ -8,7 +8,7 @@ import { ISignal } from '@lumino/signaling';
|
|
|
8
8
|
import { LabChatModel } from './model';
|
|
9
9
|
import { LabChatPanel } from './widget';
|
|
10
10
|
import { YChat } from './ychat';
|
|
11
|
-
import {
|
|
11
|
+
import { ILabChatConfig, IWidgetConfig } from './token';
|
|
12
12
|
/**
|
|
13
13
|
* The object provided by the chatDocument extension.
|
|
14
14
|
* It is used to set the current config (from settings) to newly created chat widget,
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
package/lib/model.d.ts
CHANGED
|
@@ -54,12 +54,10 @@ export declare class LabChatModel extends AbstractChatModel implements DocumentR
|
|
|
54
54
|
get sharedModel(): YChat;
|
|
55
55
|
get contentChanged(): ISignal<this, void>;
|
|
56
56
|
get stateChanged(): ISignal<this, IChangedArgs<any, any, string>>;
|
|
57
|
-
get ready(): Promise<void>;
|
|
58
57
|
get dirty(): boolean;
|
|
59
58
|
set dirty(value: boolean);
|
|
60
59
|
get readOnly(): boolean;
|
|
61
60
|
set readOnly(value: boolean);
|
|
62
|
-
get disposed(): ISignal<LabChatModel, void>;
|
|
63
61
|
set id(value: string | undefined);
|
|
64
62
|
dispose(): void;
|
|
65
63
|
toString(): string;
|
|
@@ -96,11 +94,9 @@ export declare class LabChatModel extends AbstractChatModel implements DocumentR
|
|
|
96
94
|
private _onchange;
|
|
97
95
|
readonly defaultKernelName: string;
|
|
98
96
|
readonly defaultKernelLanguage: string;
|
|
99
|
-
private _ready;
|
|
100
97
|
private _sharedModel;
|
|
101
98
|
private _dirty;
|
|
102
99
|
private _readOnly;
|
|
103
|
-
private _disposed;
|
|
104
100
|
private _contentChanged;
|
|
105
101
|
private _stateChanged;
|
|
106
102
|
private _timeoutWriting;
|
package/lib/model.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import { AbstractChatModel, AbstractChatContext } from '@jupyter/chat';
|
|
6
|
-
import {
|
|
6
|
+
import { UUID } from '@lumino/coreutils';
|
|
7
7
|
import { Signal } from '@lumino/signaling';
|
|
8
8
|
import { YChat } from './ychat';
|
|
9
9
|
const WRITING_DELAY = 1000;
|
|
@@ -172,10 +172,8 @@ export class LabChatModel extends AbstractChatModel {
|
|
|
172
172
|
};
|
|
173
173
|
this.defaultKernelName = '';
|
|
174
174
|
this.defaultKernelLanguage = '';
|
|
175
|
-
this._ready = new PromiseDelegate();
|
|
176
175
|
this._dirty = false;
|
|
177
176
|
this._readOnly = false;
|
|
178
|
-
this._disposed = new Signal(this);
|
|
179
177
|
this._contentChanged = new Signal(this);
|
|
180
178
|
this._stateChanged = new Signal(this);
|
|
181
179
|
this._timeoutWriting = null;
|
|
@@ -209,9 +207,6 @@ export class LabChatModel extends AbstractChatModel {
|
|
|
209
207
|
get stateChanged() {
|
|
210
208
|
return this._stateChanged;
|
|
211
209
|
}
|
|
212
|
-
get ready() {
|
|
213
|
-
return this._ready.promise;
|
|
214
|
-
}
|
|
215
210
|
get dirty() {
|
|
216
211
|
return this._dirty;
|
|
217
212
|
}
|
|
@@ -224,13 +219,10 @@ export class LabChatModel extends AbstractChatModel {
|
|
|
224
219
|
set readOnly(value) {
|
|
225
220
|
this._readOnly = value;
|
|
226
221
|
}
|
|
227
|
-
get disposed() {
|
|
228
|
-
return this._disposed;
|
|
229
|
-
}
|
|
230
222
|
set id(value) {
|
|
231
223
|
super.id = value;
|
|
232
224
|
if (value) {
|
|
233
|
-
this.
|
|
225
|
+
this.setReady();
|
|
234
226
|
}
|
|
235
227
|
}
|
|
236
228
|
dispose() {
|
|
@@ -239,7 +231,6 @@ export class LabChatModel extends AbstractChatModel {
|
|
|
239
231
|
}
|
|
240
232
|
super.dispose();
|
|
241
233
|
this._sharedModel.dispose();
|
|
242
|
-
this._disposed.emit();
|
|
243
234
|
Signal.clearData(this);
|
|
244
235
|
}
|
|
245
236
|
toString() {
|
|
@@ -260,7 +251,7 @@ export class LabChatModel extends AbstractChatModel {
|
|
|
260
251
|
async messagesInserted(index, messages) {
|
|
261
252
|
// Ensure the chat has an ID before inserting the messages, to properly catch the
|
|
262
253
|
// unread messages (the last read message is saved using the chat ID).
|
|
263
|
-
return this.
|
|
254
|
+
return this.ready.then(() => {
|
|
264
255
|
super.messagesInserted(index, messages);
|
|
265
256
|
});
|
|
266
257
|
}
|
package/lib/token.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { IConfig, IActiveCellManager, ISelectionWatcher, ChatWidget
|
|
1
|
+
import { IConfig, IActiveCellManager, ISelectionWatcher, ChatWidget } from '@jupyter/chat';
|
|
2
2
|
import { WidgetTracker } from '@jupyterlab/apputils';
|
|
3
3
|
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
4
4
|
import { Token } from '@lumino/coreutils';
|
|
5
5
|
import { ISignal } from '@lumino/signaling';
|
|
6
|
-
import {
|
|
6
|
+
import { LabChatPanel } from './widget';
|
|
7
|
+
import { MultiChatPanel as ChatPanel } from '@jupyter/chat';
|
|
7
8
|
/**
|
|
8
9
|
* The file type for a chat document.
|
|
9
10
|
*/
|
|
@@ -64,6 +65,10 @@ export declare const CommandIDs: {
|
|
|
64
65
|
* Open a chat file.
|
|
65
66
|
*/
|
|
66
67
|
openChat: string;
|
|
68
|
+
/**
|
|
69
|
+
* Create and open.
|
|
70
|
+
*/
|
|
71
|
+
createAndOpen: string;
|
|
67
72
|
/**
|
|
68
73
|
* Move a main widget to the side panel.
|
|
69
74
|
*/
|
|
@@ -76,6 +81,10 @@ export declare const CommandIDs: {
|
|
|
76
81
|
* Focus the input of the current chat.
|
|
77
82
|
*/
|
|
78
83
|
focusInput: string;
|
|
84
|
+
/**
|
|
85
|
+
* Rename the current chat.
|
|
86
|
+
*/
|
|
87
|
+
renameChat: string;
|
|
79
88
|
};
|
|
80
89
|
/**
|
|
81
90
|
* The chat panel token.
|
|
@@ -89,19 +98,6 @@ export declare const IActiveCellManagerToken: Token<IActiveCellManager>;
|
|
|
89
98
|
* The selection watcher plugin.
|
|
90
99
|
*/
|
|
91
100
|
export declare const ISelectionWatcherToken: Token<ISelectionWatcher>;
|
|
92
|
-
/**
|
|
93
|
-
* The input toolbar registry factory.
|
|
94
|
-
*/
|
|
95
|
-
export interface IInputToolbarRegistryFactory {
|
|
96
|
-
/**
|
|
97
|
-
* Create an input toolbar registry.
|
|
98
|
-
*/
|
|
99
|
-
create: () => IInputToolbarRegistry;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* The token of the factory to create an input toolbar registry.
|
|
103
|
-
*/
|
|
104
|
-
export declare const IInputToolbarRegistryFactory: Token<IInputToolbarRegistryFactory>;
|
|
105
101
|
/**
|
|
106
102
|
* The token to add a welcome message to the chat.
|
|
107
103
|
* This token is not provided by default, but can be provided by third party extensions
|
package/lib/token.js
CHANGED
|
@@ -32,6 +32,10 @@ export const CommandIDs = {
|
|
|
32
32
|
* Open a chat file.
|
|
33
33
|
*/
|
|
34
34
|
openChat: 'jupyterlab-chat:open',
|
|
35
|
+
/**
|
|
36
|
+
* Create and open.
|
|
37
|
+
*/
|
|
38
|
+
createAndOpen: 'jupyterlab-chat:createAndOpen',
|
|
35
39
|
/**
|
|
36
40
|
* Move a main widget to the side panel.
|
|
37
41
|
*/
|
|
@@ -43,7 +47,11 @@ export const CommandIDs = {
|
|
|
43
47
|
/**
|
|
44
48
|
* Focus the input of the current chat.
|
|
45
49
|
*/
|
|
46
|
-
focusInput: 'jupyterlab-chat:focusInput'
|
|
50
|
+
focusInput: 'jupyterlab-chat:focusInput',
|
|
51
|
+
/**
|
|
52
|
+
* Rename the current chat.
|
|
53
|
+
*/
|
|
54
|
+
renameChat: 'jupyterlab-chat:renameChat'
|
|
47
55
|
};
|
|
48
56
|
/**
|
|
49
57
|
* The chat panel token.
|
|
@@ -57,10 +65,6 @@ export const IActiveCellManagerToken = new Token('jupyterlab-chat:IActiveCellMan
|
|
|
57
65
|
* The selection watcher plugin.
|
|
58
66
|
*/
|
|
59
67
|
export const ISelectionWatcherToken = new Token('jupyterlab-chat:ISelectionWatcher');
|
|
60
|
-
/**
|
|
61
|
-
* The token of the factory to create an input toolbar registry.
|
|
62
|
-
*/
|
|
63
|
-
export const IInputToolbarRegistryFactory = new Token('jupyterlab-chat:IInputToolbarRegistryFactory');
|
|
64
68
|
/**
|
|
65
69
|
* The token to add a welcome message to the chat.
|
|
66
70
|
* This token is not provided by default, but can be provided by third party extensions
|
package/lib/utils.d.ts
ADDED
package/lib/utils.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { PathExt } from '@jupyterlab/coreutils';
|
|
6
|
+
import { chatFileType } from './token';
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @param defaultDirectory - the default directory.
|
|
10
|
+
* @param path - the path of the chat file.
|
|
11
|
+
* @returns - the display name of the chat.
|
|
12
|
+
*/
|
|
13
|
+
export function getDisplayName(path, defaultDirectory) {
|
|
14
|
+
const inDefault = defaultDirectory
|
|
15
|
+
? !PathExt.relative(defaultDirectory, path).startsWith('..')
|
|
16
|
+
: true;
|
|
17
|
+
const pattern = new RegExp(`${chatFileType.extensions[0]}$`, 'g');
|
|
18
|
+
return (inDefault
|
|
19
|
+
? defaultDirectory
|
|
20
|
+
? PathExt.relative(defaultDirectory, path)
|
|
21
|
+
: path
|
|
22
|
+
: '/' + path).replace(pattern, '');
|
|
23
|
+
}
|
package/lib/widget.d.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import { ChatWidget
|
|
2
|
-
import { Contents } from '@jupyterlab/services';
|
|
3
|
-
import { IThemeManager } from '@jupyterlab/apputils';
|
|
1
|
+
import { ChatWidget } from '@jupyter/chat';
|
|
4
2
|
import { DocumentWidget } from '@jupyterlab/docregistry';
|
|
5
|
-
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
6
|
-
import { SidePanel } from '@jupyterlab/ui-components';
|
|
7
|
-
import { CommandRegistry } from '@lumino/commands';
|
|
8
|
-
import { Message } from '@lumino/messaging';
|
|
9
|
-
import { Panel } from '@lumino/widgets';
|
|
10
3
|
import { LabChatModel } from './model';
|
|
11
|
-
import { IInputToolbarRegistryFactory } from './token';
|
|
12
4
|
/**
|
|
13
5
|
* DocumentWidget: widget that represents the view or editor for a file type.
|
|
14
6
|
*/
|
|
@@ -27,104 +19,3 @@ export declare class LabChatPanel extends DocumentWidget<ChatWidget, LabChatMode
|
|
|
27
19
|
*/
|
|
28
20
|
private _unreadChanged;
|
|
29
21
|
}
|
|
30
|
-
/**
|
|
31
|
-
* Sidepanel widget including the chats and the add chat button.
|
|
32
|
-
*/
|
|
33
|
-
export declare class ChatPanel extends SidePanel {
|
|
34
|
-
/**
|
|
35
|
-
* The constructor of the chat panel.
|
|
36
|
-
*/
|
|
37
|
-
constructor(options: ChatPanel.IOptions);
|
|
38
|
-
/**
|
|
39
|
-
* Getter and setter of the defaultDirectory.
|
|
40
|
-
*/
|
|
41
|
-
get defaultDirectory(): string;
|
|
42
|
-
set defaultDirectory(value: string);
|
|
43
|
-
/**
|
|
44
|
-
* Add a new widget to the chat panel.
|
|
45
|
-
*
|
|
46
|
-
* @param model - the model of the chat widget
|
|
47
|
-
* @param name - the name of the chat.
|
|
48
|
-
*/
|
|
49
|
-
addChat(model: IChatModel): ChatWidget;
|
|
50
|
-
/**
|
|
51
|
-
* Update the list of available chats in the default directory.
|
|
52
|
-
*/
|
|
53
|
-
updateChatList: () => Promise<void>;
|
|
54
|
-
/**
|
|
55
|
-
* Open a chat if it exists in the side panel.
|
|
56
|
-
*
|
|
57
|
-
* @param path - the path of the chat.
|
|
58
|
-
* @returns a boolean, whether the chat existed in the side panel or not.
|
|
59
|
-
*/
|
|
60
|
-
openIfExists(path: string): boolean;
|
|
61
|
-
/**
|
|
62
|
-
* A message handler invoked on an `'after-show'` message.
|
|
63
|
-
*/
|
|
64
|
-
protected onAfterShow(msg: Message): void;
|
|
65
|
-
/**
|
|
66
|
-
* Return the index of the chat in the list (-1 if not opened).
|
|
67
|
-
*
|
|
68
|
-
* @param name - the chat name.
|
|
69
|
-
*/
|
|
70
|
-
private _getChatIndex;
|
|
71
|
-
/**
|
|
72
|
-
* Expand the chat from its index.
|
|
73
|
-
*/
|
|
74
|
-
private _expandChat;
|
|
75
|
-
/**
|
|
76
|
-
* Handle `change` events for the HTMLSelect component.
|
|
77
|
-
*/
|
|
78
|
-
private _chatSelected;
|
|
79
|
-
/**
|
|
80
|
-
* Triggered when a section is toogled. If the section is opened, all others
|
|
81
|
-
* sections are closed.
|
|
82
|
-
*/
|
|
83
|
-
private _onExpansionToggled;
|
|
84
|
-
private _chatNamesChanged;
|
|
85
|
-
private _commands;
|
|
86
|
-
private _defaultDirectory;
|
|
87
|
-
private _contentsManager;
|
|
88
|
-
private _openChat;
|
|
89
|
-
private _rmRegistry;
|
|
90
|
-
private _themeManager;
|
|
91
|
-
private _chatCommandRegistry?;
|
|
92
|
-
private _attachmentOpenerRegistry?;
|
|
93
|
-
private _inputToolbarFactory?;
|
|
94
|
-
private _messageFooterRegistry?;
|
|
95
|
-
private _welcomeMessage?;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* The chat panel namespace.
|
|
99
|
-
*/
|
|
100
|
-
export declare namespace ChatPanel {
|
|
101
|
-
/**
|
|
102
|
-
* Options of the constructor of the chat panel.
|
|
103
|
-
*/
|
|
104
|
-
interface IOptions extends SidePanel.IOptions {
|
|
105
|
-
commands: CommandRegistry;
|
|
106
|
-
contentsManager: Contents.IManager;
|
|
107
|
-
rmRegistry: IRenderMimeRegistry;
|
|
108
|
-
themeManager: IThemeManager | null;
|
|
109
|
-
defaultDirectory: string;
|
|
110
|
-
chatCommandRegistry?: IChatCommandRegistry;
|
|
111
|
-
attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
112
|
-
inputToolbarFactory?: IInputToolbarRegistryFactory;
|
|
113
|
-
messageFooterRegistry?: IMessageFooterRegistry;
|
|
114
|
-
welcomeMessage?: string;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* The chat section namespace.
|
|
119
|
-
*/
|
|
120
|
-
export declare namespace ChatSection {
|
|
121
|
-
/**
|
|
122
|
-
* Options to build a chat section.
|
|
123
|
-
*/
|
|
124
|
-
interface IOptions extends Panel.IOptions {
|
|
125
|
-
commands: CommandRegistry;
|
|
126
|
-
defaultDirectory: string;
|
|
127
|
-
widget: ChatWidget;
|
|
128
|
-
path: string;
|
|
129
|
-
}
|
|
130
|
-
}
|
package/lib/widget.js
CHANGED
|
@@ -2,20 +2,9 @@
|
|
|
2
2
|
* Copyright (c) Jupyter Development Team.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
import { ChatWidget, readIcon } from '@jupyter/chat';
|
|
6
|
-
import { PathExt } from '@jupyterlab/coreutils';
|
|
7
5
|
import { DocumentWidget } from '@jupyterlab/docregistry';
|
|
8
|
-
import { addIcon, closeIcon, CommandToolbarButton, HTMLSelect, launchIcon, PanelWithToolbar, ReactWidget, SidePanel, Spinner, ToolbarButton } from '@jupyterlab/ui-components';
|
|
9
|
-
import { Signal } from '@lumino/signaling';
|
|
10
|
-
import React, { useState } from 'react';
|
|
11
|
-
import { CommandIDs, chatFileType } from './token';
|
|
12
6
|
const MAIN_PANEL_CLASS = 'jp-lab-chat-main-panel';
|
|
13
7
|
const TITLE_UNREAD_CLASS = 'jp-lab-chat-title-unread';
|
|
14
|
-
const SIDEPANEL_CLASS = 'jp-lab-chat-sidepanel';
|
|
15
|
-
const ADD_BUTTON_CLASS = 'jp-lab-chat-add';
|
|
16
|
-
const OPEN_SELECT_CLASS = 'jp-lab-chat-open';
|
|
17
|
-
const SECTION_CLASS = 'jp-lab-chat-section';
|
|
18
|
-
const TOOLBAR_CLASS = 'jp-lab-chat-toolbar';
|
|
19
8
|
/**
|
|
20
9
|
* DocumentWidget: widget that represents the view or editor for a file type.
|
|
21
10
|
*/
|
|
@@ -55,309 +44,3 @@ export class LabChatPanel extends DocumentWidget {
|
|
|
55
44
|
return this.context.model;
|
|
56
45
|
}
|
|
57
46
|
}
|
|
58
|
-
/**
|
|
59
|
-
* Sidepanel widget including the chats and the add chat button.
|
|
60
|
-
*/
|
|
61
|
-
export class ChatPanel extends SidePanel {
|
|
62
|
-
/**
|
|
63
|
-
* The constructor of the chat panel.
|
|
64
|
-
*/
|
|
65
|
-
constructor(options) {
|
|
66
|
-
super(options);
|
|
67
|
-
/**
|
|
68
|
-
* Update the list of available chats in the default directory.
|
|
69
|
-
*/
|
|
70
|
-
this.updateChatList = async () => {
|
|
71
|
-
const extension = chatFileType.extensions[0];
|
|
72
|
-
this._contentsManager
|
|
73
|
-
.get(this._defaultDirectory)
|
|
74
|
-
.then((contentModel) => {
|
|
75
|
-
const chatsNames = {};
|
|
76
|
-
contentModel.content
|
|
77
|
-
.filter(f => f.type === 'file' && f.name.endsWith(extension))
|
|
78
|
-
.forEach(f => {
|
|
79
|
-
chatsNames[PathExt.basename(f.name, extension)] = f.path;
|
|
80
|
-
});
|
|
81
|
-
this._chatNamesChanged.emit(chatsNames);
|
|
82
|
-
})
|
|
83
|
-
.catch(e => console.error('Error getting the chat files from drive', e));
|
|
84
|
-
};
|
|
85
|
-
/**
|
|
86
|
-
* Handle `change` events for the HTMLSelect component.
|
|
87
|
-
*/
|
|
88
|
-
this._chatSelected = (event) => {
|
|
89
|
-
const select = event.target;
|
|
90
|
-
const path = select.value;
|
|
91
|
-
const name = select.options[select.selectedIndex].textContent;
|
|
92
|
-
if (name === '-') {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
this._commands.execute(CommandIDs.openChat, {
|
|
96
|
-
filepath: path,
|
|
97
|
-
inSidePanel: true
|
|
98
|
-
});
|
|
99
|
-
event.target.selectedIndex = 0;
|
|
100
|
-
};
|
|
101
|
-
this._chatNamesChanged = new Signal(this);
|
|
102
|
-
this.addClass(SIDEPANEL_CLASS);
|
|
103
|
-
this._commands = options.commands;
|
|
104
|
-
this._contentsManager = options.contentsManager;
|
|
105
|
-
this._rmRegistry = options.rmRegistry;
|
|
106
|
-
this._themeManager = options.themeManager;
|
|
107
|
-
this._defaultDirectory = options.defaultDirectory;
|
|
108
|
-
this._chatCommandRegistry = options.chatCommandRegistry;
|
|
109
|
-
this._attachmentOpenerRegistry = options.attachmentOpenerRegistry;
|
|
110
|
-
this._inputToolbarFactory = options.inputToolbarFactory;
|
|
111
|
-
this._messageFooterRegistry = options.messageFooterRegistry;
|
|
112
|
-
this._welcomeMessage = options.welcomeMessage;
|
|
113
|
-
const addChat = new CommandToolbarButton({
|
|
114
|
-
commands: this._commands,
|
|
115
|
-
id: CommandIDs.createChat,
|
|
116
|
-
args: { inSidePanel: true },
|
|
117
|
-
icon: addIcon
|
|
118
|
-
});
|
|
119
|
-
addChat.addClass(ADD_BUTTON_CLASS);
|
|
120
|
-
this.toolbar.addItem('createChat', addChat);
|
|
121
|
-
this._openChat = ReactWidget.create(React.createElement(ChatSelect, { chatNamesChanged: this._chatNamesChanged, handleChange: this._chatSelected.bind(this) }));
|
|
122
|
-
this._openChat.addClass(OPEN_SELECT_CLASS);
|
|
123
|
-
this.toolbar.addItem('openChat', this._openChat);
|
|
124
|
-
const content = this.content;
|
|
125
|
-
content.expansionToggled.connect(this._onExpansionToggled, this);
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Getter and setter of the defaultDirectory.
|
|
129
|
-
*/
|
|
130
|
-
get defaultDirectory() {
|
|
131
|
-
return this._defaultDirectory;
|
|
132
|
-
}
|
|
133
|
-
set defaultDirectory(value) {
|
|
134
|
-
if (value === this._defaultDirectory) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
this._defaultDirectory = value;
|
|
138
|
-
// Update the list of discoverable chat (in default directory)
|
|
139
|
-
this.updateChatList();
|
|
140
|
-
// Update the sections names.
|
|
141
|
-
this.widgets.forEach(w => {
|
|
142
|
-
w.defaultDirectory = value;
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Add a new widget to the chat panel.
|
|
147
|
-
*
|
|
148
|
-
* @param model - the model of the chat widget
|
|
149
|
-
* @param name - the name of the chat.
|
|
150
|
-
*/
|
|
151
|
-
addChat(model) {
|
|
152
|
-
// Collapse all chats
|
|
153
|
-
const content = this.content;
|
|
154
|
-
for (let i = 0; i < this.widgets.length; i++) {
|
|
155
|
-
content.collapse(i);
|
|
156
|
-
}
|
|
157
|
-
// Create the toolbar registry.
|
|
158
|
-
let inputToolbarRegistry;
|
|
159
|
-
if (this._inputToolbarFactory) {
|
|
160
|
-
inputToolbarRegistry = this._inputToolbarFactory.create();
|
|
161
|
-
}
|
|
162
|
-
// Create a new widget.
|
|
163
|
-
const widget = new ChatWidget({
|
|
164
|
-
model: model,
|
|
165
|
-
rmRegistry: this._rmRegistry,
|
|
166
|
-
themeManager: this._themeManager,
|
|
167
|
-
chatCommandRegistry: this._chatCommandRegistry,
|
|
168
|
-
attachmentOpenerRegistry: this._attachmentOpenerRegistry,
|
|
169
|
-
inputToolbarRegistry,
|
|
170
|
-
messageFooterRegistry: this._messageFooterRegistry,
|
|
171
|
-
welcomeMessage: this._welcomeMessage
|
|
172
|
-
});
|
|
173
|
-
this.addWidget(new ChatSection({
|
|
174
|
-
widget,
|
|
175
|
-
commands: this._commands,
|
|
176
|
-
path: model.name,
|
|
177
|
-
defaultDirectory: this._defaultDirectory
|
|
178
|
-
}));
|
|
179
|
-
return widget;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Open a chat if it exists in the side panel.
|
|
183
|
-
*
|
|
184
|
-
* @param path - the path of the chat.
|
|
185
|
-
* @returns a boolean, whether the chat existed in the side panel or not.
|
|
186
|
-
*/
|
|
187
|
-
openIfExists(path) {
|
|
188
|
-
const index = this._getChatIndex(path);
|
|
189
|
-
if (index > -1) {
|
|
190
|
-
this._expandChat(index);
|
|
191
|
-
}
|
|
192
|
-
return index > -1;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* A message handler invoked on an `'after-show'` message.
|
|
196
|
-
*/
|
|
197
|
-
onAfterShow(msg) {
|
|
198
|
-
var _a;
|
|
199
|
-
// Wait for the component to be rendered.
|
|
200
|
-
(_a = this._openChat.renderPromise) === null || _a === void 0 ? void 0 : _a.then(() => this.updateChatList());
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Return the index of the chat in the list (-1 if not opened).
|
|
204
|
-
*
|
|
205
|
-
* @param name - the chat name.
|
|
206
|
-
*/
|
|
207
|
-
_getChatIndex(path) {
|
|
208
|
-
return this.widgets.findIndex(w => w.path === path);
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Expand the chat from its index.
|
|
212
|
-
*/
|
|
213
|
-
_expandChat(index) {
|
|
214
|
-
if (!this.widgets[index].isVisible) {
|
|
215
|
-
this.content.expand(index);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Triggered when a section is toogled. If the section is opened, all others
|
|
220
|
-
* sections are closed.
|
|
221
|
-
*/
|
|
222
|
-
_onExpansionToggled(panel, index) {
|
|
223
|
-
if (!this.widgets[index].isVisible) {
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
for (let i = 0; i < this.widgets.length; i++) {
|
|
227
|
-
if (i !== index) {
|
|
228
|
-
panel.collapse(i);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* The chat section containing a chat widget.
|
|
235
|
-
*/
|
|
236
|
-
class ChatSection extends PanelWithToolbar {
|
|
237
|
-
/**
|
|
238
|
-
* Constructor of the chat section.
|
|
239
|
-
*/
|
|
240
|
-
constructor(options) {
|
|
241
|
-
var _a;
|
|
242
|
-
super(options);
|
|
243
|
-
/**
|
|
244
|
-
* Change the title when messages are unread.
|
|
245
|
-
*
|
|
246
|
-
* TODO: fix it upstream in @jupyterlab/ui-components.
|
|
247
|
-
* Updating the title create a new Title widget, but does not attach again the
|
|
248
|
-
* toolbar. The toolbar is attached only when the title widget is attached the first
|
|
249
|
-
* time.
|
|
250
|
-
*/
|
|
251
|
-
this._unreadChanged = (_, unread) => {
|
|
252
|
-
this._markAsRead.enabled = unread.length > 0;
|
|
253
|
-
// this.title.label = `${unread.length ? '* ' : ''}${this._name}`;
|
|
254
|
-
};
|
|
255
|
-
this._spinner = new Spinner();
|
|
256
|
-
this.addWidget(options.widget);
|
|
257
|
-
this.addWidget(this._spinner);
|
|
258
|
-
this.addClass(SECTION_CLASS);
|
|
259
|
-
this._defaultDirectory = options.defaultDirectory;
|
|
260
|
-
this._path = options.path;
|
|
261
|
-
this._updateTitle();
|
|
262
|
-
this.toolbar.addClass(TOOLBAR_CLASS);
|
|
263
|
-
this._markAsRead = new ToolbarButton({
|
|
264
|
-
icon: readIcon,
|
|
265
|
-
iconLabel: 'Mark chat as read',
|
|
266
|
-
className: 'jp-mod-styled',
|
|
267
|
-
onClick: () => (this.model.unreadMessages = [])
|
|
268
|
-
});
|
|
269
|
-
const moveToMain = new ToolbarButton({
|
|
270
|
-
icon: launchIcon,
|
|
271
|
-
iconLabel: 'Move the chat to the main area',
|
|
272
|
-
className: 'jp-mod-styled',
|
|
273
|
-
onClick: () => {
|
|
274
|
-
this.model.dispose();
|
|
275
|
-
options.commands.execute(CommandIDs.openChat, {
|
|
276
|
-
filepath: this._path
|
|
277
|
-
});
|
|
278
|
-
this.dispose();
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
const closeButton = new ToolbarButton({
|
|
282
|
-
icon: closeIcon,
|
|
283
|
-
iconLabel: 'Close the chat',
|
|
284
|
-
className: 'jp-mod-styled',
|
|
285
|
-
onClick: () => {
|
|
286
|
-
this.model.dispose();
|
|
287
|
-
this.dispose();
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
this.toolbar.addItem('jupyterlabChat-markRead', this._markAsRead);
|
|
291
|
-
this.toolbar.addItem('jupyterlabChat-moveMain', moveToMain);
|
|
292
|
-
this.toolbar.addItem('jupyterlabChat-close', closeButton);
|
|
293
|
-
(_a = this.model.unreadChanged) === null || _a === void 0 ? void 0 : _a.connect(this._unreadChanged);
|
|
294
|
-
this._markAsRead.enabled = this.model.unreadMessages.length > 0;
|
|
295
|
-
options.widget.node.style.height = '100%';
|
|
296
|
-
/**
|
|
297
|
-
* Remove the spinner when the chat is ready.
|
|
298
|
-
*/
|
|
299
|
-
const model = this.model;
|
|
300
|
-
model.ready.then(() => {
|
|
301
|
-
this._spinner.dispose();
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* The path of the chat.
|
|
306
|
-
*/
|
|
307
|
-
get path() {
|
|
308
|
-
return this._path;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Set the default directory property.
|
|
312
|
-
*/
|
|
313
|
-
set defaultDirectory(value) {
|
|
314
|
-
this._defaultDirectory = value;
|
|
315
|
-
this._updateTitle();
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* The model of the widget.
|
|
319
|
-
*/
|
|
320
|
-
get model() {
|
|
321
|
-
return this.widgets[0].model;
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Dispose of the resources held by the widget.
|
|
325
|
-
*/
|
|
326
|
-
dispose() {
|
|
327
|
-
var _a;
|
|
328
|
-
(_a = this.model.unreadChanged) === null || _a === void 0 ? void 0 : _a.disconnect(this._unreadChanged);
|
|
329
|
-
super.dispose();
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Update the section's title, depending on the default directory and chat file name.
|
|
333
|
-
* If the chat file is in the default directory, the section's name is its relative
|
|
334
|
-
* path to that default directory. Otherwise, it is it absolute path.
|
|
335
|
-
*/
|
|
336
|
-
_updateTitle() {
|
|
337
|
-
const inDefault = this._defaultDirectory
|
|
338
|
-
? !PathExt.relative(this._defaultDirectory, this._path).startsWith('..')
|
|
339
|
-
: true;
|
|
340
|
-
const pattern = new RegExp(`${chatFileType.extensions[0]}$`, 'g');
|
|
341
|
-
this.title.label = (inDefault
|
|
342
|
-
? this._defaultDirectory
|
|
343
|
-
? PathExt.relative(this._defaultDirectory, this._path)
|
|
344
|
-
: this._path
|
|
345
|
-
: '/' + this._path).replace(pattern, '');
|
|
346
|
-
this.title.caption = this._path;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* A component to select a chat from the drive.
|
|
351
|
-
*/
|
|
352
|
-
function ChatSelect({ chatNamesChanged, handleChange }) {
|
|
353
|
-
// An object associating a chat name to its path. Both are purely indicative, the name
|
|
354
|
-
// is the section title and the path is used as caption.
|
|
355
|
-
const [chatNames, setChatNames] = useState({});
|
|
356
|
-
// Update the chat list.
|
|
357
|
-
chatNamesChanged.connect((_, chatNames) => {
|
|
358
|
-
setChatNames(chatNames);
|
|
359
|
-
});
|
|
360
|
-
return (React.createElement(HTMLSelect, { onChange: handleChange },
|
|
361
|
-
React.createElement("option", { value: "-" }, "Open a chat"),
|
|
362
|
-
Object.keys(chatNames).map(name => (React.createElement("option", { value: chatNames[name] }, name)))));
|
|
363
|
-
}
|