Skip to content

Commit 19b69c2

Browse files
authored
Use partial message content to send message (#455)
* Use partial message content to send message * Fix example package * Fix empty message with only attachments or mime model * Reduce the INewMessage attributes to keep only the necessary ones
1 parent dfbed2e commit 19b69c2

6 files changed

Lines changed: 78 additions & 30 deletions

File tree

docs/jupyter-chat-example/src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,12 @@ class MyChatModel extends AbstractChatModel {
5858
sendMessage(
5959
newMessage: INewMessage
6060
): Promise<boolean | void> | boolean | void {
61+
if (!newMessage.body) {
62+
return;
63+
}
6164
const message: IMessageContent = {
6265
body: newMessage.body,
63-
id: newMessage.id ?? UUID.uuid4(),
66+
id: UUID.uuid4(),
6467
type: 'msg',
6568
time: Date.now() / 1000,
6669
sender: { username: 'me', mention_name: 'me' },

packages/jupyter-chat/src/components/messages/message.tsx

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { MessageRenderer } from './message-renderer';
1010
import { AttachmentPreviewList } from '../attachments';
1111
import { ChatInput } from '../input';
1212
import { useChatContext } from '../../context';
13-
import { IInputModel, InputModel } from '../../input-model';
14-
import { IMessageContent, IMessage } from '../../types';
13+
import { InputModel } from '../../input-model';
14+
import { IMessageContent, IMessage, INewMessage } from '../../types';
1515
import { replaceSpanToMention } from '../../utils';
1616

1717
export const MESSAGE_CONTAINER_CLASS = 'jp-chat-message-container';
@@ -96,8 +96,8 @@ export function ChatMessageBase(props: ChatMessageProps): JSX.Element {
9696
});
9797
const inputModel = new InputModel({
9898
chatContext: model.createChatContext(),
99-
onSend: (input: string, model?: IInputModel) =>
100-
updateMessage(message.id, input, model),
99+
onSend: (newMessage: INewMessage) =>
100+
updateMessage(message.id, newMessage),
101101
onCancel: () => cancelEdition(),
102102
value: body,
103103
activeCellManager: model.activeCellManager,
@@ -121,17 +121,27 @@ export function ChatMessageBase(props: ChatMessageProps): JSX.Element {
121121

122122
// Update the content of the message.
123123
const updateMessage = useCallback(
124-
(id: string, input: string, inputModel?: IInputModel): void => {
125-
if (!canEdit || !inputModel) {
124+
(id: string, newMessage: INewMessage): void => {
125+
const inputModel = model.getEditionModel(id);
126+
if (!canEdit || !inputModel || !model.updateMessage) {
127+
setEdit(false);
126128
return;
127129
}
130+
128131
// Update the message
129132
const updatedMessage = { ...message };
130-
updatedMessage.body = input;
131-
updatedMessage.attachments = inputModel.attachments;
132-
updatedMessage.mentions = inputModel.mentions;
133-
model.updateMessage!(id, updatedMessage);
134-
model.getEditionModel(message.id)?.dispose();
133+
if (newMessage.body) {
134+
updatedMessage.body = newMessage.body;
135+
}
136+
if (newMessage.attachments) {
137+
updatedMessage.attachments = newMessage.attachments;
138+
}
139+
if (newMessage.mentions) {
140+
updatedMessage.mentions = newMessage.mentions;
141+
}
142+
143+
model.updateMessage(id, updatedMessage);
144+
inputModel.dispose();
135145
setEdit(false);
136146
},
137147
[model, message, canEdit]

packages/jupyter-chat/src/input-model.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { ISignal, Signal } from '@lumino/signaling';
1010
import { IActiveCellManager } from './active-cell-manager';
1111
import { ISelectionWatcher } from './selection-watcher';
1212
import { IChatContext } from './model';
13-
import { IAttachment, INotebookAttachment, IUser } from './types';
13+
import { IAttachment, INewMessage, INotebookAttachment, IUser } from './types';
1414

1515
/**
1616
* The chat input interface.
@@ -194,8 +194,27 @@ export class InputModel implements IInputModel {
194194
* Function to send a message.
195195
*/
196196
send = (input: string): void => {
197-
this._onSend(input, this);
197+
const message: INewMessage = {
198+
body: input
199+
};
200+
201+
// Add the attachments
202+
if (this.attachments.length) {
203+
message.attachments = [...this.attachments];
204+
}
205+
206+
// Add the mentions
207+
if (this.mentions.length) {
208+
message.mentions = [...this.mentions];
209+
}
210+
211+
// Send the message
212+
this._onSend(message);
213+
214+
// Clear the input
198215
this.value = '';
216+
this.clearAttachments();
217+
this.clearMentions();
199218
};
200219

201220
/**
@@ -486,7 +505,7 @@ export class InputModel implements IInputModel {
486505
}
487506

488507
private _id: string;
489-
private _onSend: (input: string, model?: InputModel) => void;
508+
private _onSend: (message: INewMessage) => void;
490509
private _chatContext?: IChatContext;
491510
private _value: string;
492511
private _cursorIndex: number | null = null;
@@ -519,7 +538,7 @@ export namespace InputModel {
519538
* @param content - the content of the message.
520539
* @param model - the model of the input sending the message.
521540
*/
522-
onSend: (content: string, model?: InputModel) => void;
541+
onSend: (message: INewMessage) => void;
523542

524543
/**
525544
* Function that should cancel the message edition.

packages/jupyter-chat/src/model.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ export abstract class AbstractChatModel implements IChatModel {
264264
config: {
265265
sendWithShiftEnter: config.sendWithShiftEnter
266266
},
267-
onSend: (input: string) => this.sendMessage({ body: input })
267+
onSend: this.sendMessage.bind(this)
268268
});
269269

270270
this._commands = options.commands;

packages/jupyter-chat/src/types.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,12 @@ export interface IChatHistory {
174174
/**
175175
* The content of a new message.
176176
*/
177-
export interface INewMessage {
178-
body: string;
179-
id?: string;
180-
}
177+
export type INewMessage<T = IUser, U = IAttachment> = Partial<
178+
Pick<
179+
IMessageContent<T, U>,
180+
'body' | 'attachments' | 'mentions' | 'metadata' | 'mime_model' | 'sender'
181+
>
182+
>;
181183

182184
/**
183185
* The attachment type. Jupyter Chat allows for two types of attachments

packages/jupyterlab-chat/src/model.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -204,40 +204,54 @@ export class LabChatModel
204204
}
205205

206206
sendMessage(message: INewMessage): Promise<boolean | void> | boolean | void {
207+
if (!message.body && !message.mime_model && !message.attachments?.length) {
208+
return false;
209+
}
207210
this._resetWritingStatus();
208211
if (this._timeoutWriting !== null) {
209212
window.clearTimeout(this._timeoutWriting);
210213
}
211214

215+
const body = message.body ?? '';
216+
const user = message.sender ?? this._user;
217+
212218
const msg: IYmessage = {
213219
type: 'msg',
214220
id: UUID.uuid4(),
215-
body: message.body,
221+
body,
216222
time: Date.now() / 1000,
217-
sender: this._user.username,
223+
sender: user.username,
218224
raw_time: true
219225
};
220226

221-
// Add the user if it does not exist or has changed
222-
if (!(this.sharedModel.getUser(this._user.username) === this._user)) {
223-
this.sharedModel.setUser(this._user);
227+
// Add the MIME model if provided.
228+
if (message.mime_model) {
229+
msg.mime_model = message.mime_model;
230+
}
231+
232+
// Add the user if it does not exist
233+
if (!this.sharedModel.getUser(user.username)) {
234+
this.sharedModel.setUser(user);
224235
}
225236

226237
// Add the attachments to the message.
227-
const attachmentIds = this.input.attachments?.map(attachment =>
238+
const attachmentIds = message.attachments?.map(attachment =>
228239
this.sharedModel.setAttachment(attachment)
229240
);
230241
if (attachmentIds?.length) {
231242
msg.attachments = attachmentIds;
232243
}
233-
this.input.clearAttachments();
234244

235245
// Add the mentioned users.
236-
const mentions = this._buildMentionList(this.input.mentions, message.body);
246+
const mentions = this._buildMentionList(message.mentions, body);
237247
if (mentions.length) {
238248
msg.mentions = mentions;
239249
}
240-
this.input.clearMentions();
250+
251+
// Add the metadata if provided.
252+
if (message.metadata) {
253+
msg.metadata = message.metadata;
254+
}
241255

242256
this.sharedModel.addMessage(msg);
243257
}

0 commit comments

Comments
 (0)