@jupyter/chat 0.8.0 → 0.9.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/chat-input.d.ts +3 -11
- package/lib/components/chat-input.js +26 -40
- package/lib/components/chat-messages.d.ts +17 -4
- package/lib/components/chat-messages.js +9 -9
- package/lib/components/chat.d.ts +5 -5
- package/lib/components/chat.js +9 -8
- package/lib/components/code-blocks/copy-button.js +6 -3
- package/lib/components/input/buttons/attach-button.d.ts +6 -0
- package/lib/components/input/{attach-button.js → buttons/attach-button.js} +11 -8
- package/lib/components/input/buttons/cancel-button.d.ts +6 -0
- package/lib/components/input/{cancel-button.js → buttons/cancel-button.js} +5 -7
- package/lib/components/input/buttons/index.d.ts +3 -0
- package/lib/components/input/buttons/index.js +7 -0
- package/lib/components/input/buttons/send-button.d.ts +6 -0
- package/lib/components/input/{send-button.js → buttons/send-button.js} +52 -42
- package/lib/components/input/index.d.ts +3 -3
- package/lib/components/input/index.js +3 -3
- package/lib/components/input/toolbar-registry.d.ts +98 -0
- package/lib/components/input/toolbar-registry.js +85 -0
- package/lib/components/input/use-chat-commands.js +3 -2
- package/lib/components/mui-extras/tooltipped-button.d.ts +1 -1
- package/lib/components/mui-extras/tooltipped-button.js +3 -2
- package/lib/components/mui-extras/tooltipped-icon-button.js +4 -2
- package/lib/input-model.d.ts +41 -0
- package/lib/input-model.js +17 -1
- package/lib/model.d.ts +22 -0
- package/lib/model.js +18 -2
- package/lib/types.d.ts +0 -18
- package/lib/widgets/chat-widget.d.ts +5 -1
- package/lib/widgets/chat-widget.js +7 -1
- package/package.json +1 -1
- package/src/components/chat-input.tsx +40 -65
- package/src/components/chat-messages.tsx +31 -14
- package/src/components/chat.tsx +12 -21
- package/src/components/code-blocks/copy-button.tsx +9 -3
- package/src/components/input/{attach-button.tsx → buttons/attach-button.tsx} +15 -20
- package/src/components/input/{cancel-button.tsx → buttons/cancel-button.tsx} +9 -16
- package/src/components/input/buttons/index.ts +8 -0
- package/src/components/input/{send-button.tsx → buttons/send-button.tsx} +62 -61
- package/src/components/input/index.ts +3 -3
- package/src/components/input/toolbar-registry.tsx +162 -0
- package/src/components/input/use-chat-commands.tsx +8 -2
- package/src/components/mui-extras/tooltipped-button.tsx +4 -2
- package/src/components/mui-extras/tooltipped-icon-button.tsx +5 -2
- package/src/input-model.ts +58 -1
- package/src/model.ts +36 -2
- package/src/types.ts +0 -21
- package/src/widgets/chat-widget.tsx +8 -1
- package/style/base.css +1 -0
- package/style/chat.css +10 -0
- package/style/input.css +32 -0
- package/lib/components/input/attach-button.d.ts +0 -14
- package/lib/components/input/cancel-button.d.ts +0 -11
- package/lib/components/input/send-button.d.ts +0 -18
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
7
6
|
import {
|
|
8
7
|
Autocomplete,
|
|
9
8
|
AutocompleteInputChangeReason,
|
|
@@ -17,16 +16,20 @@ import clsx from 'clsx';
|
|
|
17
16
|
import React, { useEffect, useRef, useState } from 'react';
|
|
18
17
|
|
|
19
18
|
import { AttachmentPreviewList } from './attachments';
|
|
20
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
IInputToolbarRegistry,
|
|
21
|
+
InputToolbarRegistry,
|
|
22
|
+
useChatCommands
|
|
23
|
+
} from './input';
|
|
21
24
|
import { IInputModel, InputModel } from '../input-model';
|
|
22
|
-
import { IAttachment
|
|
23
|
-
import { useChatCommands } from './input/use-chat-commands';
|
|
25
|
+
import { IAttachment } from '../types';
|
|
24
26
|
import { IChatCommandRegistry } from '../chat-commands';
|
|
25
27
|
|
|
26
28
|
const INPUT_BOX_CLASS = 'jp-chat-input-container';
|
|
29
|
+
const INPUT_TOOLBAR_CLASS = 'jp-chat-input-toolbar';
|
|
27
30
|
|
|
28
31
|
export function ChatInput(props: ChatInput.IProps): JSX.Element {
|
|
29
|
-
const {
|
|
32
|
+
const { model, toolbarRegistry } = props;
|
|
30
33
|
const [input, setInput] = useState<string>(model.value);
|
|
31
34
|
const inputRef = useRef<HTMLInputElement>();
|
|
32
35
|
|
|
@@ -38,14 +41,16 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
|
|
|
38
41
|
const [attachments, setAttachments] = useState<IAttachment[]>(
|
|
39
42
|
model.attachments
|
|
40
43
|
);
|
|
44
|
+
const [toolbarElements, setToolbarElements] = useState<
|
|
45
|
+
InputToolbarRegistry.IToolbarItem[]
|
|
46
|
+
>([]);
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Handle the changes on the model that affect the input.
|
|
50
|
+
* - focus requested
|
|
51
|
+
* - config changed
|
|
52
|
+
* - attachments changed
|
|
53
|
+
*/
|
|
49
54
|
useEffect(() => {
|
|
50
55
|
const inputChanged = (_: IInputModel, value: string) => {
|
|
51
56
|
setInput(value);
|
|
@@ -76,6 +81,22 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
|
|
|
76
81
|
};
|
|
77
82
|
}, [model]);
|
|
78
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Handle the changes in the toolbar items.
|
|
86
|
+
*/
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
const updateToolbar = () => {
|
|
89
|
+
setToolbarElements(toolbarRegistry.getItems());
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
toolbarRegistry.itemsChanged.connect(updateToolbar);
|
|
93
|
+
updateToolbar();
|
|
94
|
+
|
|
95
|
+
return () => {
|
|
96
|
+
toolbarRegistry.itemsChanged.disconnect(updateToolbar);
|
|
97
|
+
};
|
|
98
|
+
}, [toolbarRegistry]);
|
|
99
|
+
|
|
79
100
|
const inputExists = !!input.trim();
|
|
80
101
|
|
|
81
102
|
/**
|
|
@@ -136,38 +157,12 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
|
|
|
136
157
|
(sendWithShiftEnter && event.shiftKey) ||
|
|
137
158
|
(!sendWithShiftEnter && !event.shiftKey)
|
|
138
159
|
) {
|
|
139
|
-
|
|
160
|
+
model.send(input);
|
|
140
161
|
event.stopPropagation();
|
|
141
162
|
event.preventDefault();
|
|
142
163
|
}
|
|
143
164
|
}
|
|
144
165
|
|
|
145
|
-
/**
|
|
146
|
-
* Triggered when sending the message.
|
|
147
|
-
*
|
|
148
|
-
* Add code block if cell or text is selected.
|
|
149
|
-
*/
|
|
150
|
-
function onSend(selection?: Selection) {
|
|
151
|
-
let content = input;
|
|
152
|
-
if (selection) {
|
|
153
|
-
content += `
|
|
154
|
-
|
|
155
|
-
\`\`\`
|
|
156
|
-
${selection.source}
|
|
157
|
-
\`\`\`
|
|
158
|
-
`;
|
|
159
|
-
}
|
|
160
|
-
props.onSend(content);
|
|
161
|
-
model.value = '';
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Triggered when cancelling edition.
|
|
166
|
-
*/
|
|
167
|
-
function onCancel() {
|
|
168
|
-
props.onCancel?.();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
166
|
// Set the helper text based on whether Shift+Enter is used for sending.
|
|
172
167
|
const helperText = sendWithShiftEnter ? (
|
|
173
168
|
<span>
|
|
@@ -221,22 +216,10 @@ ${selection.source}
|
|
|
221
216
|
InputProps={{
|
|
222
217
|
...params.InputProps,
|
|
223
218
|
endAdornment: (
|
|
224
|
-
<InputAdornment position="end">
|
|
225
|
-
{
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
onAttach={model.addAttachment}
|
|
229
|
-
/>
|
|
230
|
-
)}
|
|
231
|
-
{props.onCancel && <CancelButton onCancel={onCancel} />}
|
|
232
|
-
<SendButton
|
|
233
|
-
model={model}
|
|
234
|
-
sendWithShiftEnter={sendWithShiftEnter}
|
|
235
|
-
inputExists={inputExists || attachments.length > 0}
|
|
236
|
-
onSend={onSend}
|
|
237
|
-
hideIncludeSelection={hideIncludeSelection}
|
|
238
|
-
hasButtonOnLeft={!!props.onCancel}
|
|
239
|
-
/>
|
|
219
|
+
<InputAdornment position="end" className={INPUT_TOOLBAR_CLASS}>
|
|
220
|
+
{toolbarElements.map(item => (
|
|
221
|
+
<item.element model={model} />
|
|
222
|
+
))}
|
|
240
223
|
</InputAdornment>
|
|
241
224
|
)
|
|
242
225
|
}}
|
|
@@ -277,25 +260,17 @@ export namespace ChatInput {
|
|
|
277
260
|
*/
|
|
278
261
|
model: IInputModel;
|
|
279
262
|
/**
|
|
280
|
-
* The
|
|
263
|
+
* The toolbar registry.
|
|
281
264
|
*/
|
|
282
|
-
|
|
265
|
+
toolbarRegistry: IInputToolbarRegistry;
|
|
283
266
|
/**
|
|
284
267
|
* The function to be called to cancel editing.
|
|
285
268
|
*/
|
|
286
269
|
onCancel?: () => unknown;
|
|
287
|
-
/**
|
|
288
|
-
* Whether to allow or not including selection.
|
|
289
|
-
*/
|
|
290
|
-
hideIncludeSelection?: boolean;
|
|
291
270
|
/**
|
|
292
271
|
* Custom mui/material styles.
|
|
293
272
|
*/
|
|
294
273
|
sx?: SxProps<Theme>;
|
|
295
|
-
/**
|
|
296
|
-
* The document manager.
|
|
297
|
-
*/
|
|
298
|
-
documentManager?: IDocumentManager;
|
|
299
274
|
/**
|
|
300
275
|
* Chat command registry.
|
|
301
276
|
*/
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Button } from '@jupyter/react-components';
|
|
7
|
-
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
8
7
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
9
8
|
import {
|
|
10
9
|
LabIcon,
|
|
@@ -19,6 +18,7 @@ import React, { useEffect, useState, useRef, forwardRef } from 'react';
|
|
|
19
18
|
|
|
20
19
|
import { AttachmentPreviewList } from './attachments';
|
|
21
20
|
import { ChatInput } from './chat-input';
|
|
21
|
+
import { IInputToolbarRegistry } from './input';
|
|
22
22
|
import { MarkdownRenderer } from './markdown-renderer';
|
|
23
23
|
import { ScrollContainer } from './scroll-container';
|
|
24
24
|
import { IChatCommandRegistry } from '../chat-commands';
|
|
@@ -41,10 +41,22 @@ const NAVIGATION_BOTTOM_CLASS = 'jp-chat-navigation-bottom';
|
|
|
41
41
|
* The base components props.
|
|
42
42
|
*/
|
|
43
43
|
type BaseMessageProps = {
|
|
44
|
+
/**
|
|
45
|
+
* The mime renderer registry.
|
|
46
|
+
*/
|
|
44
47
|
rmRegistry: IRenderMimeRegistry;
|
|
48
|
+
/**
|
|
49
|
+
* The chat model.
|
|
50
|
+
*/
|
|
45
51
|
model: IChatModel;
|
|
52
|
+
/**
|
|
53
|
+
* The chat commands registry.
|
|
54
|
+
*/
|
|
46
55
|
chatCommandRegistry?: IChatCommandRegistry;
|
|
47
|
-
|
|
56
|
+
/**
|
|
57
|
+
* The input toolbar registry.
|
|
58
|
+
*/
|
|
59
|
+
inputToolbarRegistry: IInputToolbarRegistry;
|
|
48
60
|
};
|
|
49
61
|
|
|
50
62
|
/**
|
|
@@ -200,8 +212,10 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
|
|
|
200
212
|
* The message header props.
|
|
201
213
|
*/
|
|
202
214
|
type ChatMessageHeaderProps = {
|
|
215
|
+
/**
|
|
216
|
+
* The chat message.
|
|
217
|
+
*/
|
|
203
218
|
message: IChatMessage;
|
|
204
|
-
sx?: SxProps<Theme>;
|
|
205
219
|
};
|
|
206
220
|
|
|
207
221
|
/**
|
|
@@ -262,8 +276,7 @@ export function ChatMessageHeader(props: ChatMessageHeaderProps): JSX.Element {
|
|
|
262
276
|
'& > :not(:last-child)': {
|
|
263
277
|
marginRight: 3
|
|
264
278
|
},
|
|
265
|
-
marginBottom: message.stacked ? '0px' : '12px'
|
|
266
|
-
...props.sx
|
|
279
|
+
marginBottom: message.stacked ? '0px' : '12px'
|
|
267
280
|
}}
|
|
268
281
|
>
|
|
269
282
|
{avatar}
|
|
@@ -364,13 +377,15 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
|
|
|
364
377
|
if (edit && canEdit) {
|
|
365
378
|
setInputModel(
|
|
366
379
|
new InputModel({
|
|
380
|
+
onSend: (input: string, model?: IInputModel) =>
|
|
381
|
+
updateMessage(message.id, input, model),
|
|
382
|
+
onCancel: () => cancelEdition(),
|
|
367
383
|
value: message.body,
|
|
368
|
-
activeCellManager: model.activeCellManager,
|
|
369
|
-
selectionWatcher: model.selectionWatcher,
|
|
370
384
|
config: {
|
|
371
385
|
sendWithShiftEnter: model.config.sendWithShiftEnter
|
|
372
386
|
},
|
|
373
|
-
attachments: message.attachments
|
|
387
|
+
attachments: message.attachments,
|
|
388
|
+
documentManager: model.documentManager
|
|
374
389
|
})
|
|
375
390
|
);
|
|
376
391
|
} else {
|
|
@@ -384,14 +399,18 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
|
|
|
384
399
|
};
|
|
385
400
|
|
|
386
401
|
// Update the content of the message.
|
|
387
|
-
const updateMessage = (
|
|
388
|
-
|
|
402
|
+
const updateMessage = (
|
|
403
|
+
id: string,
|
|
404
|
+
input: string,
|
|
405
|
+
inputModel?: IInputModel
|
|
406
|
+
): void => {
|
|
407
|
+
if (!canEdit || !inputModel) {
|
|
389
408
|
return;
|
|
390
409
|
}
|
|
391
410
|
// Update the message
|
|
392
411
|
const updatedMessage = { ...message };
|
|
393
412
|
updatedMessage.body = input;
|
|
394
|
-
updatedMessage.attachments = inputModel
|
|
413
|
+
updatedMessage.attachments = inputModel.attachments;
|
|
395
414
|
model.updateMessage!(id, updatedMessage);
|
|
396
415
|
setEdit(false);
|
|
397
416
|
};
|
|
@@ -411,12 +430,10 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
|
|
|
411
430
|
<div ref={ref} data-index={props.index}>
|
|
412
431
|
{edit && canEdit && inputModel ? (
|
|
413
432
|
<ChatInput
|
|
414
|
-
onSend={(input: string) => updateMessage(message.id, input)}
|
|
415
433
|
onCancel={() => cancelEdition()}
|
|
416
434
|
model={inputModel}
|
|
417
|
-
hideIncludeSelection={true}
|
|
418
435
|
chatCommandRegistry={props.chatCommandRegistry}
|
|
419
|
-
|
|
436
|
+
toolbarRegistry={props.inputToolbarRegistry}
|
|
420
437
|
/>
|
|
421
438
|
) : (
|
|
422
439
|
<MarkdownRenderer
|
package/src/components/chat.tsx
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IThemeManager } from '@jupyterlab/apputils';
|
|
7
|
-
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
8
7
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
9
8
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
|
10
9
|
import SettingsIcon from '@mui/icons-material/Settings';
|
|
@@ -16,16 +15,17 @@ import { JlThemeProvider } from './jl-theme-provider';
|
|
|
16
15
|
import { IChatCommandRegistry } from '../chat-commands';
|
|
17
16
|
import { ChatMessages } from './chat-messages';
|
|
18
17
|
import { ChatInput } from './chat-input';
|
|
18
|
+
import { IInputToolbarRegistry, InputToolbarRegistry } from './input';
|
|
19
19
|
import { AttachmentOpenerContext } from '../context';
|
|
20
20
|
import { IChatModel } from '../model';
|
|
21
21
|
import { IAttachmentOpenerRegistry } from '../registry';
|
|
22
22
|
|
|
23
23
|
export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
|
|
24
24
|
const { model } = props;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
25
|
+
let { inputToolbarRegistry } = props;
|
|
26
|
+
if (!inputToolbarRegistry) {
|
|
27
|
+
inputToolbarRegistry = InputToolbarRegistry.defaultToolbarRegistry();
|
|
28
|
+
}
|
|
29
29
|
|
|
30
30
|
return (
|
|
31
31
|
<AttachmentOpenerContext.Provider value={props.attachmentOpenerRegistry}>
|
|
@@ -33,10 +33,9 @@ export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
|
|
|
33
33
|
rmRegistry={props.rmRegistry}
|
|
34
34
|
model={model}
|
|
35
35
|
chatCommandRegistry={props.chatCommandRegistry}
|
|
36
|
-
|
|
36
|
+
inputToolbarRegistry={inputToolbarRegistry}
|
|
37
37
|
/>
|
|
38
38
|
<ChatInput
|
|
39
|
-
onSend={onSend}
|
|
40
39
|
sx={{
|
|
41
40
|
paddingLeft: 4,
|
|
42
41
|
paddingRight: 4,
|
|
@@ -45,8 +44,8 @@ export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
|
|
|
45
44
|
borderTop: '1px solid var(--jp-border-color1)'
|
|
46
45
|
}}
|
|
47
46
|
model={model.input}
|
|
48
|
-
documentManager={props.documentManager}
|
|
49
47
|
chatCommandRegistry={props.chatCommandRegistry}
|
|
48
|
+
toolbarRegistry={inputToolbarRegistry}
|
|
50
49
|
/>
|
|
51
50
|
</AttachmentOpenerContext.Provider>
|
|
52
51
|
);
|
|
@@ -89,15 +88,7 @@ export function Chat(props: Chat.IOptions): JSX.Element {
|
|
|
89
88
|
)}
|
|
90
89
|
</Box>
|
|
91
90
|
{/* body */}
|
|
92
|
-
{view === Chat.View.chat &&
|
|
93
|
-
<ChatBody
|
|
94
|
-
model={props.model}
|
|
95
|
-
rmRegistry={props.rmRegistry}
|
|
96
|
-
documentManager={props.documentManager}
|
|
97
|
-
chatCommandRegistry={props.chatCommandRegistry}
|
|
98
|
-
attachmentOpenerRegistry={props.attachmentOpenerRegistry}
|
|
99
|
-
/>
|
|
100
|
-
)}
|
|
91
|
+
{view === Chat.View.chat && <ChatBody {...props} />}
|
|
101
92
|
{view === Chat.View.settings && props.settingsPanel && (
|
|
102
93
|
<props.settingsPanel />
|
|
103
94
|
)}
|
|
@@ -122,10 +113,6 @@ export namespace Chat {
|
|
|
122
113
|
* The rendermime registry.
|
|
123
114
|
*/
|
|
124
115
|
rmRegistry: IRenderMimeRegistry;
|
|
125
|
-
/**
|
|
126
|
-
* The document manager.
|
|
127
|
-
*/
|
|
128
|
-
documentManager?: IDocumentManager;
|
|
129
116
|
/**
|
|
130
117
|
* Chat command registry.
|
|
131
118
|
*/
|
|
@@ -134,6 +121,10 @@ export namespace Chat {
|
|
|
134
121
|
* Attachment opener registry.
|
|
135
122
|
*/
|
|
136
123
|
attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
|
|
124
|
+
/**
|
|
125
|
+
* The input toolbar registry
|
|
126
|
+
*/
|
|
127
|
+
inputToolbarRegistry?: IInputToolbarRegistry;
|
|
137
128
|
}
|
|
138
129
|
|
|
139
130
|
/**
|
|
@@ -12,13 +12,15 @@ import { TooltippedIconButton } from '../mui-extras/tooltipped-icon-button';
|
|
|
12
12
|
enum CopyStatus {
|
|
13
13
|
None,
|
|
14
14
|
Copying,
|
|
15
|
-
Copied
|
|
15
|
+
Copied,
|
|
16
|
+
Disabled
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
const COPYBTN_TEXT_BY_STATUS: Record<CopyStatus, string> = {
|
|
19
20
|
[CopyStatus.None]: 'Copy to clipboard',
|
|
20
21
|
[CopyStatus.Copying]: 'Copying…',
|
|
21
|
-
[CopyStatus.Copied]: 'Copied!'
|
|
22
|
+
[CopyStatus.Copied]: 'Copied!',
|
|
23
|
+
[CopyStatus.Disabled]: 'Copy to clipboard disabled in insecure context'
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
type CopyButtonProps = {
|
|
@@ -27,7 +29,10 @@ type CopyButtonProps = {
|
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
export function CopyButton(props: CopyButtonProps): JSX.Element {
|
|
30
|
-
const
|
|
32
|
+
const isCopyDisabled = navigator.clipboard === undefined;
|
|
33
|
+
const [copyStatus, setCopyStatus] = useState<CopyStatus>(
|
|
34
|
+
isCopyDisabled ? CopyStatus.Disabled : CopyStatus.None
|
|
35
|
+
);
|
|
31
36
|
const timeoutId = useRef<number | null>(null);
|
|
32
37
|
|
|
33
38
|
const copy = useCallback(async () => {
|
|
@@ -56,6 +61,7 @@ export function CopyButton(props: CopyButtonProps): JSX.Element {
|
|
|
56
61
|
|
|
57
62
|
return (
|
|
58
63
|
<TooltippedIconButton
|
|
64
|
+
disabled={isCopyDisabled}
|
|
59
65
|
className={props.className}
|
|
60
66
|
tooltip={COPYBTN_TEXT_BY_STATUS[copyStatus]}
|
|
61
67
|
placement="top"
|
|
@@ -3,40 +3,41 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
7
6
|
import { FileDialog } from '@jupyterlab/filebrowser';
|
|
8
7
|
import AttachFileIcon from '@mui/icons-material/AttachFile';
|
|
9
8
|
import React from 'react';
|
|
10
9
|
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { InputToolbarRegistry } from '../toolbar-registry';
|
|
11
|
+
import { TooltippedButton } from '../../mui-extras/tooltipped-button';
|
|
13
12
|
|
|
14
13
|
const ATTACH_BUTTON_CLASS = 'jp-chat-attach-button';
|
|
15
14
|
|
|
16
|
-
/**
|
|
17
|
-
* The attach button props.
|
|
18
|
-
*/
|
|
19
|
-
export type AttachButtonProps = {
|
|
20
|
-
documentManager: IDocumentManager;
|
|
21
|
-
onAttach: (attachment: IAttachment) => void;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
15
|
/**
|
|
25
16
|
* The attach button.
|
|
26
17
|
*/
|
|
27
|
-
export function AttachButton(
|
|
18
|
+
export function AttachButton(
|
|
19
|
+
props: InputToolbarRegistry.IToolbarItemProps
|
|
20
|
+
): JSX.Element {
|
|
21
|
+
const { model } = props;
|
|
28
22
|
const tooltip = 'Add attachment';
|
|
29
23
|
|
|
24
|
+
if (!model.documentManager || !model.addAttachment) {
|
|
25
|
+
return <></>;
|
|
26
|
+
}
|
|
27
|
+
|
|
30
28
|
const onclick = async () => {
|
|
29
|
+
if (!model.documentManager || !model.addAttachment) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
31
32
|
try {
|
|
32
33
|
const files = await FileDialog.getOpenFiles({
|
|
33
34
|
title: 'Select files to attach',
|
|
34
|
-
manager:
|
|
35
|
+
manager: model.documentManager
|
|
35
36
|
});
|
|
36
37
|
if (files.value) {
|
|
37
38
|
files.value.forEach(file => {
|
|
38
39
|
if (file.type !== 'directory') {
|
|
39
|
-
|
|
40
|
+
model.addAttachment?.({ type: 'file', value: file.path });
|
|
40
41
|
}
|
|
41
42
|
});
|
|
42
43
|
}
|
|
@@ -55,12 +56,6 @@ export function AttachButton(props: AttachButtonProps): JSX.Element {
|
|
|
55
56
|
title: tooltip,
|
|
56
57
|
className: ATTACH_BUTTON_CLASS
|
|
57
58
|
}}
|
|
58
|
-
sx={{
|
|
59
|
-
minWidth: 'unset',
|
|
60
|
-
padding: '4px',
|
|
61
|
-
borderRadius: '2px 0px 0px 2px',
|
|
62
|
-
marginRight: '1px'
|
|
63
|
-
}}
|
|
64
59
|
>
|
|
65
60
|
<AttachFileIcon />
|
|
66
61
|
</TooltippedButton>
|
|
@@ -6,25 +6,24 @@
|
|
|
6
6
|
import CancelIcon from '@mui/icons-material/Cancel';
|
|
7
7
|
import React from 'react';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { InputToolbarRegistry } from '../toolbar-registry';
|
|
10
|
+
import { TooltippedButton } from '../../mui-extras/tooltipped-button';
|
|
10
11
|
|
|
11
12
|
const CANCEL_BUTTON_CLASS = 'jp-chat-cancel-button';
|
|
12
13
|
|
|
13
|
-
/**
|
|
14
|
-
* The cancel button props.
|
|
15
|
-
*/
|
|
16
|
-
export type CancelButtonProps = {
|
|
17
|
-
onCancel: () => void;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
14
|
/**
|
|
21
15
|
* The cancel button.
|
|
22
16
|
*/
|
|
23
|
-
export function CancelButton(
|
|
17
|
+
export function CancelButton(
|
|
18
|
+
props: InputToolbarRegistry.IToolbarItemProps
|
|
19
|
+
): JSX.Element {
|
|
20
|
+
if (!props.model.cancel) {
|
|
21
|
+
return <></>;
|
|
22
|
+
}
|
|
24
23
|
const tooltip = 'Cancel edition';
|
|
25
24
|
return (
|
|
26
25
|
<TooltippedButton
|
|
27
|
-
onClick={props.
|
|
26
|
+
onClick={props.model.cancel}
|
|
28
27
|
tooltip={tooltip}
|
|
29
28
|
buttonProps={{
|
|
30
29
|
size: 'small',
|
|
@@ -32,12 +31,6 @@ export function CancelButton(props: CancelButtonProps): JSX.Element {
|
|
|
32
31
|
title: tooltip,
|
|
33
32
|
className: CANCEL_BUTTON_CLASS
|
|
34
33
|
}}
|
|
35
|
-
sx={{
|
|
36
|
-
minWidth: 'unset',
|
|
37
|
-
padding: '4px',
|
|
38
|
-
borderRadius: '2px 0px 0px 2px',
|
|
39
|
-
marginRight: '1px'
|
|
40
|
-
}}
|
|
41
34
|
>
|
|
42
35
|
<CancelIcon />
|
|
43
36
|
</TooltippedButton>
|