@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.
Files changed (65) hide show
  1. package/lib/__tests__/model.spec.js +2 -2
  2. package/lib/components/chat.js +29 -2
  3. package/lib/components/index.d.ts +1 -0
  4. package/lib/components/index.js +1 -0
  5. package/lib/components/input/buttons/attach-button.js +1 -1
  6. package/lib/components/input/buttons/cancel-button.js +1 -1
  7. package/lib/components/input/buttons/save-edit-button.js +1 -1
  8. package/lib/components/input/buttons/send-button.js +3 -1
  9. package/lib/components/input/buttons/stop-button.js +1 -1
  10. package/lib/components/input/chat-input.js +3 -30
  11. package/lib/components/input/index.d.ts +0 -1
  12. package/lib/components/input/index.js +0 -1
  13. package/lib/components/messages/footer.d.ts +2 -2
  14. package/lib/components/messages/header.d.ts +2 -2
  15. package/lib/components/messages/header.js +13 -6
  16. package/lib/components/messages/message.d.ts +2 -2
  17. package/lib/components/messages/message.js +16 -1
  18. package/lib/components/messages/messages.js +3 -2
  19. package/lib/components/messages/toolbar.js +6 -14
  20. package/lib/components/mui-extras/tooltipped-button.d.ts +5 -26
  21. package/lib/components/mui-extras/tooltipped-button.js +4 -33
  22. package/lib/components/mui-extras/tooltipped-icon-button.d.ts +12 -22
  23. package/lib/components/mui-extras/tooltipped-icon-button.js +10 -8
  24. package/lib/components/writing-indicator.d.ts +20 -0
  25. package/lib/components/{input/writing-indicator.js → writing-indicator.js} +3 -2
  26. package/lib/message.d.ts +41 -0
  27. package/lib/message.js +74 -0
  28. package/lib/model.d.ts +13 -13
  29. package/lib/model.js +9 -7
  30. package/lib/registers/footers.d.ts +2 -2
  31. package/lib/theme-provider.d.ts +19 -0
  32. package/lib/theme-provider.js +74 -3
  33. package/lib/types.d.ts +21 -3
  34. package/lib/widgets/chat-widget.d.ts +4 -0
  35. package/lib/widgets/chat-widget.js +52 -8
  36. package/lib/widgets/multichat-panel.js +1 -1
  37. package/package.json +3 -1
  38. package/src/__tests__/model.spec.ts +7 -7
  39. package/src/components/chat.tsx +35 -1
  40. package/src/components/index.ts +1 -0
  41. package/src/components/input/buttons/attach-button.tsx +1 -1
  42. package/src/components/input/buttons/cancel-button.tsx +1 -1
  43. package/src/components/input/buttons/save-edit-button.tsx +1 -1
  44. package/src/components/input/buttons/send-button.tsx +4 -1
  45. package/src/components/input/buttons/stop-button.tsx +1 -1
  46. package/src/components/input/chat-input.tsx +1 -34
  47. package/src/components/input/index.ts +0 -1
  48. package/src/components/messages/footer.tsx +2 -2
  49. package/src/components/messages/header.tsx +20 -8
  50. package/src/components/messages/message.tsx +23 -3
  51. package/src/components/messages/messages.tsx +9 -4
  52. package/src/components/messages/toolbar.tsx +14 -14
  53. package/src/components/mui-extras/tooltipped-button.tsx +9 -43
  54. package/src/components/mui-extras/tooltipped-icon-button.tsx +17 -38
  55. package/src/components/{input/writing-indicator.tsx → writing-indicator.tsx} +9 -4
  56. package/src/message.ts +83 -0
  57. package/src/model.ts +25 -22
  58. package/src/registers/footers.ts +2 -2
  59. package/src/theme-provider.ts +95 -3
  60. package/src/types.ts +23 -3
  61. package/src/widgets/chat-widget.tsx +61 -10
  62. package/src/widgets/multichat-panel.tsx +5 -1
  63. package/style/chat.css +10 -0
  64. package/style/input.css +4 -0
  65. package/lib/components/input/writing-indicator.d.ts +0 -15
@@ -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, INewMessage, IChatMessage, IConfig, IUser } from './types';
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: IChatMessage[];
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: IChatMessage): Promise<boolean | void> | boolean | void;
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: IChatMessage): void;
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: IChatMessage[]): void;
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(): IChatMessage[];
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 messages list is updated.
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: IChatMessage): IChatMessage;
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: IChatMessage): void;
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: IChatMessage[]): void;
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: IChatMessage[];
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(): IChatMessage[];
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 = previousUser === message.sender.username;
174
+ message.update({ stacked: previousUser === message.sender.username });
174
175
  });
175
176
  }
176
177
  else {
177
178
  this._messages.forEach(message => {
178
- delete message.stacked;
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 messages list is updated.
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
- formattedMessages.push(this.formatChatMessage(message));
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 = previousUser === message.sender.username;
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 [...this._model.messages];
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 { IChatMessage } from '../types';
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: IChatMessage;
29
+ message: IMessageContent;
30
30
  };
31
31
  /**
32
32
  * A message footer section which can be added to the footer registry.
@@ -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>;
@@ -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 interface IChatMessage<T = IUser, U = IAttachment> {
58
- type: 'msg';
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: IChatMessage[];
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) || types.includes(FILE_BROWSER_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-alpha.2",
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",