@jupyter/chat 0.18.2 → 0.19.0-alpha.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/components/attachments.js +47 -21
- package/lib/components/chat.d.ts +5 -0
- package/lib/components/chat.js +7 -6
- package/lib/components/code-blocks/code-toolbar.js +29 -10
- package/lib/components/code-blocks/copy-button.js +11 -3
- package/lib/components/index.d.ts +0 -1
- package/lib/components/index.js +0 -1
- package/lib/components/input/buttons/attach-button.js +7 -2
- package/lib/components/input/buttons/cancel-button.js +12 -10
- package/lib/components/input/buttons/index.d.ts +2 -0
- package/lib/components/input/buttons/index.js +2 -0
- package/lib/components/input/buttons/save-edit-button.d.ts +6 -0
- package/lib/components/input/buttons/save-edit-button.js +51 -0
- package/lib/components/input/buttons/send-button.d.ts +1 -1
- package/lib/components/input/buttons/send-button.js +35 -122
- package/lib/components/input/buttons/stop-button.d.ts +6 -0
- package/lib/components/input/buttons/stop-button.js +63 -0
- package/lib/components/input/chat-input.d.ts +15 -0
- package/lib/components/input/chat-input.js +109 -46
- package/lib/components/input/index.d.ts +1 -0
- package/lib/components/input/index.js +1 -0
- package/lib/components/input/toolbar-registry.d.ts +10 -0
- package/lib/components/input/toolbar-registry.js +10 -1
- package/lib/components/input/use-chat-commands.js +9 -4
- package/lib/components/input/writing-indicator.d.ts +15 -0
- package/lib/components/input/writing-indicator.js +50 -0
- package/lib/components/messages/header.d.ts +4 -0
- package/lib/components/messages/header.js +4 -0
- package/lib/components/messages/index.d.ts +0 -1
- package/lib/components/messages/index.js +0 -1
- package/lib/components/messages/message.js +1 -1
- package/lib/components/messages/messages.d.ts +5 -0
- package/lib/components/messages/messages.js +24 -14
- package/lib/components/messages/toolbar.js +37 -15
- package/lib/input-model.d.ts +14 -0
- package/lib/input-model.js +12 -4
- package/lib/model.d.ts +8 -0
- package/lib/model.js +6 -0
- package/lib/types.d.ts +4 -0
- package/lib/widgets/chat-widget.d.ts +4 -0
- package/lib/widgets/chat-widget.js +36 -11
- package/lib/widgets/multichat-panel.js +2 -1
- package/package.json +1 -1
- package/src/components/attachments.tsx +70 -33
- package/src/components/chat.tsx +13 -4
- package/src/components/code-blocks/code-toolbar.tsx +56 -28
- package/src/components/code-blocks/copy-button.tsx +21 -12
- package/src/components/index.ts +0 -1
- package/src/components/input/buttons/attach-button.tsx +8 -2
- package/src/components/input/buttons/cancel-button.tsx +20 -15
- package/src/components/input/buttons/index.ts +2 -0
- package/src/components/input/buttons/save-edit-button.tsx +75 -0
- package/src/components/input/buttons/send-button.tsx +50 -167
- package/src/components/input/buttons/stop-button.tsx +88 -0
- package/src/components/input/chat-input.tsx +188 -83
- package/src/components/input/index.ts +1 -0
- package/src/components/input/toolbar-registry.tsx +25 -1
- package/src/components/input/use-chat-commands.tsx +25 -5
- package/src/components/input/writing-indicator.tsx +83 -0
- package/src/components/messages/header.tsx +8 -0
- package/src/components/messages/index.ts +0 -1
- package/src/components/messages/message.tsx +1 -0
- package/src/components/messages/messages.tsx +63 -39
- package/src/components/messages/toolbar.tsx +51 -21
- package/src/input-model.ts +21 -0
- package/src/model.ts +12 -0
- package/src/types.ts +5 -0
- package/src/widgets/chat-widget.tsx +43 -12
- package/src/widgets/multichat-panel.tsx +2 -1
- package/style/chat.css +13 -141
- package/style/input.css +0 -58
- package/lib/components/messages/writers.d.ts +0 -16
- package/lib/components/messages/writers.js +0 -39
- package/src/components/messages/writers.tsx +0 -81
|
@@ -14,12 +14,11 @@ import { ChatMessageHeader } from './header';
|
|
|
14
14
|
import { ChatMessage } from './message';
|
|
15
15
|
import { Navigation } from './navigation';
|
|
16
16
|
import { WelcomeMessage } from './welcome';
|
|
17
|
-
import { WritingUsersList } from './writers';
|
|
18
17
|
import { IInputToolbarRegistry } from '../input';
|
|
19
18
|
import { ScrollContainer } from '../scroll-container';
|
|
20
19
|
import { IChatCommandRegistry, IMessageFooterRegistry } from '../../registers';
|
|
21
20
|
import { IChatModel } from '../../model';
|
|
22
|
-
import {
|
|
21
|
+
import { ChatArea, IChatMessage } from '../../types';
|
|
23
22
|
|
|
24
23
|
export const MESSAGE_CLASS = 'jp-chat-message';
|
|
25
24
|
const MESSAGES_BOX_CLASS = 'jp-chat-messages-container';
|
|
@@ -53,6 +52,10 @@ export type BaseMessageProps = {
|
|
|
53
52
|
* The welcome message.
|
|
54
53
|
*/
|
|
55
54
|
welcomeMessage?: string;
|
|
55
|
+
/**
|
|
56
|
+
* The area where the chat is displayed.
|
|
57
|
+
*/
|
|
58
|
+
area?: ChatArea;
|
|
56
59
|
};
|
|
57
60
|
|
|
58
61
|
/**
|
|
@@ -62,7 +65,6 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
|
|
|
62
65
|
const { model } = props;
|
|
63
66
|
const [messages, setMessages] = useState<IChatMessage[]>(model.messages);
|
|
64
67
|
const refMsgBox = useRef<HTMLDivElement>(null);
|
|
65
|
-
const [currentWriters, setCurrentWriters] = useState<IUser[]>([]);
|
|
66
68
|
const [allRendered, setAllRendered] = useState<boolean>(false);
|
|
67
69
|
|
|
68
70
|
// The list of message DOM and their rendered promises.
|
|
@@ -84,7 +86,6 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
|
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
fetchHistory();
|
|
87
|
-
setCurrentWriters([]);
|
|
88
89
|
}, [model]);
|
|
89
90
|
|
|
90
91
|
/**
|
|
@@ -95,16 +96,10 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
|
|
|
95
96
|
setMessages([...model.messages]);
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
function handleWritersChange(_: IChatModel, writers: IChatModel.IWriter[]) {
|
|
99
|
-
setCurrentWriters(writers.map(writer => writer.user));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
99
|
model.messagesUpdated.connect(handleChatEvents);
|
|
103
|
-
model.writersChanged?.connect(handleWritersChange);
|
|
104
100
|
|
|
105
101
|
return function cleanup() {
|
|
106
102
|
model.messagesUpdated.disconnect(handleChatEvents);
|
|
107
|
-
model.writersChanged?.disconnect(handleChatEvents);
|
|
108
103
|
};
|
|
109
104
|
}, [model]);
|
|
110
105
|
|
|
@@ -170,6 +165,7 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
|
|
|
170
165
|
};
|
|
171
166
|
}, [messages, allRendered]);
|
|
172
167
|
|
|
168
|
+
const horizontalPadding = props.area === 'main' ? 8 : 4;
|
|
173
169
|
return (
|
|
174
170
|
<>
|
|
175
171
|
<ScrollContainer sx={{ flexGrow: 1 }}>
|
|
@@ -179,39 +175,67 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
|
|
|
179
175
|
content={props.welcomeMessage}
|
|
180
176
|
/>
|
|
181
177
|
)}
|
|
182
|
-
<Box
|
|
183
|
-
{
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
178
|
+
<Box
|
|
179
|
+
sx={{
|
|
180
|
+
paddingLeft: horizontalPadding,
|
|
181
|
+
paddingRight: horizontalPadding,
|
|
182
|
+
paddingTop: 4,
|
|
183
|
+
paddingBottom: 16,
|
|
184
|
+
display: 'flex',
|
|
185
|
+
flexDirection: 'column',
|
|
186
|
+
gap: 4
|
|
187
|
+
}}
|
|
188
|
+
ref={refMsgBox}
|
|
189
|
+
className={clsx(MESSAGES_BOX_CLASS)}
|
|
190
|
+
>
|
|
191
|
+
{messages
|
|
192
|
+
.filter(message => !message.deleted)
|
|
193
|
+
.map((message, i) => {
|
|
194
|
+
renderedPromise.current[i] = new PromiseDelegate();
|
|
195
|
+
const isCurrentUser =
|
|
196
|
+
model.user !== undefined &&
|
|
197
|
+
model.user.username === message.sender.username;
|
|
198
|
+
return (
|
|
199
|
+
// extra div needed to ensure each bubble is on a new line
|
|
200
|
+
<Box
|
|
201
|
+
key={i}
|
|
202
|
+
sx={{
|
|
203
|
+
...(isCurrentUser && {
|
|
204
|
+
marginLeft: props.area === 'main' ? '25%' : '10%',
|
|
205
|
+
backgroundColor: 'var(--jp-layout-color2)',
|
|
206
|
+
border: 'none',
|
|
207
|
+
borderRadius: 2,
|
|
208
|
+
padding: 2
|
|
209
|
+
})
|
|
210
|
+
}}
|
|
211
|
+
className={clsx(
|
|
212
|
+
MESSAGE_CLASS,
|
|
213
|
+
message.stacked ? MESSAGE_STACKED_CLASS : ''
|
|
214
|
+
)}
|
|
215
|
+
>
|
|
216
|
+
<ChatMessageHeader
|
|
217
|
+
message={message}
|
|
218
|
+
isCurrentUser={isCurrentUser}
|
|
219
|
+
/>
|
|
220
|
+
<ChatMessage
|
|
221
|
+
{...props}
|
|
205
222
|
message={message}
|
|
206
|
-
|
|
223
|
+
index={i}
|
|
224
|
+
renderedPromise={renderedPromise.current[i]}
|
|
225
|
+
ref={el => (listRef.current[i] = el)}
|
|
207
226
|
/>
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
227
|
+
{props.messageFooterRegistry && (
|
|
228
|
+
<MessageFooterComponent
|
|
229
|
+
registry={props.messageFooterRegistry}
|
|
230
|
+
message={message}
|
|
231
|
+
model={model}
|
|
232
|
+
/>
|
|
233
|
+
)}
|
|
234
|
+
</Box>
|
|
235
|
+
);
|
|
236
|
+
})}
|
|
212
237
|
</Box>
|
|
213
238
|
</ScrollContainer>
|
|
214
|
-
<WritingUsersList writers={currentWriters}></WritingUsersList>
|
|
215
239
|
<Navigation {...props} refMsgBox={refMsgBox} allRendered={allRendered} />
|
|
216
240
|
</>
|
|
217
241
|
);
|
|
@@ -3,11 +3,9 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
editIcon
|
|
10
|
-
} from '@jupyterlab/ui-components';
|
|
6
|
+
// import EditIcon from '@mui/icons-material/Edit';
|
|
7
|
+
import DeleteIcon from '@mui/icons-material/Delete';
|
|
8
|
+
import { Box, IconButton, Tooltip } from '@mui/material';
|
|
11
9
|
import React from 'react';
|
|
12
10
|
|
|
13
11
|
const TOOLBAR_CLASS = 'jp-chat-toolbar';
|
|
@@ -18,27 +16,59 @@ const TOOLBAR_CLASS = 'jp-chat-toolbar';
|
|
|
18
16
|
export function MessageToolbar(props: MessageToolbar.IProps): JSX.Element {
|
|
19
17
|
const buttons: JSX.Element[] = [];
|
|
20
18
|
|
|
21
|
-
if (props.edit !== undefined) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
// if (props.edit !== undefined) {
|
|
20
|
+
// const editButton = (
|
|
21
|
+
// <Tooltip key="edit" title="Edit" placement="top" arrow>
|
|
22
|
+
// <span>
|
|
23
|
+
// <IconButton
|
|
24
|
+
// onClick={props.edit}
|
|
25
|
+
// aria-label="Edit"
|
|
26
|
+
// sx={{
|
|
27
|
+
// width: '24px',
|
|
28
|
+
// height: '24px',
|
|
29
|
+
// padding: 0,
|
|
30
|
+
// lineHeight: 0
|
|
31
|
+
// }}
|
|
32
|
+
// >
|
|
33
|
+
// <EditIcon sx={{ fontSize: '16px' }} />
|
|
34
|
+
// </IconButton>
|
|
35
|
+
// </span>
|
|
36
|
+
// </Tooltip>
|
|
37
|
+
// );
|
|
38
|
+
// buttons.push(editButton);
|
|
39
|
+
// }
|
|
29
40
|
if (props.delete !== undefined) {
|
|
30
|
-
const deleteButton =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
const deleteButton = (
|
|
42
|
+
<Tooltip key="delete" title="Delete" placement="top" arrow>
|
|
43
|
+
<span>
|
|
44
|
+
<IconButton
|
|
45
|
+
onClick={props.delete}
|
|
46
|
+
aria-label="Delete"
|
|
47
|
+
sx={{
|
|
48
|
+
width: '24px',
|
|
49
|
+
height: '24px',
|
|
50
|
+
padding: 0,
|
|
51
|
+
lineHeight: 0
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
<DeleteIcon sx={{ fontSize: '16px' }} />
|
|
55
|
+
</IconButton>
|
|
56
|
+
</span>
|
|
57
|
+
</Tooltip>
|
|
58
|
+
);
|
|
35
59
|
buttons.push(deleteButton);
|
|
36
60
|
}
|
|
37
61
|
|
|
38
62
|
return (
|
|
39
|
-
<
|
|
40
|
-
{
|
|
41
|
-
|
|
63
|
+
<Box
|
|
64
|
+
className={TOOLBAR_CLASS}
|
|
65
|
+
sx={{
|
|
66
|
+
display: 'flex',
|
|
67
|
+
gap: 2
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
{buttons}
|
|
71
|
+
</Box>
|
|
42
72
|
);
|
|
43
73
|
}
|
|
44
74
|
|
package/src/input-model.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
7
|
+
import { UUID } from '@lumino/coreutils';
|
|
7
8
|
import { IDisposable } from '@lumino/disposable';
|
|
8
9
|
import { ISignal, Signal } from '@lumino/signaling';
|
|
9
10
|
import { IActiveCellManager } from './active-cell-manager';
|
|
@@ -116,6 +117,11 @@ export interface IInputModel extends IDisposable {
|
|
|
116
117
|
*/
|
|
117
118
|
clearAttachments(): void;
|
|
118
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Unique identifier for the input (needed for drag-and-drop).
|
|
122
|
+
*/
|
|
123
|
+
readonly id: string;
|
|
124
|
+
|
|
119
125
|
/**
|
|
120
126
|
* A signal emitting when the attachment list has changed.
|
|
121
127
|
*/
|
|
@@ -157,6 +163,7 @@ export interface IInputModel extends IDisposable {
|
|
|
157
163
|
*/
|
|
158
164
|
export class InputModel implements IInputModel {
|
|
159
165
|
constructor(options: InputModel.IOptions) {
|
|
166
|
+
this._id = options.id ?? `input-${UUID.uuid4()}`;
|
|
160
167
|
this._onSend = options.onSend;
|
|
161
168
|
this._chatContext = options.chatContext;
|
|
162
169
|
this._value = options.value || '';
|
|
@@ -196,6 +203,13 @@ export class InputModel implements IInputModel {
|
|
|
196
203
|
*/
|
|
197
204
|
cancel: (() => void) | undefined;
|
|
198
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Unique identifier for the input (needed for drag-and-drop).
|
|
208
|
+
*/
|
|
209
|
+
get id(): string {
|
|
210
|
+
return this._id;
|
|
211
|
+
}
|
|
212
|
+
|
|
199
213
|
/**
|
|
200
214
|
* The entire input value.
|
|
201
215
|
*/
|
|
@@ -471,6 +485,7 @@ export class InputModel implements IInputModel {
|
|
|
471
485
|
return this._isDisposed;
|
|
472
486
|
}
|
|
473
487
|
|
|
488
|
+
private _id: string;
|
|
474
489
|
private _onSend: (input: string, model?: InputModel) => void;
|
|
475
490
|
private _chatContext?: IChatContext;
|
|
476
491
|
private _value: string;
|
|
@@ -532,6 +547,12 @@ export namespace InputModel {
|
|
|
532
547
|
*/
|
|
533
548
|
cursorIndex?: number;
|
|
534
549
|
|
|
550
|
+
/**
|
|
551
|
+
* Optional unique identifier for this input model.
|
|
552
|
+
* If not provided, one will be generated automatically.
|
|
553
|
+
*/
|
|
554
|
+
id?: string;
|
|
555
|
+
|
|
535
556
|
/**
|
|
536
557
|
* The configuration for the input component.
|
|
537
558
|
*/
|
package/src/model.ts
CHANGED
|
@@ -201,6 +201,11 @@ export interface IChatModel extends IDisposable {
|
|
|
201
201
|
*/
|
|
202
202
|
getEditionModel(messageID: string): IInputModel | undefined;
|
|
203
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Get the input models of all edited messages.
|
|
206
|
+
*/
|
|
207
|
+
getEditionModels(): IInputModel[];
|
|
208
|
+
|
|
204
209
|
/**
|
|
205
210
|
* Add an input model of the edited message.
|
|
206
211
|
*/
|
|
@@ -637,6 +642,13 @@ export abstract class AbstractChatModel implements IChatModel {
|
|
|
637
642
|
return this._messageEditions.get(messageID);
|
|
638
643
|
}
|
|
639
644
|
|
|
645
|
+
/**
|
|
646
|
+
* Get the input models of all edited messages.
|
|
647
|
+
*/
|
|
648
|
+
getEditionModels(): IInputModel[] {
|
|
649
|
+
return Array.from(this._messageEditions.values());
|
|
650
|
+
}
|
|
651
|
+
|
|
640
652
|
/**
|
|
641
653
|
* Add an input model of the edited message.
|
|
642
654
|
*/
|
package/src/types.ts
CHANGED
|
@@ -172,3 +172,8 @@ export interface IAttachmentSelection {
|
|
|
172
172
|
* An empty interface to describe optional settings that could be fetched from server.
|
|
173
173
|
*/
|
|
174
174
|
export interface ISettings {} /* eslint-disable-line @typescript-eslint/no-empty-object-type */
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The area where the chat is displayed.
|
|
178
|
+
*/
|
|
179
|
+
export type ChatArea = 'sidebar' | 'main';
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
INotebookAttachmentCell
|
|
21
21
|
} from '../types';
|
|
22
22
|
import { ActiveCellManager } from '../active-cell-manager';
|
|
23
|
+
import { IInputModel } from '../input-model';
|
|
23
24
|
|
|
24
25
|
// MIME type constant for file browser drag events
|
|
25
26
|
const FILE_BROWSER_MIME = 'application/x-jupyter-icontentsrich';
|
|
@@ -141,12 +142,19 @@ export class ChatWidget extends ReactWidget {
|
|
|
141
142
|
* Handle drag over events
|
|
142
143
|
*/
|
|
143
144
|
private _handleDrag(event: Drag.Event): void {
|
|
144
|
-
const
|
|
145
|
+
const inputContainers = this.node.querySelectorAll<HTMLElement>(
|
|
146
|
+
`.${INPUT_CONTAINER_CLASS}`
|
|
147
|
+
);
|
|
145
148
|
const target = event.target as HTMLElement;
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
let overInput: HTMLElement | null = null;
|
|
150
|
+
for (const container of inputContainers) {
|
|
151
|
+
if (container.contains(target)) {
|
|
152
|
+
overInput = container;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
148
156
|
|
|
149
|
-
if (!
|
|
157
|
+
if (!overInput) {
|
|
150
158
|
this._removeDragHoverClass();
|
|
151
159
|
return;
|
|
152
160
|
}
|
|
@@ -159,12 +167,9 @@ export class ChatWidget extends ReactWidget {
|
|
|
159
167
|
event.stopPropagation();
|
|
160
168
|
event.dropAction = 'move';
|
|
161
169
|
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
) {
|
|
166
|
-
inputContainer.classList.add(DRAG_HOVER_CLASS);
|
|
167
|
-
this._dragTarget = inputContainer as HTMLElement;
|
|
170
|
+
if (!overInput.classList.contains(DRAG_HOVER_CLASS)) {
|
|
171
|
+
overInput.classList.add(DRAG_HOVER_CLASS);
|
|
172
|
+
this._dragTarget = overInput;
|
|
168
173
|
}
|
|
169
174
|
}
|
|
170
175
|
|
|
@@ -203,6 +208,30 @@ export class ChatWidget extends ReactWidget {
|
|
|
203
208
|
}
|
|
204
209
|
}
|
|
205
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Get the input model associated with the event target and input ids.
|
|
213
|
+
*/
|
|
214
|
+
private _getInputFromEvent(event: Drag.Event): IInputModel | undefined {
|
|
215
|
+
let element = event.target as HTMLElement | null;
|
|
216
|
+
|
|
217
|
+
while (element) {
|
|
218
|
+
if (
|
|
219
|
+
element.classList.contains(INPUT_CONTAINER_CLASS) &&
|
|
220
|
+
element.dataset.inputId
|
|
221
|
+
) {
|
|
222
|
+
const inputId = element.dataset.inputId;
|
|
223
|
+
const inputModel =
|
|
224
|
+
this.model.input.id === inputId
|
|
225
|
+
? this.model.input
|
|
226
|
+
: this.model.getEditionModels().find(model => model.id === inputId);
|
|
227
|
+
return inputModel;
|
|
228
|
+
}
|
|
229
|
+
element = element.parentElement;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
206
235
|
/**
|
|
207
236
|
* Process dropped files
|
|
208
237
|
*/
|
|
@@ -221,7 +250,8 @@ export class ChatWidget extends ReactWidget {
|
|
|
221
250
|
value: data.model.path,
|
|
222
251
|
mimetype: data.model.mimetype
|
|
223
252
|
};
|
|
224
|
-
this.
|
|
253
|
+
const inputModel = this._getInputFromEvent(event);
|
|
254
|
+
inputModel?.addAttachment?.(attachment);
|
|
225
255
|
}
|
|
226
256
|
|
|
227
257
|
/**
|
|
@@ -283,7 +313,8 @@ export class ChatWidget extends ReactWidget {
|
|
|
283
313
|
value: notebookPath,
|
|
284
314
|
cells: validCells
|
|
285
315
|
};
|
|
286
|
-
this.
|
|
316
|
+
const inputModel = this._getInputFromEvent(event);
|
|
317
|
+
inputModel?.addAttachment?.(attachment);
|
|
287
318
|
}
|
|
288
319
|
} catch (error) {
|
|
289
320
|
console.error('Failed to process cell drop: ', error);
|
|
@@ -155,7 +155,8 @@ export class MultiChatPanel extends SidePanel {
|
|
|
155
155
|
attachmentOpenerRegistry: this._attachmentOpenerRegistry,
|
|
156
156
|
inputToolbarRegistry,
|
|
157
157
|
messageFooterRegistry: this._messageFooterRegistry,
|
|
158
|
-
welcomeMessage: this._welcomeMessage
|
|
158
|
+
welcomeMessage: this._welcomeMessage,
|
|
159
|
+
area: 'sidebar'
|
|
159
160
|
});
|
|
160
161
|
|
|
161
162
|
const section = new ChatSection({
|
package/style/chat.css
CHANGED
|
@@ -2,20 +2,18 @@
|
|
|
2
2
|
* Copyright (c) Jupyter Development Team.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
.jp-chat-message:not(.jp-chat-message-stacked) {
|
|
6
|
-
padding: 1em 1em 0;
|
|
7
|
-
}
|
|
8
5
|
|
|
9
|
-
.jp-chat-
|
|
10
|
-
|
|
6
|
+
.jp-chat-rendered-markdown {
|
|
7
|
+
position: relative;
|
|
11
8
|
}
|
|
12
9
|
|
|
13
|
-
.jp-chat-
|
|
14
|
-
|
|
10
|
+
.jp-chat-rendered-markdown hr {
|
|
11
|
+
color: #00000026;
|
|
12
|
+
background-color: transparent;
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
.jp-chat-rendered-markdown {
|
|
18
|
-
|
|
15
|
+
.jp-chat-rendered-markdown .jp-RenderedHTMLCommon > :last-child {
|
|
16
|
+
margin-bottom: 0;
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
/*
|
|
@@ -38,7 +36,7 @@
|
|
|
38
36
|
overflow-x: auto;
|
|
39
37
|
white-space: pre;
|
|
40
38
|
margin: 0;
|
|
41
|
-
padding: 4px
|
|
39
|
+
padding: 4px 6px;
|
|
42
40
|
border: var(--jp-border-width) solid var(--jp-cell-editor-border-color);
|
|
43
41
|
}
|
|
44
42
|
|
|
@@ -53,7 +51,7 @@
|
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
.jp-chat-toolbar {
|
|
56
|
-
|
|
54
|
+
visibility: hidden;
|
|
57
55
|
position: absolute;
|
|
58
56
|
right: 2px;
|
|
59
57
|
top: 2px;
|
|
@@ -67,107 +65,13 @@
|
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
.jp-chat-rendered-markdown:hover .jp-chat-toolbar {
|
|
70
|
-
|
|
68
|
+
visibility: visible;
|
|
71
69
|
}
|
|
72
70
|
|
|
73
71
|
.jp-chat-toolbar > .jp-ToolbarButtonComponent {
|
|
74
72
|
margin-top: 0;
|
|
75
73
|
}
|
|
76
74
|
|
|
77
|
-
.jp-chat-writers {
|
|
78
|
-
display: flex;
|
|
79
|
-
flex-wrap: wrap;
|
|
80
|
-
position: sticky;
|
|
81
|
-
bottom: 0;
|
|
82
|
-
padding: 8px;
|
|
83
|
-
background-color: var(--jp-layout-color0);
|
|
84
|
-
border-top: 1px solid var(--jp-border-color2);
|
|
85
|
-
z-index: 1;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.jp-chat-writers-content {
|
|
89
|
-
display: flex;
|
|
90
|
-
align-items: center;
|
|
91
|
-
gap: 4px;
|
|
92
|
-
flex-wrap: wrap;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.jp-chat-writer-item {
|
|
96
|
-
display: flex;
|
|
97
|
-
align-items: center;
|
|
98
|
-
gap: 6px;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.jp-chat-writer-name {
|
|
102
|
-
color: var(--jp-ui-font-color1);
|
|
103
|
-
font-weight: 500;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.jp-chat-writer-separator {
|
|
107
|
-
color: var(--jp-ui-font-color2);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.jp-chat-writing-status {
|
|
111
|
-
display: flex;
|
|
112
|
-
align-items: center;
|
|
113
|
-
gap: 8px;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.jp-chat-writing-text {
|
|
117
|
-
color: var(--jp-ui-font-color2);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/* Animated typing indicator */
|
|
121
|
-
.jp-chat-typing-indicator {
|
|
122
|
-
display: flex;
|
|
123
|
-
align-items: center;
|
|
124
|
-
gap: 2px;
|
|
125
|
-
padding: 2px 4px;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.jp-chat-typing-dot {
|
|
129
|
-
width: 4px;
|
|
130
|
-
height: 4px;
|
|
131
|
-
border-radius: 50%;
|
|
132
|
-
background-color: var(--jp-brand-color1);
|
|
133
|
-
animation: jp-chat-typing-bounce 1.4s infinite ease-in-out;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.jp-chat-typing-dot:nth-child(1) {
|
|
137
|
-
animation-delay: -0.32s;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.jp-chat-typing-dot:nth-child(2) {
|
|
141
|
-
animation-delay: -0.16s;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
.jp-chat-typing-dot:nth-child(3) {
|
|
145
|
-
animation-delay: 0s;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/* Keyframe animations */
|
|
149
|
-
@keyframes jp-chat-typing-bounce {
|
|
150
|
-
0%,
|
|
151
|
-
80%,
|
|
152
|
-
100% {
|
|
153
|
-
transform: scale(0.8);
|
|
154
|
-
opacity: 0.5;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
40% {
|
|
158
|
-
transform: scale(1.2);
|
|
159
|
-
opacity: 1;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
.jp-chat-writers > div {
|
|
164
|
-
display: flex;
|
|
165
|
-
align-items: center;
|
|
166
|
-
gap: 0.2em;
|
|
167
|
-
white-space: pre;
|
|
168
|
-
padding-left: 0.5em;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
75
|
.jp-chat-navigation {
|
|
172
76
|
position: absolute;
|
|
173
77
|
right: 10px;
|
|
@@ -197,40 +101,8 @@
|
|
|
197
101
|
bottom: 120px;
|
|
198
102
|
}
|
|
199
103
|
|
|
200
|
-
.jp-chat-attachments {
|
|
201
|
-
display: flex;
|
|
202
|
-
gap: 4px;
|
|
203
|
-
flex-wrap: wrap;
|
|
204
|
-
min-height: 1.5em;
|
|
205
|
-
padding: 4px 0;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.jp-chat-attachment {
|
|
209
|
-
border: solid 1px;
|
|
210
|
-
border-radius: 10px;
|
|
211
|
-
margin: 0 0.2em;
|
|
212
|
-
padding: 0 0.3em;
|
|
213
|
-
align-content: center;
|
|
214
|
-
background-color: var(--jp-border-color3);
|
|
215
|
-
flex-shrink: 0;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.jp-chat-attachment .jp-chat-attachment-clickable:hover {
|
|
219
|
-
cursor: pointer;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.jp-chat-command-name {
|
|
223
|
-
font-weight: normal;
|
|
224
|
-
margin: 5px;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
.jp-chat-command-description {
|
|
228
|
-
color: gray;
|
|
229
|
-
margin: 5px;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
104
|
.jp-chat-mention {
|
|
233
|
-
border-radius:
|
|
234
|
-
padding:
|
|
235
|
-
|
|
105
|
+
border-radius: 4px;
|
|
106
|
+
padding: 2px 0;
|
|
107
|
+
font-weight: bold;
|
|
236
108
|
}
|