jupyterlab-chat 0.8.1 → 0.10.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 +6 -4
- package/lib/factory.js +8 -4
- package/lib/model.d.ts +19 -4
- package/lib/model.js +102 -13
- package/lib/token.d.ts +14 -1
- package/lib/token.js +4 -0
- package/lib/widget.d.ts +3 -3
- package/lib/widget.js +8 -3
- package/lib/ychat.d.ts +1 -1
- package/lib/ychat.js +2 -1
- package/package.json +2 -2
- package/src/factory.ts +17 -6
- package/src/model.ts +134 -15
- package/src/token.ts +20 -1
- package/src/widget.tsx +17 -7
- package/src/ychat.ts +7 -2
package/lib/factory.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IAttachmentOpenerRegistry, IChatCommandRegistry } from '@jupyter/chat';
|
|
1
|
+
import { IAttachmentOpenerRegistry, IChatCommandRegistry, IInputToolbarRegistry } 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 { ILabChatConfig, IWidgetConfig } from './token';
|
|
11
|
+
import { IInputToolbarRegistryFactory, 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,
|
|
@@ -50,9 +50,9 @@ export declare class ChatWidgetFactory extends ABCWidgetFactory<LabChatPanel, La
|
|
|
50
50
|
protected createNewWidget(context: ChatWidgetFactory.IContext): LabChatPanel;
|
|
51
51
|
private _themeManager;
|
|
52
52
|
private _rmRegistry;
|
|
53
|
-
private _documentManager?;
|
|
54
53
|
private _chatCommandRegistry?;
|
|
55
54
|
private _attachmentOpenerRegistry?;
|
|
55
|
+
private _inputToolbarFactory?;
|
|
56
56
|
}
|
|
57
57
|
export declare namespace ChatWidgetFactory {
|
|
58
58
|
interface IContext extends DocumentRegistry.IContext<LabChatModel> {
|
|
@@ -61,13 +61,14 @@ export declare namespace ChatWidgetFactory {
|
|
|
61
61
|
documentManager?: IDocumentManager;
|
|
62
62
|
chatCommandRegistry?: IChatCommandRegistry;
|
|
63
63
|
attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
64
|
+
inputToolbarRegistry?: IInputToolbarRegistry;
|
|
64
65
|
}
|
|
65
66
|
interface IOptions<T extends LabChatPanel> extends DocumentRegistry.IWidgetFactoryOptions<T> {
|
|
66
67
|
themeManager: IThemeManager | null;
|
|
67
68
|
rmRegistry: IRenderMimeRegistry;
|
|
68
|
-
documentManager?: IDocumentManager;
|
|
69
69
|
chatCommandRegistry?: IChatCommandRegistry;
|
|
70
70
|
attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
71
|
+
inputToolbarFactory?: IInputToolbarRegistryFactory;
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
export declare class LabChatModelFactory implements DocumentRegistry.IModelFactory<LabChatModel> {
|
|
@@ -122,4 +123,5 @@ export declare class LabChatModelFactory implements DocumentRegistry.IModelFacto
|
|
|
122
123
|
private _commands?;
|
|
123
124
|
private _activeCellManager;
|
|
124
125
|
private _selectionWatcher;
|
|
126
|
+
private _documentManager;
|
|
125
127
|
}
|
package/lib/factory.js
CHANGED
|
@@ -50,9 +50,9 @@ export class ChatWidgetFactory extends ABCWidgetFactory {
|
|
|
50
50
|
super(options);
|
|
51
51
|
this._themeManager = options.themeManager;
|
|
52
52
|
this._rmRegistry = options.rmRegistry;
|
|
53
|
-
this._documentManager = options.documentManager;
|
|
54
53
|
this._chatCommandRegistry = options.chatCommandRegistry;
|
|
55
54
|
this._attachmentOpenerRegistry = options.attachmentOpenerRegistry;
|
|
55
|
+
this._inputToolbarFactory = options.inputToolbarFactory;
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
58
|
* Create a new widget given a context.
|
|
@@ -63,9 +63,11 @@ export class ChatWidgetFactory extends ABCWidgetFactory {
|
|
|
63
63
|
createNewWidget(context) {
|
|
64
64
|
context.rmRegistry = this._rmRegistry;
|
|
65
65
|
context.themeManager = this._themeManager;
|
|
66
|
-
context.documentManager = this._documentManager;
|
|
67
66
|
context.chatCommandRegistry = this._chatCommandRegistry;
|
|
68
67
|
context.attachmentOpenerRegistry = this._attachmentOpenerRegistry;
|
|
68
|
+
if (this._inputToolbarFactory) {
|
|
69
|
+
context.inputToolbarRegistry = this._inputToolbarFactory.create();
|
|
70
|
+
}
|
|
69
71
|
return new LabChatPanel({
|
|
70
72
|
context,
|
|
71
73
|
content: new ChatWidget(context)
|
|
@@ -74,7 +76,7 @@ export class ChatWidgetFactory extends ABCWidgetFactory {
|
|
|
74
76
|
}
|
|
75
77
|
export class LabChatModelFactory {
|
|
76
78
|
constructor(options) {
|
|
77
|
-
var _a, _b;
|
|
79
|
+
var _a, _b, _c;
|
|
78
80
|
this.collaborative = true;
|
|
79
81
|
this._disposed = false;
|
|
80
82
|
this._user = options.user;
|
|
@@ -82,6 +84,7 @@ export class LabChatModelFactory {
|
|
|
82
84
|
this._commands = options.commands;
|
|
83
85
|
this._activeCellManager = (_a = options.activeCellManager) !== null && _a !== void 0 ? _a : null;
|
|
84
86
|
this._selectionWatcher = (_b = options.selectionWatcher) !== null && _b !== void 0 ? _b : null;
|
|
87
|
+
this._documentManager = (_c = options.documentManager) !== null && _c !== void 0 ? _c : null;
|
|
85
88
|
}
|
|
86
89
|
/**
|
|
87
90
|
* The name of the model.
|
|
@@ -144,7 +147,8 @@ export class LabChatModelFactory {
|
|
|
144
147
|
widgetConfig: this._widgetConfig,
|
|
145
148
|
commands: this._commands,
|
|
146
149
|
activeCellManager: this._activeCellManager,
|
|
147
|
-
selectionWatcher: this._selectionWatcher
|
|
150
|
+
selectionWatcher: this._selectionWatcher,
|
|
151
|
+
documentManager: this._documentManager
|
|
148
152
|
});
|
|
149
153
|
}
|
|
150
154
|
}
|
package/lib/model.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AbstractChatModel, AbstractChatContext, IChatContext, IChatMessage, IChatModel, IInputModel, INewMessage, IUser } from '@jupyter/chat';
|
|
2
2
|
import { IChangedArgs } from '@jupyterlab/coreutils';
|
|
3
3
|
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
4
4
|
import { User } from '@jupyterlab/services';
|
|
@@ -10,7 +10,7 @@ import { YChat } from './ychat';
|
|
|
10
10
|
* Chat model namespace.
|
|
11
11
|
*/
|
|
12
12
|
export declare namespace LabChatModel {
|
|
13
|
-
interface IOptions extends
|
|
13
|
+
interface IOptions extends IChatModel.IOptions {
|
|
14
14
|
widgetConfig: IWidgetConfig;
|
|
15
15
|
user: User.IIdentity | null;
|
|
16
16
|
sharedModel?: YChat;
|
|
@@ -20,7 +20,7 @@ export declare namespace LabChatModel {
|
|
|
20
20
|
/**
|
|
21
21
|
* The chat model.
|
|
22
22
|
*/
|
|
23
|
-
export declare class LabChatModel extends
|
|
23
|
+
export declare class LabChatModel extends AbstractChatModel implements DocumentRegistry.IModel {
|
|
24
24
|
constructor(options: LabChatModel.IOptions);
|
|
25
25
|
readonly collaborative = true;
|
|
26
26
|
get user(): IUser;
|
|
@@ -38,8 +38,13 @@ export declare class LabChatModel extends ChatModel implements DocumentRegistry.
|
|
|
38
38
|
fromString(data: string): void;
|
|
39
39
|
toJSON(): PartialJSONObject;
|
|
40
40
|
fromJSON(data: PartialJSONObject): void;
|
|
41
|
-
|
|
41
|
+
createChatContext(): IChatContext;
|
|
42
|
+
messagesInserted(index: number, messages: IChatMessage[]): Promise<void>;
|
|
42
43
|
sendMessage(message: INewMessage): Promise<boolean | void> | boolean | void;
|
|
44
|
+
/**
|
|
45
|
+
* Override the clear messages method.
|
|
46
|
+
*/
|
|
47
|
+
clearMessages(): void;
|
|
43
48
|
updateMessage(id: string, updatedMessage: IChatMessage): Promise<boolean | void> | boolean | void;
|
|
44
49
|
deleteMessage(id: string): Promise<boolean | void> | boolean | void;
|
|
45
50
|
/**
|
|
@@ -51,6 +56,7 @@ export declare class LabChatModel extends ChatModel implements DocumentRegistry.
|
|
|
51
56
|
* Used to populate the writers list.
|
|
52
57
|
*/
|
|
53
58
|
onAwarenessChange: () => void;
|
|
59
|
+
private _buildMentionList;
|
|
54
60
|
private _resetWritingStatus;
|
|
55
61
|
private _onchange;
|
|
56
62
|
readonly defaultKernelName: string;
|
|
@@ -65,3 +71,12 @@ export declare class LabChatModel extends ChatModel implements DocumentRegistry.
|
|
|
65
71
|
private _timeoutWriting;
|
|
66
72
|
private _user;
|
|
67
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* The chat context to be sent to the input model.
|
|
76
|
+
*/
|
|
77
|
+
export declare class LabChatContext extends AbstractChatContext {
|
|
78
|
+
/**
|
|
79
|
+
* The list of users who have connected to this chat.
|
|
80
|
+
*/
|
|
81
|
+
get users(): IUser[];
|
|
82
|
+
}
|
package/lib/model.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Jupyter Development Team.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { AbstractChatModel, AbstractChatContext } from '@jupyter/chat';
|
|
6
6
|
import { PromiseDelegate, UUID } from '@lumino/coreutils';
|
|
7
7
|
import { Signal } from '@lumino/signaling';
|
|
8
8
|
import { YChat } from './ychat';
|
|
@@ -10,7 +10,7 @@ const WRITING_DELAY = 1000;
|
|
|
10
10
|
/**
|
|
11
11
|
* The chat model.
|
|
12
12
|
*/
|
|
13
|
-
export class LabChatModel extends
|
|
13
|
+
export class LabChatModel extends AbstractChatModel {
|
|
14
14
|
constructor(options) {
|
|
15
15
|
super(options);
|
|
16
16
|
this.collaborative = true;
|
|
@@ -48,17 +48,17 @@ export class LabChatModel extends ChatModel {
|
|
|
48
48
|
}
|
|
49
49
|
this.updateWriters(writers);
|
|
50
50
|
};
|
|
51
|
-
this._onchange = (_, changes) => {
|
|
51
|
+
this._onchange = async (_, changes) => {
|
|
52
52
|
if (changes.messageChanges) {
|
|
53
53
|
const msgDelta = changes.messageChanges;
|
|
54
54
|
let index = 0;
|
|
55
|
-
|
|
55
|
+
for (const delta of msgDelta) {
|
|
56
56
|
if (delta.retain) {
|
|
57
57
|
index += delta.retain;
|
|
58
58
|
}
|
|
59
59
|
else if (delta.insert) {
|
|
60
60
|
const messages = delta.insert.map(ymessage => {
|
|
61
|
-
const { sender, attachments: attachmentIds, ...baseMessage } = ymessage;
|
|
61
|
+
const { sender, attachments: attachmentIds, mentions: mentionsIds, ...baseMessage } = ymessage;
|
|
62
62
|
// Build the base message with sender.
|
|
63
63
|
const msg = {
|
|
64
64
|
...baseMessage,
|
|
@@ -79,15 +79,21 @@ export class LabChatModel extends ChatModel {
|
|
|
79
79
|
msg.attachments = attachments;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
const mentions = mentionsIds === null || mentionsIds === void 0 ? void 0 : mentionsIds.map(user => this.sharedModel.getUser(user) || {
|
|
83
|
+
username: 'User undefined'
|
|
84
|
+
});
|
|
85
|
+
if (mentions === null || mentions === void 0 ? void 0 : mentions.length) {
|
|
86
|
+
msg.mentions = mentions;
|
|
87
|
+
}
|
|
82
88
|
return msg;
|
|
83
89
|
});
|
|
84
|
-
this.messagesInserted(index, messages);
|
|
90
|
+
await this.messagesInserted(index, messages);
|
|
85
91
|
index += messages.length;
|
|
86
92
|
}
|
|
87
93
|
else if (delta.delete) {
|
|
88
94
|
this.messagesDeleted(index, delta.delete);
|
|
89
95
|
}
|
|
90
|
-
}
|
|
96
|
+
}
|
|
91
97
|
}
|
|
92
98
|
if (changes.metadataChanges) {
|
|
93
99
|
changes.metadataChanges.forEach(change => {
|
|
@@ -98,6 +104,14 @@ export class LabChatModel extends ChatModel {
|
|
|
98
104
|
}
|
|
99
105
|
});
|
|
100
106
|
}
|
|
107
|
+
if (changes.userChanges) {
|
|
108
|
+
// Update the current user if it changes (if it has been mentioned for example).
|
|
109
|
+
changes.userChanges.forEach(change => {
|
|
110
|
+
if (change.key === this._user.username && change.newValue) {
|
|
111
|
+
this._user = change.newValue;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
101
115
|
};
|
|
102
116
|
this.defaultKernelName = '';
|
|
103
117
|
this.defaultKernelLanguage = '';
|
|
@@ -178,14 +192,18 @@ export class LabChatModel extends ChatModel {
|
|
|
178
192
|
fromJSON(data) {
|
|
179
193
|
// nothing to do
|
|
180
194
|
}
|
|
181
|
-
|
|
195
|
+
createChatContext() {
|
|
196
|
+
return new LabChatContext({ model: this });
|
|
197
|
+
}
|
|
198
|
+
async messagesInserted(index, messages) {
|
|
182
199
|
// Ensure the chat has an ID before inserting the messages, to properly catch the
|
|
183
200
|
// unread messages (the last read message is saved using the chat ID).
|
|
184
|
-
this._ready.promise.then(() => {
|
|
201
|
+
return this._ready.promise.then(() => {
|
|
185
202
|
super.messagesInserted(index, messages);
|
|
186
203
|
});
|
|
187
204
|
}
|
|
188
205
|
sendMessage(message) {
|
|
206
|
+
var _a;
|
|
189
207
|
this._resetWritingStatus();
|
|
190
208
|
if (this._timeoutWriting !== null) {
|
|
191
209
|
window.clearTimeout(this._timeoutWriting);
|
|
@@ -203,13 +221,25 @@ export class LabChatModel extends ChatModel {
|
|
|
203
221
|
this.sharedModel.setUser(this._user);
|
|
204
222
|
}
|
|
205
223
|
// Add the attachments to the message.
|
|
206
|
-
|
|
207
|
-
|
|
224
|
+
const attachmentIds = (_a = this.input.attachments) === null || _a === void 0 ? void 0 : _a.map(attachment => this.sharedModel.setAttachment(attachment));
|
|
225
|
+
if (attachmentIds === null || attachmentIds === void 0 ? void 0 : attachmentIds.length) {
|
|
208
226
|
msg.attachments = attachmentIds;
|
|
209
|
-
this.input.clearAttachments();
|
|
210
227
|
}
|
|
228
|
+
this.input.clearAttachments();
|
|
229
|
+
// Add the mentioned users.
|
|
230
|
+
const mentions = this._buildMentionList(this.input.mentions, message.body);
|
|
231
|
+
if (mentions.length) {
|
|
232
|
+
msg.mentions = mentions;
|
|
233
|
+
}
|
|
234
|
+
this.input.clearMentions();
|
|
211
235
|
this.sharedModel.addMessage(msg);
|
|
212
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Override the clear messages method.
|
|
239
|
+
*/
|
|
240
|
+
clearMessages() {
|
|
241
|
+
// No-op as we may not need to clear the messages in file based chat.
|
|
242
|
+
}
|
|
213
243
|
updateMessage(id, updatedMessage) {
|
|
214
244
|
var _a;
|
|
215
245
|
const index = this.sharedModel.getMessageIndex(id);
|
|
@@ -229,10 +259,22 @@ export class LabChatModel extends ChatModel {
|
|
|
229
259
|
edited: true
|
|
230
260
|
};
|
|
231
261
|
}
|
|
262
|
+
// Update the attachments.
|
|
232
263
|
const attachmentIds = (_a = updatedMessage.attachments) === null || _a === void 0 ? void 0 : _a.map(attachment => this.sharedModel.setAttachment(attachment));
|
|
233
|
-
if (attachmentIds) {
|
|
264
|
+
if (attachmentIds === null || attachmentIds === void 0 ? void 0 : attachmentIds.length) {
|
|
234
265
|
message.attachments = attachmentIds;
|
|
235
266
|
}
|
|
267
|
+
else {
|
|
268
|
+
delete message.attachments;
|
|
269
|
+
}
|
|
270
|
+
// Update the mentioned users.
|
|
271
|
+
const mentions = this._buildMentionList(updatedMessage.mentions, updatedMessage.body);
|
|
272
|
+
if (mentions.length) {
|
|
273
|
+
message.mentions = mentions;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
delete message.mentions;
|
|
277
|
+
}
|
|
236
278
|
this.sharedModel.updateMessage(index, message);
|
|
237
279
|
}
|
|
238
280
|
deleteMessage(id) {
|
|
@@ -246,6 +288,28 @@ export class LabChatModel extends ChatModel {
|
|
|
246
288
|
message.deleted = true;
|
|
247
289
|
this.sharedModel.updateMessage(index, message);
|
|
248
290
|
}
|
|
291
|
+
_buildMentionList(userMentions, body) {
|
|
292
|
+
if (!userMentions) {
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
const mentions = [];
|
|
296
|
+
userMentions.forEach(user => {
|
|
297
|
+
// Make sure the user is still mentioned.
|
|
298
|
+
if (!user.mention_name) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const regex = new RegExp(user.mention_name);
|
|
302
|
+
if (!regex.exec(body)) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
// Save the mention name if necessary.
|
|
306
|
+
if (!(this.sharedModel.getUser(user.username) === user)) {
|
|
307
|
+
this.sharedModel.setUser(user);
|
|
308
|
+
}
|
|
309
|
+
mentions.push(user.username);
|
|
310
|
+
});
|
|
311
|
+
return mentions;
|
|
312
|
+
}
|
|
249
313
|
_resetWritingStatus() {
|
|
250
314
|
const awareness = this.sharedModel.awareness;
|
|
251
315
|
const states = awareness.getLocalState();
|
|
@@ -254,3 +318,28 @@ export class LabChatModel extends ChatModel {
|
|
|
254
318
|
this._timeoutWriting = null;
|
|
255
319
|
}
|
|
256
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* The chat context to be sent to the input model.
|
|
323
|
+
*/
|
|
324
|
+
export class LabChatContext extends AbstractChatContext {
|
|
325
|
+
/**
|
|
326
|
+
* The list of users who have connected to this chat.
|
|
327
|
+
*/
|
|
328
|
+
get users() {
|
|
329
|
+
const model = this._model;
|
|
330
|
+
const users = new Set();
|
|
331
|
+
// Get the user list from the shared YChat
|
|
332
|
+
Object.values(model.sharedModel.users).forEach(userObject => {
|
|
333
|
+
users.add(userObject);
|
|
334
|
+
});
|
|
335
|
+
// Add the users connected to the chat (even if they never sent a message).
|
|
336
|
+
model.sharedModel.awareness.getStates().forEach(value => {
|
|
337
|
+
const user = value.user;
|
|
338
|
+
if (!user) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
users.add(user);
|
|
342
|
+
});
|
|
343
|
+
return Array.from(users);
|
|
344
|
+
}
|
|
345
|
+
}
|
package/lib/token.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IConfig, IActiveCellManager, ISelectionWatcher, ChatWidget } from '@jupyter/chat';
|
|
1
|
+
import { IConfig, IActiveCellManager, ISelectionWatcher, ChatWidget, IInputToolbarRegistry } from '@jupyter/chat';
|
|
2
2
|
import { WidgetTracker } from '@jupyterlab/apputils';
|
|
3
3
|
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
4
4
|
import { Token } from '@lumino/coreutils';
|
|
@@ -89,3 +89,16 @@ export declare const IActiveCellManagerToken: Token<IActiveCellManager>;
|
|
|
89
89
|
* The selection watcher plugin.
|
|
90
90
|
*/
|
|
91
91
|
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>;
|
package/lib/token.js
CHANGED
|
@@ -57,3 +57,7 @@ export const IActiveCellManagerToken = new Token('jupyterlab-chat:IActiveCellMan
|
|
|
57
57
|
* The selection watcher plugin.
|
|
58
58
|
*/
|
|
59
59
|
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');
|
package/lib/widget.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { CommandRegistry } from '@lumino/commands';
|
|
|
8
8
|
import { Message } from '@lumino/messaging';
|
|
9
9
|
import { Panel } from '@lumino/widgets';
|
|
10
10
|
import { LabChatModel } from './model';
|
|
11
|
-
import {
|
|
11
|
+
import { IInputToolbarRegistryFactory } from './token';
|
|
12
12
|
/**
|
|
13
13
|
* DocumentWidget: widget that represents the view or editor for a file type.
|
|
14
14
|
*/
|
|
@@ -88,9 +88,9 @@ export declare class ChatPanel extends SidePanel {
|
|
|
88
88
|
private _openChat;
|
|
89
89
|
private _rmRegistry;
|
|
90
90
|
private _themeManager;
|
|
91
|
-
private _documentManager?;
|
|
92
91
|
private _chatCommandRegistry?;
|
|
93
92
|
private _attachmentOpenerRegistry?;
|
|
93
|
+
private _inputToolbarFactory?;
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* The chat panel namespace.
|
|
@@ -105,9 +105,9 @@ export declare namespace ChatPanel {
|
|
|
105
105
|
rmRegistry: IRenderMimeRegistry;
|
|
106
106
|
themeManager: IThemeManager | null;
|
|
107
107
|
defaultDirectory: string;
|
|
108
|
-
documentManager?: IDocumentManager;
|
|
109
108
|
chatCommandRegistry?: IChatCommandRegistry;
|
|
110
109
|
attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
110
|
+
inputToolbarFactory?: IInputToolbarRegistryFactory;
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
/**
|
package/lib/widget.js
CHANGED
|
@@ -105,9 +105,9 @@ export class ChatPanel extends SidePanel {
|
|
|
105
105
|
this._rmRegistry = options.rmRegistry;
|
|
106
106
|
this._themeManager = options.themeManager;
|
|
107
107
|
this._defaultDirectory = options.defaultDirectory;
|
|
108
|
-
this._documentManager = options.documentManager;
|
|
109
108
|
this._chatCommandRegistry = options.chatCommandRegistry;
|
|
110
109
|
this._attachmentOpenerRegistry = options.attachmentOpenerRegistry;
|
|
110
|
+
this._inputToolbarFactory = options.inputToolbarFactory;
|
|
111
111
|
const addChat = new CommandToolbarButton({
|
|
112
112
|
commands: this._commands,
|
|
113
113
|
id: CommandIDs.createChat,
|
|
@@ -152,14 +152,19 @@ export class ChatPanel extends SidePanel {
|
|
|
152
152
|
for (let i = 0; i < this.widgets.length; i++) {
|
|
153
153
|
content.collapse(i);
|
|
154
154
|
}
|
|
155
|
+
// Create the toolbar registry.
|
|
156
|
+
let inputToolbarRegistry;
|
|
157
|
+
if (this._inputToolbarFactory) {
|
|
158
|
+
inputToolbarRegistry = this._inputToolbarFactory.create();
|
|
159
|
+
}
|
|
155
160
|
// Create a new widget.
|
|
156
161
|
const widget = new ChatWidget({
|
|
157
162
|
model: model,
|
|
158
163
|
rmRegistry: this._rmRegistry,
|
|
159
164
|
themeManager: this._themeManager,
|
|
160
|
-
documentManager: this._documentManager,
|
|
161
165
|
chatCommandRegistry: this._chatCommandRegistry,
|
|
162
|
-
attachmentOpenerRegistry: this._attachmentOpenerRegistry
|
|
166
|
+
attachmentOpenerRegistry: this._attachmentOpenerRegistry,
|
|
167
|
+
inputToolbarRegistry
|
|
163
168
|
});
|
|
164
169
|
this.addWidget(new ChatSection({
|
|
165
170
|
widget,
|
package/lib/ychat.d.ts
CHANGED
|
@@ -65,7 +65,7 @@ export declare class YChat extends YDocument<IChatChanges> {
|
|
|
65
65
|
*/
|
|
66
66
|
static create(options?: YDocument.IOptions): YChat;
|
|
67
67
|
get id(): string;
|
|
68
|
-
get users():
|
|
68
|
+
get users(): Record<string, IUser>;
|
|
69
69
|
get messages(): string[];
|
|
70
70
|
get attachments(): JSONObject;
|
|
71
71
|
getSource(): JSONObject;
|
package/lib/ychat.js
CHANGED
|
@@ -140,7 +140,8 @@ export class YChat extends YDocument {
|
|
|
140
140
|
return this._metadata.get('id') || '';
|
|
141
141
|
}
|
|
142
142
|
get users() {
|
|
143
|
-
|
|
143
|
+
const userDict = JSONExt.deepCopy(this._users.toJSON());
|
|
144
|
+
return userDict;
|
|
144
145
|
}
|
|
145
146
|
get messages() {
|
|
146
147
|
return JSONExt.deepCopy(this._messages.toJSON());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab-chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "The library to build a chat based on shared document",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"watch:src": "tsc -w --sourceMap"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@jupyter/chat": "^0.
|
|
45
|
+
"@jupyter/chat": "^0.10.0",
|
|
46
46
|
"@jupyter/collaborative-drive": "^3.0.0",
|
|
47
47
|
"@jupyter/ydoc": "^2.0.0 || ^3.0.0",
|
|
48
48
|
"@jupyterlab/application": "^4.2.0",
|
package/src/factory.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
IActiveCellManager,
|
|
9
9
|
IAttachmentOpenerRegistry,
|
|
10
10
|
IChatCommandRegistry,
|
|
11
|
+
IInputToolbarRegistry,
|
|
11
12
|
ISelectionWatcher
|
|
12
13
|
} from '@jupyter/chat';
|
|
13
14
|
import { IThemeManager } from '@jupyterlab/apputils';
|
|
@@ -21,7 +22,11 @@ import { ISignal, Signal } from '@lumino/signaling';
|
|
|
21
22
|
import { LabChatModel } from './model';
|
|
22
23
|
import { LabChatPanel } from './widget';
|
|
23
24
|
import { YChat } from './ychat';
|
|
24
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
IInputToolbarRegistryFactory,
|
|
27
|
+
ILabChatConfig,
|
|
28
|
+
IWidgetConfig
|
|
29
|
+
} from './token';
|
|
25
30
|
|
|
26
31
|
/**
|
|
27
32
|
* The object provided by the chatDocument extension.
|
|
@@ -76,9 +81,9 @@ export class ChatWidgetFactory extends ABCWidgetFactory<
|
|
|
76
81
|
super(options);
|
|
77
82
|
this._themeManager = options.themeManager;
|
|
78
83
|
this._rmRegistry = options.rmRegistry;
|
|
79
|
-
this._documentManager = options.documentManager;
|
|
80
84
|
this._chatCommandRegistry = options.chatCommandRegistry;
|
|
81
85
|
this._attachmentOpenerRegistry = options.attachmentOpenerRegistry;
|
|
86
|
+
this._inputToolbarFactory = options.inputToolbarFactory;
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
/**
|
|
@@ -90,9 +95,11 @@ export class ChatWidgetFactory extends ABCWidgetFactory<
|
|
|
90
95
|
protected createNewWidget(context: ChatWidgetFactory.IContext): LabChatPanel {
|
|
91
96
|
context.rmRegistry = this._rmRegistry;
|
|
92
97
|
context.themeManager = this._themeManager;
|
|
93
|
-
context.documentManager = this._documentManager;
|
|
94
98
|
context.chatCommandRegistry = this._chatCommandRegistry;
|
|
95
99
|
context.attachmentOpenerRegistry = this._attachmentOpenerRegistry;
|
|
100
|
+
if (this._inputToolbarFactory) {
|
|
101
|
+
context.inputToolbarRegistry = this._inputToolbarFactory.create();
|
|
102
|
+
}
|
|
96
103
|
return new LabChatPanel({
|
|
97
104
|
context,
|
|
98
105
|
content: new ChatWidget(context)
|
|
@@ -101,9 +108,9 @@ export class ChatWidgetFactory extends ABCWidgetFactory<
|
|
|
101
108
|
|
|
102
109
|
private _themeManager: IThemeManager | null;
|
|
103
110
|
private _rmRegistry: IRenderMimeRegistry;
|
|
104
|
-
private _documentManager?: IDocumentManager;
|
|
105
111
|
private _chatCommandRegistry?: IChatCommandRegistry;
|
|
106
112
|
private _attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
113
|
+
private _inputToolbarFactory?: IInputToolbarRegistryFactory;
|
|
107
114
|
}
|
|
108
115
|
|
|
109
116
|
export namespace ChatWidgetFactory {
|
|
@@ -113,15 +120,16 @@ export namespace ChatWidgetFactory {
|
|
|
113
120
|
documentManager?: IDocumentManager;
|
|
114
121
|
chatCommandRegistry?: IChatCommandRegistry;
|
|
115
122
|
attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
123
|
+
inputToolbarRegistry?: IInputToolbarRegistry;
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
export interface IOptions<T extends LabChatPanel>
|
|
119
127
|
extends DocumentRegistry.IWidgetFactoryOptions<T> {
|
|
120
128
|
themeManager: IThemeManager | null;
|
|
121
129
|
rmRegistry: IRenderMimeRegistry;
|
|
122
|
-
documentManager?: IDocumentManager;
|
|
123
130
|
chatCommandRegistry?: IChatCommandRegistry;
|
|
124
131
|
attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
132
|
+
inputToolbarFactory?: IInputToolbarRegistryFactory;
|
|
125
133
|
}
|
|
126
134
|
}
|
|
127
135
|
|
|
@@ -134,6 +142,7 @@ export class LabChatModelFactory
|
|
|
134
142
|
this._commands = options.commands;
|
|
135
143
|
this._activeCellManager = options.activeCellManager ?? null;
|
|
136
144
|
this._selectionWatcher = options.selectionWatcher ?? null;
|
|
145
|
+
this._documentManager = options.documentManager ?? null;
|
|
137
146
|
}
|
|
138
147
|
|
|
139
148
|
collaborative = true;
|
|
@@ -206,7 +215,8 @@ export class LabChatModelFactory
|
|
|
206
215
|
widgetConfig: this._widgetConfig,
|
|
207
216
|
commands: this._commands,
|
|
208
217
|
activeCellManager: this._activeCellManager,
|
|
209
|
-
selectionWatcher: this._selectionWatcher
|
|
218
|
+
selectionWatcher: this._selectionWatcher,
|
|
219
|
+
documentManager: this._documentManager
|
|
210
220
|
});
|
|
211
221
|
}
|
|
212
222
|
|
|
@@ -216,4 +226,5 @@ export class LabChatModelFactory
|
|
|
216
226
|
private _commands?: CommandRegistry;
|
|
217
227
|
private _activeCellManager: IActiveCellManager | null;
|
|
218
228
|
private _selectionWatcher: ISelectionWatcher | null;
|
|
229
|
+
private _documentManager: IDocumentManager | null;
|
|
219
230
|
}
|
package/src/model.ts
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
AbstractChatModel,
|
|
8
|
+
AbstractChatContext,
|
|
8
9
|
IAttachment,
|
|
10
|
+
IChatContext,
|
|
9
11
|
IChatMessage,
|
|
12
|
+
IChatModel,
|
|
10
13
|
IInputModel,
|
|
11
14
|
INewMessage,
|
|
12
15
|
IUser
|
|
@@ -26,7 +29,7 @@ const WRITING_DELAY = 1000;
|
|
|
26
29
|
* Chat model namespace.
|
|
27
30
|
*/
|
|
28
31
|
export namespace LabChatModel {
|
|
29
|
-
export interface IOptions extends
|
|
32
|
+
export interface IOptions extends IChatModel.IOptions {
|
|
30
33
|
widgetConfig: IWidgetConfig;
|
|
31
34
|
user: User.IIdentity | null;
|
|
32
35
|
sharedModel?: YChat;
|
|
@@ -37,7 +40,10 @@ export namespace LabChatModel {
|
|
|
37
40
|
/**
|
|
38
41
|
* The chat model.
|
|
39
42
|
*/
|
|
40
|
-
export class LabChatModel
|
|
43
|
+
export class LabChatModel
|
|
44
|
+
extends AbstractChatModel
|
|
45
|
+
implements DocumentRegistry.IModel
|
|
46
|
+
{
|
|
41
47
|
constructor(options: LabChatModel.IOptions) {
|
|
42
48
|
super(options);
|
|
43
49
|
|
|
@@ -133,10 +139,17 @@ export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
|
|
|
133
139
|
// nothing to do
|
|
134
140
|
}
|
|
135
141
|
|
|
136
|
-
|
|
142
|
+
createChatContext(): IChatContext {
|
|
143
|
+
return new LabChatContext({ model: this });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async messagesInserted(
|
|
147
|
+
index: number,
|
|
148
|
+
messages: IChatMessage[]
|
|
149
|
+
): Promise<void> {
|
|
137
150
|
// Ensure the chat has an ID before inserting the messages, to properly catch the
|
|
138
151
|
// unread messages (the last read message is saved using the chat ID).
|
|
139
|
-
this._ready.promise.then(() => {
|
|
152
|
+
return this._ready.promise.then(() => {
|
|
140
153
|
super.messagesInserted(index, messages);
|
|
141
154
|
});
|
|
142
155
|
}
|
|
@@ -162,17 +175,31 @@ export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
|
|
|
162
175
|
}
|
|
163
176
|
|
|
164
177
|
// Add the attachments to the message.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
178
|
+
const attachmentIds = this.input.attachments?.map(attachment =>
|
|
179
|
+
this.sharedModel.setAttachment(attachment)
|
|
180
|
+
);
|
|
181
|
+
if (attachmentIds?.length) {
|
|
169
182
|
msg.attachments = attachmentIds;
|
|
170
|
-
this.input.clearAttachments();
|
|
171
183
|
}
|
|
184
|
+
this.input.clearAttachments();
|
|
185
|
+
|
|
186
|
+
// Add the mentioned users.
|
|
187
|
+
const mentions = this._buildMentionList(this.input.mentions, message.body);
|
|
188
|
+
if (mentions.length) {
|
|
189
|
+
msg.mentions = mentions;
|
|
190
|
+
}
|
|
191
|
+
this.input.clearMentions();
|
|
172
192
|
|
|
173
193
|
this.sharedModel.addMessage(msg);
|
|
174
194
|
}
|
|
175
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Override the clear messages method.
|
|
198
|
+
*/
|
|
199
|
+
clearMessages(): void {
|
|
200
|
+
// No-op as we may not need to clear the messages in file based chat.
|
|
201
|
+
}
|
|
202
|
+
|
|
176
203
|
updateMessage(
|
|
177
204
|
id: string,
|
|
178
205
|
updatedMessage: IChatMessage
|
|
@@ -194,12 +221,28 @@ export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
|
|
|
194
221
|
edited: true
|
|
195
222
|
};
|
|
196
223
|
}
|
|
224
|
+
|
|
225
|
+
// Update the attachments.
|
|
197
226
|
const attachmentIds = updatedMessage.attachments?.map(attachment =>
|
|
198
227
|
this.sharedModel.setAttachment(attachment)
|
|
199
228
|
);
|
|
200
|
-
if (attachmentIds) {
|
|
229
|
+
if (attachmentIds?.length) {
|
|
201
230
|
message.attachments = attachmentIds;
|
|
231
|
+
} else {
|
|
232
|
+
delete message.attachments;
|
|
202
233
|
}
|
|
234
|
+
|
|
235
|
+
// Update the mentioned users.
|
|
236
|
+
const mentions = this._buildMentionList(
|
|
237
|
+
updatedMessage.mentions,
|
|
238
|
+
updatedMessage.body
|
|
239
|
+
);
|
|
240
|
+
if (mentions.length) {
|
|
241
|
+
message.mentions = mentions;
|
|
242
|
+
} else {
|
|
243
|
+
delete message.mentions;
|
|
244
|
+
}
|
|
245
|
+
|
|
203
246
|
this.sharedModel.updateMessage(index, message as IYmessage);
|
|
204
247
|
}
|
|
205
248
|
|
|
@@ -251,6 +294,33 @@ export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
|
|
|
251
294
|
this.updateWriters(writers);
|
|
252
295
|
};
|
|
253
296
|
|
|
297
|
+
private _buildMentionList(
|
|
298
|
+
userMentions: IUser[] | undefined,
|
|
299
|
+
body: string
|
|
300
|
+
): string[] {
|
|
301
|
+
if (!userMentions) {
|
|
302
|
+
return [];
|
|
303
|
+
}
|
|
304
|
+
const mentions: string[] = [];
|
|
305
|
+
userMentions.forEach(user => {
|
|
306
|
+
// Make sure the user is still mentioned.
|
|
307
|
+
if (!user.mention_name) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const regex = new RegExp(user.mention_name);
|
|
311
|
+
if (!regex.exec(body)) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Save the mention name if necessary.
|
|
316
|
+
if (!(this.sharedModel.getUser(user.username) === user)) {
|
|
317
|
+
this.sharedModel.setUser(user);
|
|
318
|
+
}
|
|
319
|
+
mentions.push(user.username);
|
|
320
|
+
});
|
|
321
|
+
return mentions;
|
|
322
|
+
}
|
|
323
|
+
|
|
254
324
|
private _resetWritingStatus() {
|
|
255
325
|
const awareness = this.sharedModel.awareness;
|
|
256
326
|
const states = awareness.getLocalState();
|
|
@@ -259,11 +329,11 @@ export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
|
|
|
259
329
|
this._timeoutWriting = null;
|
|
260
330
|
}
|
|
261
331
|
|
|
262
|
-
private _onchange = (_: YChat, changes: IChatChanges) => {
|
|
332
|
+
private _onchange = async (_: YChat, changes: IChatChanges) => {
|
|
263
333
|
if (changes.messageChanges) {
|
|
264
334
|
const msgDelta = changes.messageChanges;
|
|
265
335
|
let index = 0;
|
|
266
|
-
|
|
336
|
+
for (const delta of msgDelta) {
|
|
267
337
|
if (delta.retain) {
|
|
268
338
|
index += delta.retain;
|
|
269
339
|
} else if (delta.insert) {
|
|
@@ -271,6 +341,7 @@ export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
|
|
|
271
341
|
const {
|
|
272
342
|
sender,
|
|
273
343
|
attachments: attachmentIds,
|
|
344
|
+
mentions: mentionsIds,
|
|
274
345
|
...baseMessage
|
|
275
346
|
} = ymessage;
|
|
276
347
|
|
|
@@ -296,14 +367,24 @@ export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
|
|
|
296
367
|
}
|
|
297
368
|
}
|
|
298
369
|
|
|
370
|
+
const mentions = mentionsIds?.map(
|
|
371
|
+
user =>
|
|
372
|
+
this.sharedModel.getUser(user) || {
|
|
373
|
+
username: 'User undefined'
|
|
374
|
+
}
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
if (mentions?.length) {
|
|
378
|
+
msg.mentions = mentions;
|
|
379
|
+
}
|
|
299
380
|
return msg;
|
|
300
381
|
});
|
|
301
|
-
this.messagesInserted(index, messages);
|
|
382
|
+
await this.messagesInserted(index, messages);
|
|
302
383
|
index += messages.length;
|
|
303
384
|
} else if (delta.delete) {
|
|
304
385
|
this.messagesDeleted(index, delta.delete);
|
|
305
386
|
}
|
|
306
|
-
}
|
|
387
|
+
}
|
|
307
388
|
}
|
|
308
389
|
|
|
309
390
|
if (changes.metadataChanges) {
|
|
@@ -315,6 +396,15 @@ export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
|
|
|
315
396
|
}
|
|
316
397
|
});
|
|
317
398
|
}
|
|
399
|
+
|
|
400
|
+
if (changes.userChanges) {
|
|
401
|
+
// Update the current user if it changes (if it has been mentioned for example).
|
|
402
|
+
changes.userChanges.forEach(change => {
|
|
403
|
+
if (change.key === this._user.username && change.newValue) {
|
|
404
|
+
this._user = change.newValue;
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
318
408
|
};
|
|
319
409
|
|
|
320
410
|
readonly defaultKernelName: string = '';
|
|
@@ -332,3 +422,32 @@ export class LabChatModel extends ChatModel implements DocumentRegistry.IModel {
|
|
|
332
422
|
|
|
333
423
|
private _user: IUser;
|
|
334
424
|
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* The chat context to be sent to the input model.
|
|
428
|
+
*/
|
|
429
|
+
export class LabChatContext extends AbstractChatContext {
|
|
430
|
+
/**
|
|
431
|
+
* The list of users who have connected to this chat.
|
|
432
|
+
*/
|
|
433
|
+
get users(): IUser[] {
|
|
434
|
+
const model = this._model as LabChatModel;
|
|
435
|
+
const users = new Set<IUser>();
|
|
436
|
+
|
|
437
|
+
// Get the user list from the shared YChat
|
|
438
|
+
Object.values(model.sharedModel.users).forEach(userObject => {
|
|
439
|
+
users.add(userObject);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// Add the users connected to the chat (even if they never sent a message).
|
|
443
|
+
model.sharedModel.awareness.getStates().forEach(value => {
|
|
444
|
+
const user = value.user as IUser;
|
|
445
|
+
if (!user) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
users.add(user);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
return Array.from(users);
|
|
452
|
+
}
|
|
453
|
+
}
|
package/src/token.ts
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
chatIcon,
|
|
9
9
|
IActiveCellManager,
|
|
10
10
|
ISelectionWatcher,
|
|
11
|
-
ChatWidget
|
|
11
|
+
ChatWidget,
|
|
12
|
+
IInputToolbarRegistry
|
|
12
13
|
} from '@jupyter/chat';
|
|
13
14
|
import { WidgetTracker } from '@jupyterlab/apputils';
|
|
14
15
|
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
@@ -125,3 +126,21 @@ export const IActiveCellManagerToken = new Token<IActiveCellManager>(
|
|
|
125
126
|
export const ISelectionWatcherToken = new Token<ISelectionWatcher>(
|
|
126
127
|
'jupyterlab-chat:ISelectionWatcher'
|
|
127
128
|
);
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The input toolbar registry factory.
|
|
132
|
+
*/
|
|
133
|
+
export interface IInputToolbarRegistryFactory {
|
|
134
|
+
/**
|
|
135
|
+
* Create an input toolbar registry.
|
|
136
|
+
*/
|
|
137
|
+
create: () => IInputToolbarRegistry;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The token of the factory to create an input toolbar registry.
|
|
142
|
+
*/
|
|
143
|
+
export const IInputToolbarRegistryFactory =
|
|
144
|
+
new Token<IInputToolbarRegistryFactory>(
|
|
145
|
+
'jupyterlab-chat:IInputToolbarRegistryFactory'
|
|
146
|
+
);
|
package/src/widget.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
IAttachmentOpenerRegistry,
|
|
9
9
|
IChatCommandRegistry,
|
|
10
10
|
IChatModel,
|
|
11
|
+
IInputToolbarRegistry,
|
|
11
12
|
readIcon
|
|
12
13
|
} from '@jupyter/chat';
|
|
13
14
|
import { ICollaborativeDrive } from '@jupyter/collaborative-drive';
|
|
@@ -33,8 +34,11 @@ import { AccordionPanel, Panel } from '@lumino/widgets';
|
|
|
33
34
|
import React, { useState } from 'react';
|
|
34
35
|
|
|
35
36
|
import { LabChatModel } from './model';
|
|
36
|
-
import {
|
|
37
|
-
|
|
37
|
+
import {
|
|
38
|
+
CommandIDs,
|
|
39
|
+
IInputToolbarRegistryFactory,
|
|
40
|
+
chatFileType
|
|
41
|
+
} from './token';
|
|
38
42
|
|
|
39
43
|
const MAIN_PANEL_CLASS = 'jp-lab-chat-main-panel';
|
|
40
44
|
const TITLE_UNREAD_CLASS = 'jp-lab-chat-title-unread';
|
|
@@ -104,9 +108,9 @@ export class ChatPanel extends SidePanel {
|
|
|
104
108
|
this._rmRegistry = options.rmRegistry;
|
|
105
109
|
this._themeManager = options.themeManager;
|
|
106
110
|
this._defaultDirectory = options.defaultDirectory;
|
|
107
|
-
this._documentManager = options.documentManager;
|
|
108
111
|
this._chatCommandRegistry = options.chatCommandRegistry;
|
|
109
112
|
this._attachmentOpenerRegistry = options.attachmentOpenerRegistry;
|
|
113
|
+
this._inputToolbarFactory = options.inputToolbarFactory;
|
|
110
114
|
|
|
111
115
|
const addChat = new CommandToolbarButton({
|
|
112
116
|
commands: this._commands,
|
|
@@ -163,14 +167,20 @@ export class ChatPanel extends SidePanel {
|
|
|
163
167
|
content.collapse(i);
|
|
164
168
|
}
|
|
165
169
|
|
|
170
|
+
// Create the toolbar registry.
|
|
171
|
+
let inputToolbarRegistry: IInputToolbarRegistry | undefined;
|
|
172
|
+
if (this._inputToolbarFactory) {
|
|
173
|
+
inputToolbarRegistry = this._inputToolbarFactory.create();
|
|
174
|
+
}
|
|
175
|
+
|
|
166
176
|
// Create a new widget.
|
|
167
177
|
const widget = new ChatWidget({
|
|
168
178
|
model: model,
|
|
169
179
|
rmRegistry: this._rmRegistry,
|
|
170
180
|
themeManager: this._themeManager,
|
|
171
|
-
documentManager: this._documentManager,
|
|
172
181
|
chatCommandRegistry: this._chatCommandRegistry,
|
|
173
|
-
attachmentOpenerRegistry: this._attachmentOpenerRegistry
|
|
182
|
+
attachmentOpenerRegistry: this._attachmentOpenerRegistry,
|
|
183
|
+
inputToolbarRegistry
|
|
174
184
|
});
|
|
175
185
|
|
|
176
186
|
this.addWidget(
|
|
@@ -289,9 +299,9 @@ export class ChatPanel extends SidePanel {
|
|
|
289
299
|
private _openChat: ReactWidget;
|
|
290
300
|
private _rmRegistry: IRenderMimeRegistry;
|
|
291
301
|
private _themeManager: IThemeManager | null;
|
|
292
|
-
private _documentManager?: IDocumentManager;
|
|
293
302
|
private _chatCommandRegistry?: IChatCommandRegistry;
|
|
294
303
|
private _attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
304
|
+
private _inputToolbarFactory?: IInputToolbarRegistryFactory;
|
|
295
305
|
}
|
|
296
306
|
|
|
297
307
|
/**
|
|
@@ -307,9 +317,9 @@ export namespace ChatPanel {
|
|
|
307
317
|
rmRegistry: IRenderMimeRegistry;
|
|
308
318
|
themeManager: IThemeManager | null;
|
|
309
319
|
defaultDirectory: string;
|
|
310
|
-
documentManager?: IDocumentManager;
|
|
311
320
|
chatCommandRegistry?: IChatCommandRegistry;
|
|
312
321
|
attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
322
|
+
inputToolbarFactory?: IInputToolbarRegistryFactory;
|
|
313
323
|
}
|
|
314
324
|
}
|
|
315
325
|
|
package/src/ychat.ts
CHANGED
|
@@ -100,8 +100,13 @@ export class YChat extends YDocument<IChatChanges> {
|
|
|
100
100
|
return (this._metadata.get('id') as string) || '';
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
get users():
|
|
104
|
-
|
|
103
|
+
get users(): Record<string, IUser> {
|
|
104
|
+
const userDict = JSONExt.deepCopy(this._users.toJSON()) as Record<
|
|
105
|
+
string,
|
|
106
|
+
IUser
|
|
107
|
+
>;
|
|
108
|
+
|
|
109
|
+
return userDict;
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
get messages(): string[] {
|