@jupyter/chat 0.19.0-alpha.2 → 0.19.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/__tests__/model.spec.js +2 -2
- package/lib/components/chat.js +29 -2
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.js +1 -0
- package/lib/components/input/buttons/attach-button.js +1 -1
- package/lib/components/input/buttons/cancel-button.js +1 -1
- package/lib/components/input/buttons/save-edit-button.js +1 -1
- package/lib/components/input/buttons/send-button.js +3 -1
- package/lib/components/input/buttons/stop-button.js +1 -1
- package/lib/components/input/chat-input.js +3 -30
- package/lib/components/input/index.d.ts +0 -1
- package/lib/components/input/index.js +0 -1
- package/lib/components/messages/footer.d.ts +2 -2
- package/lib/components/messages/header.d.ts +2 -2
- package/lib/components/messages/header.js +13 -6
- package/lib/components/messages/message.d.ts +2 -2
- package/lib/components/messages/message.js +16 -1
- package/lib/components/messages/messages.js +3 -2
- package/lib/components/messages/toolbar.js +6 -14
- package/lib/components/mui-extras/tooltipped-button.d.ts +5 -26
- package/lib/components/mui-extras/tooltipped-button.js +4 -33
- package/lib/components/mui-extras/tooltipped-icon-button.d.ts +12 -22
- package/lib/components/mui-extras/tooltipped-icon-button.js +10 -8
- package/lib/components/writing-indicator.d.ts +20 -0
- package/lib/components/{input/writing-indicator.js → writing-indicator.js} +3 -2
- package/lib/message.d.ts +41 -0
- package/lib/message.js +74 -0
- package/lib/model.d.ts +13 -13
- package/lib/model.js +9 -7
- package/lib/registers/footers.d.ts +2 -2
- package/lib/theme-provider.d.ts +19 -0
- package/lib/theme-provider.js +74 -3
- package/lib/types.d.ts +21 -3
- package/lib/widgets/chat-widget.d.ts +4 -0
- package/lib/widgets/chat-widget.js +52 -8
- package/lib/widgets/multichat-panel.js +1 -1
- package/package.json +3 -1
- package/src/__tests__/model.spec.ts +7 -7
- package/src/components/chat.tsx +35 -1
- package/src/components/index.ts +1 -0
- package/src/components/input/buttons/attach-button.tsx +1 -1
- package/src/components/input/buttons/cancel-button.tsx +1 -1
- package/src/components/input/buttons/save-edit-button.tsx +1 -1
- package/src/components/input/buttons/send-button.tsx +4 -1
- package/src/components/input/buttons/stop-button.tsx +1 -1
- package/src/components/input/chat-input.tsx +1 -34
- package/src/components/input/index.ts +0 -1
- package/src/components/messages/footer.tsx +2 -2
- package/src/components/messages/header.tsx +20 -8
- package/src/components/messages/message.tsx +23 -3
- package/src/components/messages/messages.tsx +9 -4
- package/src/components/messages/toolbar.tsx +14 -14
- package/src/components/mui-extras/tooltipped-button.tsx +9 -43
- package/src/components/mui-extras/tooltipped-icon-button.tsx +17 -38
- package/src/components/{input/writing-indicator.tsx → writing-indicator.tsx} +9 -4
- package/src/message.ts +83 -0
- package/src/model.ts +25 -22
- package/src/registers/footers.ts +2 -2
- package/src/theme-provider.ts +95 -3
- package/src/types.ts +23 -3
- package/src/widgets/chat-widget.tsx +61 -10
- package/src/widgets/multichat-panel.tsx +5 -1
- package/style/chat.css +10 -0
- package/style/input.css +4 -0
- package/lib/components/input/writing-indicator.d.ts +0 -15
package/lib/message.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ISignal } from '@lumino/signaling';
|
|
2
|
+
import { IAttachment, IMessageContent, IMessage, IUser } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* The message object.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Message implements IMessage {
|
|
7
|
+
/**
|
|
8
|
+
* The constructor of the message.
|
|
9
|
+
*
|
|
10
|
+
* @param content: the content of the message.
|
|
11
|
+
*/
|
|
12
|
+
constructor(content: IMessageContent);
|
|
13
|
+
/**
|
|
14
|
+
* The message content.
|
|
15
|
+
*/
|
|
16
|
+
get content(): IMessageContent;
|
|
17
|
+
/**
|
|
18
|
+
* Getters for each attribute individually.
|
|
19
|
+
*/
|
|
20
|
+
get type(): string;
|
|
21
|
+
get body(): string;
|
|
22
|
+
get id(): string;
|
|
23
|
+
get time(): number;
|
|
24
|
+
get sender(): IUser;
|
|
25
|
+
get attachments(): IAttachment[] | undefined;
|
|
26
|
+
get mentions(): IUser[] | undefined;
|
|
27
|
+
get raw_time(): boolean | undefined;
|
|
28
|
+
get deleted(): boolean | undefined;
|
|
29
|
+
get edited(): boolean | undefined;
|
|
30
|
+
get stacked(): boolean | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* A signal emitting when the message has been updated.
|
|
33
|
+
*/
|
|
34
|
+
get changed(): ISignal<IMessage, void>;
|
|
35
|
+
/**
|
|
36
|
+
* Update one or several fields of the message.
|
|
37
|
+
*/
|
|
38
|
+
update(updated: Partial<IMessageContent>): void;
|
|
39
|
+
private _content;
|
|
40
|
+
private _changed;
|
|
41
|
+
}
|
package/lib/message.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { Signal } from '@lumino/signaling';
|
|
6
|
+
/**
|
|
7
|
+
* The message object.
|
|
8
|
+
*/
|
|
9
|
+
export class Message {
|
|
10
|
+
/**
|
|
11
|
+
* The constructor of the message.
|
|
12
|
+
*
|
|
13
|
+
* @param content: the content of the message.
|
|
14
|
+
*/
|
|
15
|
+
constructor(content) {
|
|
16
|
+
this._changed = new Signal(this);
|
|
17
|
+
this._content = content;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The message content.
|
|
21
|
+
*/
|
|
22
|
+
get content() {
|
|
23
|
+
return this._content;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Getters for each attribute individually.
|
|
27
|
+
*/
|
|
28
|
+
get type() {
|
|
29
|
+
return this._content.type;
|
|
30
|
+
}
|
|
31
|
+
get body() {
|
|
32
|
+
return this._content.body;
|
|
33
|
+
}
|
|
34
|
+
get id() {
|
|
35
|
+
return this._content.id;
|
|
36
|
+
}
|
|
37
|
+
get time() {
|
|
38
|
+
return this._content.time;
|
|
39
|
+
}
|
|
40
|
+
get sender() {
|
|
41
|
+
return this._content.sender;
|
|
42
|
+
}
|
|
43
|
+
get attachments() {
|
|
44
|
+
return this._content.attachments;
|
|
45
|
+
}
|
|
46
|
+
get mentions() {
|
|
47
|
+
return this._content.mentions;
|
|
48
|
+
}
|
|
49
|
+
get raw_time() {
|
|
50
|
+
return this._content.raw_time;
|
|
51
|
+
}
|
|
52
|
+
get deleted() {
|
|
53
|
+
return this._content.deleted;
|
|
54
|
+
}
|
|
55
|
+
get edited() {
|
|
56
|
+
return this._content.edited;
|
|
57
|
+
}
|
|
58
|
+
get stacked() {
|
|
59
|
+
return this._content.stacked;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A signal emitting when the message has been updated.
|
|
63
|
+
*/
|
|
64
|
+
get changed() {
|
|
65
|
+
return this._changed;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Update one or several fields of the message.
|
|
69
|
+
*/
|
|
70
|
+
update(updated) {
|
|
71
|
+
this._content = { ...this._content, ...updated };
|
|
72
|
+
this._changed.emit();
|
|
73
|
+
}
|
|
74
|
+
}
|
package/lib/model.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { ISignal } from '@lumino/signaling';
|
|
|
5
5
|
import { IActiveCellManager } from './active-cell-manager';
|
|
6
6
|
import { IInputModel } from './input-model';
|
|
7
7
|
import { ISelectionWatcher } from './selection-watcher';
|
|
8
|
-
import { IChatHistory,
|
|
8
|
+
import { IChatHistory, IConfig, IMessage, IMessageContent, INewMessage, IUser } from './types';
|
|
9
9
|
/**
|
|
10
10
|
* The chat model interface.
|
|
11
11
|
*/
|
|
@@ -37,7 +37,7 @@ export interface IChatModel extends IDisposable {
|
|
|
37
37
|
/**
|
|
38
38
|
* The chat messages list.
|
|
39
39
|
*/
|
|
40
|
-
readonly messages:
|
|
40
|
+
readonly messages: IMessage[];
|
|
41
41
|
/**
|
|
42
42
|
* The input model.
|
|
43
43
|
*/
|
|
@@ -100,7 +100,7 @@ export interface IChatModel extends IDisposable {
|
|
|
100
100
|
* @param id - the unique ID of the message.
|
|
101
101
|
* @param message - the updated message.
|
|
102
102
|
*/
|
|
103
|
-
updateMessage?(id: string, message:
|
|
103
|
+
updateMessage?(id: string, message: IMessageContent): Promise<boolean | void> | boolean | void;
|
|
104
104
|
/**
|
|
105
105
|
* Optional, to delete a message from the chat.
|
|
106
106
|
*
|
|
@@ -124,14 +124,14 @@ export interface IChatModel extends IDisposable {
|
|
|
124
124
|
*
|
|
125
125
|
* @param message - the message with user information and body.
|
|
126
126
|
*/
|
|
127
|
-
messageAdded(message:
|
|
127
|
+
messageAdded(message: IMessageContent): void;
|
|
128
128
|
/**
|
|
129
129
|
* Function called when messages are inserted.
|
|
130
130
|
*
|
|
131
131
|
* @param index - the index of the first message of the list.
|
|
132
132
|
* @param messages - the messages list.
|
|
133
133
|
*/
|
|
134
|
-
messagesInserted(index: number, messages:
|
|
134
|
+
messagesInserted(index: number, messages: IMessageContent[]): void;
|
|
135
135
|
/**
|
|
136
136
|
* Function called when messages are deleted.
|
|
137
137
|
*
|
|
@@ -185,7 +185,7 @@ export declare abstract class AbstractChatModel implements IChatModel {
|
|
|
185
185
|
/**
|
|
186
186
|
* The chat messages list.
|
|
187
187
|
*/
|
|
188
|
-
get messages():
|
|
188
|
+
get messages(): IMessage[];
|
|
189
189
|
/**
|
|
190
190
|
* The input model.
|
|
191
191
|
*/
|
|
@@ -235,7 +235,7 @@ export declare abstract class AbstractChatModel implements IChatModel {
|
|
|
235
235
|
get messagesInViewport(): number[];
|
|
236
236
|
set messagesInViewport(values: number[]);
|
|
237
237
|
/**
|
|
238
|
-
* A signal emitting when the
|
|
238
|
+
* A signal emitting when the message list is updated.
|
|
239
239
|
*/
|
|
240
240
|
get messagesUpdated(): ISignal<IChatModel, void>;
|
|
241
241
|
/**
|
|
@@ -282,20 +282,20 @@ export declare abstract class AbstractChatModel implements IChatModel {
|
|
|
282
282
|
* A function called before transferring the message to the panel(s).
|
|
283
283
|
* Can be useful if some actions are required on the message.
|
|
284
284
|
*/
|
|
285
|
-
protected formatChatMessage(message:
|
|
285
|
+
protected formatChatMessage(message: IMessageContent): IMessageContent;
|
|
286
286
|
/**
|
|
287
287
|
* Function to call when a message is received.
|
|
288
288
|
*
|
|
289
289
|
* @param message - the message with user information and body.
|
|
290
290
|
*/
|
|
291
|
-
messageAdded(message:
|
|
291
|
+
messageAdded(message: IMessageContent): void;
|
|
292
292
|
/**
|
|
293
293
|
* Function called when messages are inserted.
|
|
294
294
|
*
|
|
295
295
|
* @param index - the index of the first message of the list.
|
|
296
296
|
* @param messages - the messages list.
|
|
297
297
|
*/
|
|
298
|
-
messagesInserted(index: number, messages:
|
|
298
|
+
messagesInserted(index: number, messages: IMessageContent[]): void;
|
|
299
299
|
/**
|
|
300
300
|
* Function called when messages are deleted.
|
|
301
301
|
*
|
|
@@ -435,9 +435,9 @@ export interface IChatContext {
|
|
|
435
435
|
*/
|
|
436
436
|
readonly name: string;
|
|
437
437
|
/**
|
|
438
|
-
* A copy of the messages.
|
|
438
|
+
* A copy of the messages content.
|
|
439
439
|
*/
|
|
440
|
-
readonly messages:
|
|
440
|
+
readonly messages: IMessageContent[];
|
|
441
441
|
/**
|
|
442
442
|
* A list of all users who have connected to this chat.
|
|
443
443
|
*/
|
|
@@ -456,7 +456,7 @@ export declare abstract class AbstractChatContext implements IChatContext {
|
|
|
456
456
|
model: IChatModel;
|
|
457
457
|
});
|
|
458
458
|
get name(): string;
|
|
459
|
-
get messages():
|
|
459
|
+
get messages(): IMessageContent[];
|
|
460
460
|
get user(): IUser | undefined;
|
|
461
461
|
/**
|
|
462
462
|
* ABSTRACT: Should return a list of users who have connected to this chat.
|
package/lib/model.js
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import { ArrayExt } from '@lumino/algorithm';
|
|
6
|
+
import { PromiseDelegate } from '@lumino/coreutils';
|
|
6
7
|
import { Signal } from '@lumino/signaling';
|
|
7
8
|
import { InputModel } from './input-model';
|
|
9
|
+
import { Message } from './message';
|
|
8
10
|
import { replaceMentionToSpan } from './utils';
|
|
9
|
-
import { PromiseDelegate } from '@lumino/coreutils';
|
|
10
11
|
/**
|
|
11
12
|
* An abstract implementation of IChatModel.
|
|
12
13
|
*
|
|
@@ -170,12 +171,12 @@ export class AbstractChatModel {
|
|
|
170
171
|
if (this._config.stackMessages) {
|
|
171
172
|
this._messages.slice(1).forEach((message, idx) => {
|
|
172
173
|
const previousUser = this._messages[idx].sender.username;
|
|
173
|
-
message.stacked
|
|
174
|
+
message.update({ stacked: previousUser === message.sender.username });
|
|
174
175
|
});
|
|
175
176
|
}
|
|
176
177
|
else {
|
|
177
178
|
this._messages.forEach(message => {
|
|
178
|
-
|
|
179
|
+
message.update({ stacked: undefined });
|
|
179
180
|
});
|
|
180
181
|
}
|
|
181
182
|
this._messagesUpdated.emit();
|
|
@@ -225,7 +226,7 @@ export class AbstractChatModel {
|
|
|
225
226
|
this._viewportChanged.emit(values);
|
|
226
227
|
}
|
|
227
228
|
/**
|
|
228
|
-
* A signal emitting when the
|
|
229
|
+
* A signal emitting when the message list is updated.
|
|
229
230
|
*/
|
|
230
231
|
get messagesUpdated() {
|
|
231
232
|
return this._messagesUpdated;
|
|
@@ -328,7 +329,8 @@ export class AbstractChatModel {
|
|
|
328
329
|
const lastRead = (_a = this.lastRead) !== null && _a !== void 0 ? _a : 0;
|
|
329
330
|
// Format the messages.
|
|
330
331
|
messages.forEach((message, idx) => {
|
|
331
|
-
|
|
332
|
+
const formattedMessage = this.formatChatMessage(message);
|
|
333
|
+
formattedMessages.push(new Message(formattedMessage));
|
|
332
334
|
if (message.time > lastRead) {
|
|
333
335
|
unreadIndexes.push(index + idx);
|
|
334
336
|
}
|
|
@@ -344,7 +346,7 @@ export class AbstractChatModel {
|
|
|
344
346
|
for (let idx = start; idx <= end; idx++) {
|
|
345
347
|
const message = this._messages[idx];
|
|
346
348
|
const previousUser = this._messages[idx - 1].sender.username;
|
|
347
|
-
message.stacked
|
|
349
|
+
message.update({ stacked: previousUser === message.sender.username });
|
|
348
350
|
}
|
|
349
351
|
}
|
|
350
352
|
this._addUnreadMessages(unreadIndexes);
|
|
@@ -461,7 +463,7 @@ export class AbstractChatContext {
|
|
|
461
463
|
return this._model.name;
|
|
462
464
|
}
|
|
463
465
|
get messages() {
|
|
464
|
-
return
|
|
466
|
+
return this._model.messages.map(message => ({ ...message.content }));
|
|
465
467
|
}
|
|
466
468
|
get user() {
|
|
467
469
|
var _a;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { Token } from '@lumino/coreutils';
|
|
3
3
|
import { IChatModel } from '../model';
|
|
4
|
-
import {
|
|
4
|
+
import { IMessageContent } from '../types';
|
|
5
5
|
/**
|
|
6
6
|
* The token providing the chat footer registry.
|
|
7
7
|
*/
|
|
@@ -26,7 +26,7 @@ export interface IMessageFooterRegistry {
|
|
|
26
26
|
*/
|
|
27
27
|
export type MessageFooterSectionProps = {
|
|
28
28
|
model: IChatModel;
|
|
29
|
-
message:
|
|
29
|
+
message: IMessageContent;
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
32
32
|
* A message footer section which can be added to the footer registry.
|
package/lib/theme-provider.d.ts
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
import '@mui/material/Button';
|
|
2
|
+
import '@mui/material/IconButton';
|
|
1
3
|
import { Theme } from '@mui/material/styles';
|
|
4
|
+
/**
|
|
5
|
+
* Allow a new variant type, for the input toolbar.
|
|
6
|
+
*/
|
|
7
|
+
declare module '@mui/material/Button' {
|
|
8
|
+
interface ButtonPropsVariantOverrides {
|
|
9
|
+
'input-toolbar': true;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Allow a new variant property in IconButton, to be able to set the same properties
|
|
14
|
+
* as the input toolbar buttons.
|
|
15
|
+
*/
|
|
16
|
+
declare module '@mui/material/IconButton' {
|
|
17
|
+
interface IconButtonOwnProps {
|
|
18
|
+
variant?: 'input-toolbar';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
2
21
|
export declare function pollUntilReady(): Promise<void>;
|
|
3
22
|
export declare function getJupyterLabTheme(): Promise<Theme>;
|
package/lib/theme-provider.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Copyright (c) Jupyter Development Team.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
+
import '@mui/material/Button';
|
|
6
|
+
import '@mui/material/IconButton';
|
|
5
7
|
import { createTheme } from '@mui/material/styles';
|
|
6
8
|
function getCSSVariable(name) {
|
|
7
9
|
return getComputedStyle(document.body).getPropertyValue(name).trim();
|
|
@@ -19,8 +21,41 @@ export async function getJupyterLabTheme() {
|
|
|
19
21
|
components: {
|
|
20
22
|
MuiButton: {
|
|
21
23
|
defaultProps: {
|
|
22
|
-
size: 'small'
|
|
23
|
-
|
|
24
|
+
size: 'small',
|
|
25
|
+
variant: 'contained'
|
|
26
|
+
},
|
|
27
|
+
styleOverrides: {
|
|
28
|
+
root: {
|
|
29
|
+
minWidth: '24px',
|
|
30
|
+
width: '24px',
|
|
31
|
+
height: '24px',
|
|
32
|
+
lineHeight: 0,
|
|
33
|
+
'&:disabled': {
|
|
34
|
+
opacity: 0.5
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
variants: [
|
|
39
|
+
{
|
|
40
|
+
// The default style for input toolbar button variant.
|
|
41
|
+
props: { variant: 'input-toolbar' },
|
|
42
|
+
style: {
|
|
43
|
+
backgroundColor: 'var(--jp-brand-color1)',
|
|
44
|
+
color: 'white',
|
|
45
|
+
borderRadius: '4px',
|
|
46
|
+
boxShadow: 'none',
|
|
47
|
+
'&:hover': {
|
|
48
|
+
backgroundColor: 'var(--jp-brand-color0)',
|
|
49
|
+
boxShadow: 'none'
|
|
50
|
+
},
|
|
51
|
+
'&:disabled': {
|
|
52
|
+
backgroundColor: 'var(--jp-border-color2)',
|
|
53
|
+
color: 'var(--jp-ui-font-color3)',
|
|
54
|
+
opacity: 0.5
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
]
|
|
24
59
|
},
|
|
25
60
|
MuiFilledInput: {
|
|
26
61
|
defaultProps: {
|
|
@@ -41,7 +76,43 @@ export async function getJupyterLabTheme() {
|
|
|
41
76
|
MuiIconButton: {
|
|
42
77
|
defaultProps: {
|
|
43
78
|
size: 'small'
|
|
44
|
-
}
|
|
79
|
+
},
|
|
80
|
+
styleOverrides: {
|
|
81
|
+
root: {
|
|
82
|
+
minWidth: '24px',
|
|
83
|
+
width: '24px',
|
|
84
|
+
height: '24px',
|
|
85
|
+
lineHeight: 0,
|
|
86
|
+
'&:disabled': {
|
|
87
|
+
opacity: 0.5
|
|
88
|
+
},
|
|
89
|
+
// Set the default size of the svg icon if not set by user.
|
|
90
|
+
'& .MuiSvgIcon-root:not([fontSize])': {
|
|
91
|
+
fontSize: 'medium'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
variants: [
|
|
96
|
+
{
|
|
97
|
+
// The default style for input toolbar button variant.
|
|
98
|
+
props: { variant: 'input-toolbar' },
|
|
99
|
+
style: {
|
|
100
|
+
backgroundColor: 'var(--jp-brand-color1)',
|
|
101
|
+
color: 'white',
|
|
102
|
+
borderRadius: '4px',
|
|
103
|
+
boxShadow: 'none',
|
|
104
|
+
'&:hover': {
|
|
105
|
+
backgroundColor: 'var(--jp-brand-color0)',
|
|
106
|
+
boxShadow: 'none'
|
|
107
|
+
},
|
|
108
|
+
'&:disabled': {
|
|
109
|
+
backgroundColor: 'var(--jp-border-color2)',
|
|
110
|
+
color: 'var(--jp-ui-font-color3)',
|
|
111
|
+
opacity: 0.5
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
]
|
|
45
116
|
},
|
|
46
117
|
MuiInputBase: {
|
|
47
118
|
defaultProps: {
|
package/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ISignal } from '@lumino/signaling';
|
|
1
2
|
/**
|
|
2
3
|
* The user description.
|
|
3
4
|
*/
|
|
@@ -54,8 +55,8 @@ export interface IConfig {
|
|
|
54
55
|
/**
|
|
55
56
|
* The chat message description.
|
|
56
57
|
*/
|
|
57
|
-
export
|
|
58
|
-
type:
|
|
58
|
+
export type IMessageContent<T = IUser, U = IAttachment> = {
|
|
59
|
+
type: string;
|
|
59
60
|
body: string;
|
|
60
61
|
id: string;
|
|
61
62
|
time: number;
|
|
@@ -66,12 +67,29 @@ export interface IChatMessage<T = IUser, U = IAttachment> {
|
|
|
66
67
|
deleted?: boolean;
|
|
67
68
|
edited?: boolean;
|
|
68
69
|
stacked?: boolean;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
*
|
|
73
|
+
*/
|
|
74
|
+
export interface IMessage extends IMessageContent {
|
|
75
|
+
/**
|
|
76
|
+
* Update one or several fields of the message.
|
|
77
|
+
*/
|
|
78
|
+
update(updated: Partial<IMessageContent>): void;
|
|
79
|
+
/**
|
|
80
|
+
* The message content.
|
|
81
|
+
*/
|
|
82
|
+
content: IMessageContent;
|
|
83
|
+
/**
|
|
84
|
+
* A signal emitting when the message has been updated.
|
|
85
|
+
*/
|
|
86
|
+
changed: ISignal<IMessage, void>;
|
|
69
87
|
}
|
|
70
88
|
/**
|
|
71
89
|
* The chat history interface.
|
|
72
90
|
*/
|
|
73
91
|
export interface IChatHistory {
|
|
74
|
-
messages:
|
|
92
|
+
messages: IMessageContent[];
|
|
75
93
|
}
|
|
76
94
|
/**
|
|
77
95
|
* The content of a new message.
|
|
@@ -55,6 +55,10 @@ export declare class ChatWidget extends ReactWidget {
|
|
|
55
55
|
* Process dropped cells
|
|
56
56
|
*/
|
|
57
57
|
private _processCellDrop;
|
|
58
|
+
/**
|
|
59
|
+
* Process dropped tabBar files
|
|
60
|
+
*/
|
|
61
|
+
private _processTabDrop;
|
|
58
62
|
/**
|
|
59
63
|
* Find the notebook path for a cell by searching through active and open notebooks
|
|
60
64
|
*/
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import { ReactWidget } from '@jupyterlab/apputils';
|
|
6
|
+
import { DocumentWidget } from '@jupyterlab/docregistry';
|
|
6
7
|
import { isCode, isMarkdown, isRaw } from '@jupyterlab/nbformat';
|
|
7
8
|
import React from 'react';
|
|
8
9
|
import { Drag } from '@lumino/dragdrop';
|
|
@@ -12,6 +13,8 @@ import { chatIcon } from '../icons';
|
|
|
12
13
|
const FILE_BROWSER_MIME = 'application/x-jupyter-icontentsrich';
|
|
13
14
|
// MIME type constant for Notebook cell drag events
|
|
14
15
|
const NOTEBOOK_CELL_MIME = 'application/vnd.jupyter.cells';
|
|
16
|
+
// MIME type constant for TabBar file drag events
|
|
17
|
+
const TABBAR_FILE_MIME = 'application/vnd.lumino.widget-factory';
|
|
15
18
|
// CSS class constants
|
|
16
19
|
const INPUT_CONTAINER_CLASS = 'jp-chat-input-container';
|
|
17
20
|
const DRAG_HOVER_CLASS = 'jp-chat-drag-hover';
|
|
@@ -146,7 +149,9 @@ export class ChatWidget extends ReactWidget {
|
|
|
146
149
|
*/
|
|
147
150
|
_canHandleDrop(event) {
|
|
148
151
|
const types = event.mimeData.types();
|
|
149
|
-
return (types.includes(NOTEBOOK_CELL_MIME) ||
|
|
152
|
+
return (types.includes(NOTEBOOK_CELL_MIME) ||
|
|
153
|
+
types.includes(FILE_BROWSER_MIME) ||
|
|
154
|
+
types.includes(TABBAR_FILE_MIME));
|
|
150
155
|
}
|
|
151
156
|
/**
|
|
152
157
|
* Handle drop events
|
|
@@ -155,21 +160,27 @@ export class ChatWidget extends ReactWidget {
|
|
|
155
160
|
if (!this._canHandleDrop(event)) {
|
|
156
161
|
return;
|
|
157
162
|
}
|
|
158
|
-
event.preventDefault();
|
|
159
|
-
event.stopPropagation();
|
|
160
163
|
event.dropAction = 'move';
|
|
161
164
|
this._removeDragHoverClass();
|
|
165
|
+
let attached = false;
|
|
162
166
|
try {
|
|
163
167
|
if (event.mimeData.hasData(NOTEBOOK_CELL_MIME)) {
|
|
164
|
-
this._processCellDrop(event);
|
|
168
|
+
attached = this._processCellDrop(event);
|
|
165
169
|
}
|
|
166
170
|
else if (event.mimeData.hasData(FILE_BROWSER_MIME)) {
|
|
167
|
-
this._processFileDrop(event);
|
|
171
|
+
attached = this._processFileDrop(event);
|
|
172
|
+
}
|
|
173
|
+
else if (event.mimeData.hasData(TABBAR_FILE_MIME)) {
|
|
174
|
+
attached = this._processTabDrop(event);
|
|
168
175
|
}
|
|
169
176
|
}
|
|
170
177
|
catch (error) {
|
|
171
178
|
console.error('Error processing drop:', error);
|
|
172
179
|
}
|
|
180
|
+
if (attached) {
|
|
181
|
+
event.preventDefault();
|
|
182
|
+
event.stopPropagation();
|
|
183
|
+
}
|
|
173
184
|
}
|
|
174
185
|
/**
|
|
175
186
|
* Get the input model associated with the event target and input ids.
|
|
@@ -197,7 +208,7 @@ export class ChatWidget extends ReactWidget {
|
|
|
197
208
|
const data = event.mimeData.getData(FILE_BROWSER_MIME);
|
|
198
209
|
if (!((_a = data === null || data === void 0 ? void 0 : data.model) === null || _a === void 0 ? void 0 : _a.path)) {
|
|
199
210
|
console.warn('Invalid file browser data in drop event');
|
|
200
|
-
return;
|
|
211
|
+
return false;
|
|
201
212
|
}
|
|
202
213
|
const attachment = {
|
|
203
214
|
type: 'file',
|
|
@@ -206,6 +217,7 @@ export class ChatWidget extends ReactWidget {
|
|
|
206
217
|
};
|
|
207
218
|
const inputModel = this._getInputFromEvent(event);
|
|
208
219
|
(_b = inputModel === null || inputModel === void 0 ? void 0 : inputModel.addAttachment) === null || _b === void 0 ? void 0 : _b.call(inputModel, attachment);
|
|
220
|
+
return !!inputModel;
|
|
209
221
|
}
|
|
210
222
|
/**
|
|
211
223
|
* Process dropped cells
|
|
@@ -219,12 +231,12 @@ export class ChatWidget extends ReactWidget {
|
|
|
219
231
|
// Get path from first cell as all cells come from same notebook as users can only select or drag cells from one notebook at a time
|
|
220
232
|
if (!((_a = cells[0]) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
221
233
|
console.warn('No valid cells to process');
|
|
222
|
-
return;
|
|
234
|
+
return false;
|
|
223
235
|
}
|
|
224
236
|
const notebookPath = this._findNotebookPath(String(cells[0].id));
|
|
225
237
|
if (!notebookPath) {
|
|
226
238
|
console.warn(`Cannot find notebook for dragged cells from ${cells[0].id}`);
|
|
227
|
-
return;
|
|
239
|
+
return false;
|
|
228
240
|
}
|
|
229
241
|
const validCells = [];
|
|
230
242
|
for (const cell of cells) {
|
|
@@ -262,11 +274,43 @@ export class ChatWidget extends ReactWidget {
|
|
|
262
274
|
};
|
|
263
275
|
const inputModel = this._getInputFromEvent(event);
|
|
264
276
|
(_b = inputModel === null || inputModel === void 0 ? void 0 : inputModel.addAttachment) === null || _b === void 0 ? void 0 : _b.call(inputModel, attachment);
|
|
277
|
+
return !!inputModel;
|
|
265
278
|
}
|
|
266
279
|
}
|
|
267
280
|
catch (error) {
|
|
268
281
|
console.error('Failed to process cell drop: ', error);
|
|
269
282
|
}
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Process dropped tabBar files
|
|
287
|
+
*/
|
|
288
|
+
_processTabDrop(event) {
|
|
289
|
+
var _a, _b;
|
|
290
|
+
const factory = event.mimeData.getData(TABBAR_FILE_MIME);
|
|
291
|
+
if (!factory) {
|
|
292
|
+
console.warn('No factory in drag event');
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
const widget = factory();
|
|
296
|
+
if (!widget || !(widget instanceof DocumentWidget)) {
|
|
297
|
+
console.warn('No file associated to the element');
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
const path = widget.context.path;
|
|
301
|
+
if (!path) {
|
|
302
|
+
console.warn('Widget has no path');
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
const mimetype = ((_a = widget.context.model) === null || _a === void 0 ? void 0 : _a.mimeType) || 'application/octet-stream';
|
|
306
|
+
const attachment = {
|
|
307
|
+
type: 'file',
|
|
308
|
+
value: path,
|
|
309
|
+
mimetype
|
|
310
|
+
};
|
|
311
|
+
const inputModel = this._getInputFromEvent(event);
|
|
312
|
+
(_b = inputModel === null || inputModel === void 0 ? void 0 : inputModel.addAttachment) === null || _b === void 0 ? void 0 : _b.call(inputModel, attachment);
|
|
313
|
+
return !!inputModel;
|
|
270
314
|
}
|
|
271
315
|
/**
|
|
272
316
|
* Find the notebook path for a cell by searching through active and open notebooks
|
|
@@ -354,7 +354,7 @@ function ChatSelect({ chatNamesChanged, handleChange }) {
|
|
|
354
354
|
chatNamesChanged.connect((_, chatNames) => {
|
|
355
355
|
setChatNames(chatNames);
|
|
356
356
|
});
|
|
357
|
-
return (React.createElement(HTMLSelect, { onChange: handleChange, value: "-" },
|
|
357
|
+
return (React.createElement(HTMLSelect, { key: Object.keys(chatNames).join(), onChange: handleChange, value: "-" },
|
|
358
358
|
React.createElement("option", { value: "-", disabled: true, hidden: true }, "Open a chat"),
|
|
359
359
|
Object.keys(chatNames).map(name => (React.createElement("option", { value: chatNames[name] }, name)))));
|
|
360
360
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupyter/chat",
|
|
3
|
-
"version": "0.19.0
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "A package that provides UI components that can be used to create a chat in a Jupyterlab extension.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"@jupyterlab/codeeditor": "^4.2.0",
|
|
52
52
|
"@jupyterlab/codemirror": "^4.2.0",
|
|
53
53
|
"@jupyterlab/docmanager": "^4.2.0",
|
|
54
|
+
"@jupyterlab/docregistry": "^4.2.0",
|
|
54
55
|
"@jupyterlab/filebrowser": "^4.2.0",
|
|
55
56
|
"@jupyterlab/fileeditor": "^4.2.0",
|
|
56
57
|
"@jupyterlab/notebook": "^4.2.0",
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
"@lumino/disposable": "^2.0.0",
|
|
63
64
|
"@lumino/polling": "^2.0.0",
|
|
64
65
|
"@lumino/signaling": "^2.0.0",
|
|
66
|
+
"@lumino/widgets": "^2.0.0",
|
|
65
67
|
"@mui/icons-material": "^7.3.2",
|
|
66
68
|
"@mui/material": "^7.3.2",
|
|
67
69
|
"clsx": "^2.1.0",
|