@instructure/canvas-rce 5.13.2 → 5.13.5
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/CHANGELOG.md +24 -0
- package/es/bridge/Bridge.js +0 -4
- package/es/defaultTinymceConfig.js +1 -1
- package/es/index.js +2 -0
- package/es/rce/RCE.js +3 -1
- package/es/rce/RCEVariants.js +121 -0
- package/es/rce/RCEWrapper.js +96 -47
- package/es/rce/RCEWrapperProps.js +5 -2
- package/es/rce/StatusBar.js +67 -17
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/Footer.js +1 -0
- package/es/rce/plugins/instructure_icon_maker/components/IconMakerTray.js +6 -1
- package/es/rce/plugins/instructure_rce_external_tools/RceToolWrapper.js +9 -9
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialog.js +25 -3
- package/es/rce/plugins/instructure_rce_external_tools/plugin.js +4 -1
- package/es/rce/plugins/shared/CanvasContentTray.js +6 -158
- package/es/rce/plugins/shared/Filter.js +0 -17
- package/es/rce/plugins/shared/FixedContentTray.js +7 -4
- package/es/rce/plugins/shared/ImageOptionsForm.js +3 -2
- package/es/rce/plugins/shared/Upload/CanvasContentPanel.js +160 -0
- package/es/rce/plugins/shared/Upload/ComputerPanel.js +1 -0
- package/es/rce/plugins/shared/Upload/PanelFilter.js +144 -0
- package/es/rce/plugins/shared/Upload/UploadFile.js +10 -2
- package/es/rce/plugins/shared/Upload/UploadFileModal.js +47 -11
- package/es/rce/plugins/shared/Upload/UsageRightsSelectBox.js +20 -20
- package/es/rce/plugins/shared/Upload/index.js +19 -0
- package/es/rce/plugins/shared/ai_tools/AIResponseModal.js +70 -0
- package/es/rce/plugins/shared/ai_tools/AIToolsTray.js +510 -0
- package/es/rce/plugins/shared/ai_tools/aiicons.js +59 -0
- package/es/rce/plugins/shared/ai_tools/index.js +20 -0
- package/es/rce/plugins/shared/canvasContentUtils.js +190 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/defaultFetchOptions.js +31 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/doFetchApi.js +85 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/get-cookie.js +29 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/index.js +22 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/parse-link-header.js +116 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/query-string-encoding.js +51 -0
- package/es/rce/plugins/shared/useFilterSettings.js +35 -0
- package/es/sidebar/actions/upload.js +5 -2
- package/es/translations/locales/ar.js +64 -1
- package/es/translations/locales/ca.js +65 -2
- package/es/translations/locales/cy.js +64 -1
- package/es/translations/locales/da-x-k12.js +65 -2
- package/es/translations/locales/da.js +65 -2
- package/es/translations/locales/de.js +65 -2
- package/es/translations/locales/el.js +9 -0
- package/es/translations/locales/en-AU-x-unimelb.js +65 -2
- package/es/translations/locales/en-GB-x-ukhe.js +65 -2
- package/es/translations/locales/en.js +65 -2
- package/es/translations/locales/en_AU.js +65 -2
- package/es/translations/locales/en_CA.js +65 -2
- package/es/translations/locales/en_CY.js +65 -2
- package/es/translations/locales/en_GB.js +65 -2
- package/es/translations/locales/es.js +64 -1
- package/es/translations/locales/es_ES.js +64 -1
- package/es/translations/locales/fa_IR.js +9 -0
- package/es/translations/locales/fi.js +64 -1
- package/es/translations/locales/fr.js +65 -2
- package/es/translations/locales/fr_CA.js +65 -2
- package/es/translations/locales/ga.js +62 -2
- package/es/translations/locales/he.js +9 -0
- package/es/translations/locales/hi.js +119 -2
- package/es/translations/locales/ht.js +65 -2
- package/es/translations/locales/hu.js +15 -3
- package/es/translations/locales/hy.js +9 -0
- package/es/translations/locales/id.js +65 -2
- package/es/translations/locales/is.js +65 -2
- package/es/translations/locales/it.js +65 -2
- package/es/translations/locales/ja.js +65 -2
- package/es/translations/locales/ko.js +3 -0
- package/es/translations/locales/mi.js +65 -2
- package/es/translations/locales/ms.js +64 -1
- package/es/translations/locales/nb-x-k12.js +65 -2
- package/es/translations/locales/nb.js +65 -2
- package/es/translations/locales/nl.js +65 -2
- package/es/translations/locales/nn.js +15 -3
- package/es/translations/locales/pl.js +64 -1
- package/es/translations/locales/pt.js +64 -1
- package/es/translations/locales/pt_BR.js +65 -2
- package/es/translations/locales/ru.js +64 -1
- package/es/translations/locales/sl.js +65 -2
- package/es/translations/locales/sv-x-k12.js +65 -2
- package/es/translations/locales/sv.js +65 -2
- package/es/translations/locales/th.js +64 -1
- package/es/translations/locales/tr.js +9 -0
- package/es/translations/locales/uk_UA.js +9 -0
- package/es/translations/locales/vi.js +64 -1
- package/es/translations/locales/zh-Hans.js +64 -1
- package/es/translations/locales/zh-Hant.js +65 -2
- package/es/translations/locales/zh.js +64 -1
- package/es/translations/locales/zh_HK.js +65 -2
- package/es/translations/tinymce/ar_SA.js +4 -0
- package/es/translations/tinymce/bg_BG.js +4 -0
- package/es/translations/tinymce/ca.js +4 -0
- package/es/translations/tinymce/cs.js +4 -0
- package/es/translations/tinymce/cy.js +4 -0
- package/es/translations/tinymce/da.js +4 -0
- package/es/translations/tinymce/de.js +4 -0
- package/es/translations/tinymce/el.js +4 -0
- package/es/translations/tinymce/es.js +4 -0
- package/es/translations/tinymce/fa_IR.js +4 -0
- package/es/translations/tinymce/fr_FR.js +4 -0
- package/es/translations/tinymce/ga.js +4 -0
- package/es/translations/tinymce/he_IL.js +4 -0
- package/es/translations/tinymce/hu_HU.js +4 -0
- package/es/translations/tinymce/hy.js +4 -0
- package/es/translations/tinymce/id.js +4 -0
- package/es/translations/tinymce/it.js +4 -0
- package/es/translations/tinymce/ja.js +4 -0
- package/es/translations/tinymce/ko_KR.js +4 -0
- package/es/translations/tinymce/nb_NO.js +4 -0
- package/es/translations/tinymce/nl.js +4 -0
- package/es/translations/tinymce/pl.js +4 -0
- package/es/translations/tinymce/pt_BR.js +4 -0
- package/es/translations/tinymce/pt_PT.js +4 -0
- package/es/translations/tinymce/ro.js +4 -0
- package/es/translations/tinymce/ru.js +4 -0
- package/es/translations/tinymce/ru_RU.js +5 -1
- package/es/translations/tinymce/sl.js +4 -0
- package/es/translations/tinymce/sr.js +4 -0
- package/es/translations/tinymce/sv_SE.js +4 -0
- package/es/translations/tinymce/th.js +5 -1
- package/es/translations/tinymce/tr_TR.js +4 -0
- package/es/translations/tinymce/uk_UA.js +4 -0
- package/es/translations/tinymce/vi_VN.js +4 -0
- package/es/translations/tinymce/zh_CN.js +4 -0
- package/es/translations/tinymce/zh_TW.js +4 -0
- package/jest/jest-setup.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
import _pt from "prop-types";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Copyright (C) 2024 - present Instructure, Inc.
|
|
5
|
+
*
|
|
6
|
+
* This file is part of Canvas.
|
|
7
|
+
*
|
|
8
|
+
* Canvas is free software: you can redistribute it and/or modify it under
|
|
9
|
+
* the terms of the GNU Affero General Public License as published by the Free
|
|
10
|
+
* Software Foundation, version 3 of the License.
|
|
11
|
+
*
|
|
12
|
+
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
13
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
14
|
+
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
15
|
+
* details.
|
|
16
|
+
*
|
|
17
|
+
* You should have received a copy of the GNU Affero General Public License along
|
|
18
|
+
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
19
|
+
*/
|
|
20
|
+
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
21
|
+
import formatMessage from '../../../../format-message';
|
|
22
|
+
import { Button, CloseButton, CondensedButton, IconButton } from '@instructure/ui-buttons';
|
|
23
|
+
import { Flex } from '@instructure/ui-flex';
|
|
24
|
+
import { Heading } from '@instructure/ui-heading';
|
|
25
|
+
import { Tray } from '@instructure/ui-tray';
|
|
26
|
+
import { SVGIcon } from '@instructure/ui-svg-images';
|
|
27
|
+
import { SimpleSelect } from '@instructure/ui-simple-select';
|
|
28
|
+
import { ScreenReaderContent } from '@instructure/ui-a11y-content';
|
|
29
|
+
import { Spinner } from '@instructure/ui-spinner';
|
|
30
|
+
import { TextArea } from '@instructure/ui-text-area';
|
|
31
|
+
import { TruncateText } from '@instructure/ui-truncate-text';
|
|
32
|
+
import { View } from '@instructure/ui-view';
|
|
33
|
+
import { uid } from '@instructure/uid';
|
|
34
|
+
import { showFlashAlert } from '../../../../common/FlashAlert';
|
|
35
|
+
import doFetchApi from '../do-fetch-api-effect';
|
|
36
|
+
import { AIWandSVG, AIAvatarSVG, InsertSVG, CopySVG, RefreshSVG, DislikeSVG } from './aiicons';
|
|
37
|
+
import { AIResponseModal } from './AIResponseModal';
|
|
38
|
+
|
|
39
|
+
const msgid = () => uid('msg', 3);
|
|
40
|
+
|
|
41
|
+
const modifyAllTaskMessage = formatMessage('Hello. Please describe the modifications you would like to make to your composition.');
|
|
42
|
+
const modifySelectionTaskMessage = formatMessage('Hello. Please describe the modifications you would like to make to your selection.');
|
|
43
|
+
const generateTaskMessage = formatMessage('Please decribe what you would like to compose.');
|
|
44
|
+
export const AIToolsTray = _ref => {
|
|
45
|
+
let {
|
|
46
|
+
open,
|
|
47
|
+
container,
|
|
48
|
+
mountNode,
|
|
49
|
+
contextId,
|
|
50
|
+
contextType,
|
|
51
|
+
currentContent,
|
|
52
|
+
onClose,
|
|
53
|
+
onInsertContent,
|
|
54
|
+
onReplaceContent
|
|
55
|
+
} = _ref;
|
|
56
|
+
const [trayRef, setTrayRef] = useState(null);
|
|
57
|
+
const [containerStyle] = useState(() => {
|
|
58
|
+
if (container) {
|
|
59
|
+
return {
|
|
60
|
+
width: container.style.width,
|
|
61
|
+
boxSizing: container.style.boxSizing,
|
|
62
|
+
transition: container.style.transition
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {};
|
|
67
|
+
});
|
|
68
|
+
const [isOpen, setIsOpen] = useState(open);
|
|
69
|
+
const [task, setTask] = useState(() => {
|
|
70
|
+
return currentContent.content.trim().length > 0 ? 'modify' : 'generate';
|
|
71
|
+
});
|
|
72
|
+
const [userPrompt, setUserPrompt] = useState('');
|
|
73
|
+
const [waitingForResponse, setWaitingForResponse] = useState(false);
|
|
74
|
+
const [responseHtml, setResponseHtml] = useState('');
|
|
75
|
+
const chatContainerRef = useRef(null);
|
|
76
|
+
const getModifyTaskMessage = useCallback(() => {
|
|
77
|
+
return currentContent.type === 'selection' ? modifySelectionTaskMessage : modifyAllTaskMessage;
|
|
78
|
+
}, [currentContent.type]);
|
|
79
|
+
const initChatMessages = useCallback(() => {
|
|
80
|
+
return [task === 'modify' ? {
|
|
81
|
+
id: msgid(),
|
|
82
|
+
type: 'message',
|
|
83
|
+
message: getModifyTaskMessage()
|
|
84
|
+
} : {
|
|
85
|
+
id: msgid(),
|
|
86
|
+
type: 'message',
|
|
87
|
+
message: generateTaskMessage
|
|
88
|
+
}];
|
|
89
|
+
}, [getModifyTaskMessage, task]);
|
|
90
|
+
const chatMessagesRef = useRef(initChatMessages());
|
|
91
|
+
const reset = useCallback(() => {
|
|
92
|
+
chatMessagesRef.current = initChatMessages();
|
|
93
|
+
setWaitingForResponse(false);
|
|
94
|
+
setUserPrompt('');
|
|
95
|
+
}, [initChatMessages]);
|
|
96
|
+
useLayoutEffect(() => {
|
|
97
|
+
var _chatContainerRef$cur;
|
|
98
|
+
|
|
99
|
+
const lastbox = (_chatContainerRef$cur = chatContainerRef.current) === null || _chatContainerRef$cur === void 0 ? void 0 : _chatContainerRef$cur.querySelector('.ai-chat-box:last-child');
|
|
100
|
+
lastbox === null || lastbox === void 0 ? void 0 : lastbox.scrollIntoView({
|
|
101
|
+
behavior: 'smooth',
|
|
102
|
+
block: 'nearest'
|
|
103
|
+
});
|
|
104
|
+
}, [trayRef, chatMessagesRef.current.length]);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
setTask(currentContent.content.trim().length > 0 ? 'modify' : 'generate');
|
|
107
|
+
}, [currentContent.content]);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (open !== isOpen) {
|
|
110
|
+
setIsOpen(open);
|
|
111
|
+
reset();
|
|
112
|
+
}
|
|
113
|
+
}, [isOpen, open, reset]);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
const shrinking_selector = '#content'; // '.block-editor-editor'
|
|
116
|
+
|
|
117
|
+
if (open && trayRef) {
|
|
118
|
+
const ed = document.querySelector(shrinking_selector);
|
|
119
|
+
if (!ed) return;
|
|
120
|
+
const edstyle = window.getComputedStyle(ed);
|
|
121
|
+
const ed_rect = ed.getBoundingClientRect();
|
|
122
|
+
const padding = parseInt(edstyle.paddingRight, 10);
|
|
123
|
+
const tray_left = window.innerWidth - trayRef.offsetWidth;
|
|
124
|
+
|
|
125
|
+
if (ed_rect.right > tray_left) {
|
|
126
|
+
ed.style.boxSizing = 'border-box';
|
|
127
|
+
ed.style.width = `${ed_rect.width - (ed_rect.right - tray_left - padding)}px`;
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
const ed = document.querySelector(shrinking_selector);
|
|
131
|
+
if (!ed) return;
|
|
132
|
+
ed.style.boxSizing = containerStyle.boxSizing || '';
|
|
133
|
+
ed.style.width = containerStyle.width || '';
|
|
134
|
+
ed.style.transition = containerStyle.transition || '';
|
|
135
|
+
}
|
|
136
|
+
}, [containerStyle, open, trayRef]);
|
|
137
|
+
const getResponse = useCallback(prompt => {
|
|
138
|
+
setWaitingForResponse(true); // the .finally triggered the error even though there is a .catch
|
|
139
|
+
// eslint-disable-next-line promise/catch-or-return
|
|
140
|
+
|
|
141
|
+
doFetchApi({
|
|
142
|
+
path: '/api/v1/rich_content/generate',
|
|
143
|
+
method: 'POST',
|
|
144
|
+
headers: {
|
|
145
|
+
'content-type': 'application/json'
|
|
146
|
+
},
|
|
147
|
+
body: JSON.stringify({
|
|
148
|
+
// context_id: contextId,
|
|
149
|
+
// context_type: contextType,
|
|
150
|
+
course_id: contextId,
|
|
151
|
+
prompt,
|
|
152
|
+
current_copy: task === 'modify' ? currentContent : undefined,
|
|
153
|
+
type_of_request: task
|
|
154
|
+
})
|
|
155
|
+
}).then(result => {
|
|
156
|
+
const {
|
|
157
|
+
json
|
|
158
|
+
} = result;
|
|
159
|
+
|
|
160
|
+
if (json.error) {
|
|
161
|
+
chatMessagesRef.current.push({
|
|
162
|
+
id: msgid(),
|
|
163
|
+
type: 'error',
|
|
164
|
+
message: formatMessage(json.error)
|
|
165
|
+
});
|
|
166
|
+
} else {
|
|
167
|
+
chatMessagesRef.current.push({
|
|
168
|
+
id: msgid(),
|
|
169
|
+
type: 'response',
|
|
170
|
+
message: json.content
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}).catch(async err => {
|
|
174
|
+
const err_result = await err.response.json();
|
|
175
|
+
const msg = err_result.error || formatMessage('An error occurred processing your request');
|
|
176
|
+
chatMessagesRef.current.push({
|
|
177
|
+
id: msgid(),
|
|
178
|
+
type: 'error',
|
|
179
|
+
message: msg
|
|
180
|
+
});
|
|
181
|
+
}).finally(() => {
|
|
182
|
+
setWaitingForResponse(false);
|
|
183
|
+
});
|
|
184
|
+
}, [contextId, currentContent, task]);
|
|
185
|
+
const handleCloseTray = useCallback(() => {
|
|
186
|
+
onClose();
|
|
187
|
+
chatMessagesRef.current.push({
|
|
188
|
+
id: msgid(),
|
|
189
|
+
type: 'message',
|
|
190
|
+
message: task === 'modify' ? getModifyTaskMessage() : generateTaskMessage
|
|
191
|
+
});
|
|
192
|
+
setUserPrompt('');
|
|
193
|
+
}, [getModifyTaskMessage, onClose, task]);
|
|
194
|
+
const handleChangeTask = useCallback((event, data) => {
|
|
195
|
+
setTask(data.value);
|
|
196
|
+
setWaitingForResponse(false);
|
|
197
|
+
chatMessagesRef.current.push({
|
|
198
|
+
id: msgid(),
|
|
199
|
+
type: 'message',
|
|
200
|
+
message: data.value === 'modify' ? getModifyTaskMessage() : generateTaskMessage
|
|
201
|
+
});
|
|
202
|
+
}, [getModifyTaskMessage]);
|
|
203
|
+
const handlePromptChange = useCallback(e => {
|
|
204
|
+
setUserPrompt(e.target.value);
|
|
205
|
+
}, []);
|
|
206
|
+
const handleSubmitPrompt = useCallback(() => {
|
|
207
|
+
chatMessagesRef.current.push({
|
|
208
|
+
id: msgid(),
|
|
209
|
+
type: 'user',
|
|
210
|
+
message: userPrompt.trim()
|
|
211
|
+
});
|
|
212
|
+
getResponse(userPrompt);
|
|
213
|
+
setUserPrompt('');
|
|
214
|
+
}, [getResponse, userPrompt]);
|
|
215
|
+
const handleInsertResponse = useCallback(responseText => {
|
|
216
|
+
onInsertContent(responseText);
|
|
217
|
+
}, [onInsertContent]);
|
|
218
|
+
const handleCopyResponse = useCallback(async responseText => {
|
|
219
|
+
try {
|
|
220
|
+
// @ts-expect-error ClipboardItem.supports really does exist
|
|
221
|
+
if (ClipboardItem.supports('text/html')) {
|
|
222
|
+
const htmlBlob = new Blob([responseText], {
|
|
223
|
+
type: 'text/html'
|
|
224
|
+
});
|
|
225
|
+
await navigator.clipboard.write([new ClipboardItem({
|
|
226
|
+
'text/html': htmlBlob
|
|
227
|
+
})]);
|
|
228
|
+
} else {
|
|
229
|
+
const div = document.createElement('div');
|
|
230
|
+
div.innerHTML = responseText;
|
|
231
|
+
await navigator.clipboard.writeText(div.textContent || '');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
showFlashAlert({
|
|
235
|
+
message: formatMessage('Response copied to clipboard'),
|
|
236
|
+
type: 'success',
|
|
237
|
+
err: undefined
|
|
238
|
+
});
|
|
239
|
+
} catch (err) {
|
|
240
|
+
showFlashAlert({
|
|
241
|
+
message: formatMessage('Failed to copy response'),
|
|
242
|
+
type: 'error',
|
|
243
|
+
err: undefined
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}, []);
|
|
247
|
+
const handleRefreshResponse = useCallback(() => {
|
|
248
|
+
getResponse(userPrompt);
|
|
249
|
+
}, [getResponse, userPrompt]);
|
|
250
|
+
const handleDislikeResponse = useCallback(() => {
|
|
251
|
+
// eslint-disable-next-line no-console
|
|
252
|
+
console.log('dislike response'); // TODO: what?
|
|
253
|
+
}, []);
|
|
254
|
+
const handleShowWholeResponse = useCallback(event => {
|
|
255
|
+
const msgId = event.target.dataset.messageId;
|
|
256
|
+
const message = chatMessagesRef.current.find(msg => msg.id === msgId);
|
|
257
|
+
|
|
258
|
+
if (message) {
|
|
259
|
+
setResponseHtml(message.message);
|
|
260
|
+
}
|
|
261
|
+
}, []);
|
|
262
|
+
const handleCloseResponseModal = useCallback(() => {
|
|
263
|
+
setResponseHtml('');
|
|
264
|
+
}, []);
|
|
265
|
+
const handleInsertFromModal = useCallback(() => {
|
|
266
|
+
handleInsertResponse(responseHtml);
|
|
267
|
+
handleCloseResponseModal();
|
|
268
|
+
}, [handleCloseResponseModal, handleInsertResponse, responseHtml]);
|
|
269
|
+
const handleReplaceFromModal = useCallback(() => {
|
|
270
|
+
onReplaceContent(responseHtml);
|
|
271
|
+
handleCloseResponseModal();
|
|
272
|
+
}, [handleCloseResponseModal, onReplaceContent, responseHtml]);
|
|
273
|
+
|
|
274
|
+
const sharkfin = () => {
|
|
275
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
276
|
+
width: "14",
|
|
277
|
+
height: "14",
|
|
278
|
+
viewBox: "0 0 14 14",
|
|
279
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
280
|
+
}, /*#__PURE__*/React.createElement("polyline", {
|
|
281
|
+
points: "0,14 0,0 14,14",
|
|
282
|
+
fill: "none",
|
|
283
|
+
stroke: "#ccc",
|
|
284
|
+
strokeWidth: "1"
|
|
285
|
+
}), /*#__PURE__*/React.createElement("polyline", {
|
|
286
|
+
points: "0,14 14,14",
|
|
287
|
+
stroke: "white",
|
|
288
|
+
strokeWidth: "2"
|
|
289
|
+
}));
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const renderResponse = msgId => {
|
|
293
|
+
const message = chatMessagesRef.current.find(msg => msg.id === msgId);
|
|
294
|
+
|
|
295
|
+
if (!message) {
|
|
296
|
+
return /*#__PURE__*/React.createElement("span", null, formatMessage("I'm sorry, but I cannot find the AI's answer"));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const div = document.createElement('div');
|
|
300
|
+
div.innerHTML = message.message;
|
|
301
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
302
|
+
style: {
|
|
303
|
+
display: 'flex',
|
|
304
|
+
flexDirection: 'column'
|
|
305
|
+
}
|
|
306
|
+
}, /*#__PURE__*/React.createElement(TruncateText, {
|
|
307
|
+
maxLines: 3
|
|
308
|
+
}, div.textContent), /*#__PURE__*/React.createElement("span", {
|
|
309
|
+
style: {
|
|
310
|
+
alignSelf: 'end'
|
|
311
|
+
}
|
|
312
|
+
}, /*#__PURE__*/React.createElement(CondensedButton, {
|
|
313
|
+
onClick: handleShowWholeResponse,
|
|
314
|
+
"data-message-id": msgId
|
|
315
|
+
}, formatMessage('Show all'))));
|
|
316
|
+
}; // TODO: should the response box get truncated?
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
const renderChatBox = (message, key) => {
|
|
320
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
321
|
+
id: message.id,
|
|
322
|
+
className: "ai-chat-box",
|
|
323
|
+
key: key,
|
|
324
|
+
style: {
|
|
325
|
+
display: 'flex',
|
|
326
|
+
flexDirection: 'column',
|
|
327
|
+
justifyContent: 'start',
|
|
328
|
+
rowGap: '4px'
|
|
329
|
+
}
|
|
330
|
+
}, /*#__PURE__*/React.createElement(SVGIcon, {
|
|
331
|
+
src: AIAvatarSVG,
|
|
332
|
+
size: "small"
|
|
333
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
334
|
+
style: {
|
|
335
|
+
padding: '.5rem',
|
|
336
|
+
border: '1px solid #ccc',
|
|
337
|
+
borderRadius: '.5rem',
|
|
338
|
+
position: 'relative'
|
|
339
|
+
}
|
|
340
|
+
}, message.type === 'waiting' && /*#__PURE__*/React.createElement(Spinner, {
|
|
341
|
+
renderTitle: message.message,
|
|
342
|
+
size: "x-small"
|
|
343
|
+
}), (message.type === 'message' || message.type === 'user') && message.message, message.type === 'response' && renderResponse(message.id), message.type === 'error' && /*#__PURE__*/React.createElement("span", null, message.message), /*#__PURE__*/React.createElement("div", {
|
|
344
|
+
style: {
|
|
345
|
+
position: 'absolute',
|
|
346
|
+
top: '-18px',
|
|
347
|
+
// Adjust this value to position the sharkfin
|
|
348
|
+
left: '40px' // Adjust this value to align the sharkfin horizontally
|
|
349
|
+
|
|
350
|
+
}
|
|
351
|
+
}, sharkfin())), message.type === 'response' ?
|
|
352
|
+
/*#__PURE__*/
|
|
353
|
+
|
|
354
|
+
/* TODO: why is it to wide w/o maxWidth? */
|
|
355
|
+
React.createElement("div", {
|
|
356
|
+
style: {
|
|
357
|
+
display: 'flex',
|
|
358
|
+
gap: '8px',
|
|
359
|
+
justifyContent: 'end',
|
|
360
|
+
maxWidth: '95%',
|
|
361
|
+
margin: '5px 0'
|
|
362
|
+
}
|
|
363
|
+
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
364
|
+
screenReaderLabel: formatMessage('Insert'),
|
|
365
|
+
withBackground: false,
|
|
366
|
+
withBorder: false,
|
|
367
|
+
onClick: handleInsertResponse.bind(null, message.message)
|
|
368
|
+
}, /*#__PURE__*/React.createElement(SVGIcon, {
|
|
369
|
+
src: InsertSVG,
|
|
370
|
+
size: "x-small"
|
|
371
|
+
})), /*#__PURE__*/React.createElement(IconButton, {
|
|
372
|
+
screenReaderLabel: formatMessage('Copy'),
|
|
373
|
+
withBackground: false,
|
|
374
|
+
withBorder: false,
|
|
375
|
+
onClick: handleCopyResponse.bind(null, message.message)
|
|
376
|
+
}, /*#__PURE__*/React.createElement(SVGIcon, {
|
|
377
|
+
src: CopySVG,
|
|
378
|
+
size: "x-small"
|
|
379
|
+
})), /*#__PURE__*/React.createElement(IconButton, {
|
|
380
|
+
screenReaderLabel: formatMessage('Retry'),
|
|
381
|
+
withBackground: false,
|
|
382
|
+
withBorder: false,
|
|
383
|
+
onClick: handleRefreshResponse
|
|
384
|
+
}, /*#__PURE__*/React.createElement(SVGIcon, {
|
|
385
|
+
src: RefreshSVG,
|
|
386
|
+
size: "x-small"
|
|
387
|
+
})), /*#__PURE__*/React.createElement(IconButton, {
|
|
388
|
+
screenReaderLabel: formatMessage('Dislike'),
|
|
389
|
+
withBackground: false,
|
|
390
|
+
withBorder: false,
|
|
391
|
+
onClick: handleDislikeResponse
|
|
392
|
+
}, /*#__PURE__*/React.createElement(SVGIcon, {
|
|
393
|
+
src: DislikeSVG,
|
|
394
|
+
size: "x-small"
|
|
395
|
+
}))) : null);
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const renderChatMessages = () => {
|
|
399
|
+
const messages = chatMessagesRef.current.map(message => {
|
|
400
|
+
return renderChatBox(message, message.id);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
if (waitingForResponse) {
|
|
404
|
+
messages.push(renderChatBox({
|
|
405
|
+
id: msgid(),
|
|
406
|
+
type: 'waiting',
|
|
407
|
+
message: formatMessage('Waiting for response')
|
|
408
|
+
}, 'ai-waiting-message'));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return messages;
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
return /*#__PURE__*/React.createElement(Tray, {
|
|
415
|
+
contentRef: el => setTrayRef(el),
|
|
416
|
+
label: "AIToolsTray",
|
|
417
|
+
mountNode: mountNode,
|
|
418
|
+
open: open,
|
|
419
|
+
placement: "end",
|
|
420
|
+
size: "small",
|
|
421
|
+
onClose: handleCloseTray
|
|
422
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
423
|
+
as: "div",
|
|
424
|
+
padding: "small",
|
|
425
|
+
position: "relative",
|
|
426
|
+
height: "100vh",
|
|
427
|
+
overflowY: "hidden"
|
|
428
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
429
|
+
style: {
|
|
430
|
+
display: 'flex',
|
|
431
|
+
flexDirection: 'column',
|
|
432
|
+
gap: '16px',
|
|
433
|
+
height: '100%',
|
|
434
|
+
minHeight: '1px',
|
|
435
|
+
maxHeight: '100%'
|
|
436
|
+
}
|
|
437
|
+
}, /*#__PURE__*/React.createElement(Flex, {
|
|
438
|
+
margin: "0 0 medium",
|
|
439
|
+
gap: "small"
|
|
440
|
+
}, /*#__PURE__*/React.createElement(CloseButton, {
|
|
441
|
+
placement: "end",
|
|
442
|
+
onClick: handleCloseTray,
|
|
443
|
+
screenReaderLabel: "Close"
|
|
444
|
+
}), /*#__PURE__*/React.createElement(SVGIcon, {
|
|
445
|
+
src: AIWandSVG,
|
|
446
|
+
size: "x-small"
|
|
447
|
+
}), /*#__PURE__*/React.createElement(Heading, {
|
|
448
|
+
level: "h3"
|
|
449
|
+
}, formatMessage('Writing Assistant'))), /*#__PURE__*/React.createElement(SimpleSelect, {
|
|
450
|
+
renderLabel: formatMessage('What would you like to do?'),
|
|
451
|
+
value: task,
|
|
452
|
+
onChange: handleChangeTask
|
|
453
|
+
}, /*#__PURE__*/React.createElement(SimpleSelect.Option, {
|
|
454
|
+
id: "modify",
|
|
455
|
+
value: "modify",
|
|
456
|
+
isDisabled: currentContent.content.trim().length === 0
|
|
457
|
+
}, formatMessage('Modify')), /*#__PURE__*/React.createElement(SimpleSelect.Option, {
|
|
458
|
+
id: "generate",
|
|
459
|
+
value: "generate"
|
|
460
|
+
}, formatMessage('Compose'))), /*#__PURE__*/React.createElement("div", {
|
|
461
|
+
style: {
|
|
462
|
+
flexGrow: 1,
|
|
463
|
+
overflowY: 'auto'
|
|
464
|
+
}
|
|
465
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
466
|
+
ref: chatContainerRef,
|
|
467
|
+
style: {
|
|
468
|
+
display: 'flex',
|
|
469
|
+
flexDirection: 'column',
|
|
470
|
+
gap: '8px',
|
|
471
|
+
justifyContent: 'end',
|
|
472
|
+
minHeight: '100%'
|
|
473
|
+
}
|
|
474
|
+
}, renderChatMessages())), /*#__PURE__*/React.createElement(View, {
|
|
475
|
+
as: "div",
|
|
476
|
+
padding: "small 0 0 0",
|
|
477
|
+
borderWidth: "small 0 0 0"
|
|
478
|
+
}, /*#__PURE__*/React.createElement(TextArea, {
|
|
479
|
+
id: "ai-prompt",
|
|
480
|
+
label: /*#__PURE__*/React.createElement(ScreenReaderContent, null, formatMessage('Enter text')),
|
|
481
|
+
resize: "vertical",
|
|
482
|
+
value: userPrompt,
|
|
483
|
+
onChange: handlePromptChange
|
|
484
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
485
|
+
style: {
|
|
486
|
+
alignSelf: 'end'
|
|
487
|
+
}
|
|
488
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
489
|
+
onClick: handleSubmitPrompt,
|
|
490
|
+
interaction: waitingForResponse || !userPrompt.trim() ? 'disabled' : 'enabled'
|
|
491
|
+
}, formatMessage('Submit')))), responseHtml && /*#__PURE__*/React.createElement(AIResponseModal, {
|
|
492
|
+
open: true,
|
|
493
|
+
onClose: handleCloseResponseModal,
|
|
494
|
+
html: responseHtml,
|
|
495
|
+
onInsert: handleInsertFromModal,
|
|
496
|
+
onReplace: handleReplaceFromModal
|
|
497
|
+
})));
|
|
498
|
+
};
|
|
499
|
+
AIToolsTray.propTypes = {
|
|
500
|
+
open: _pt.bool.isRequired,
|
|
501
|
+
contextId: _pt.string.isRequired,
|
|
502
|
+
contextType: _pt.string.isRequired,
|
|
503
|
+
currentContent: _pt.shape({
|
|
504
|
+
type: _pt.oneOf(['selection', 'full']).isRequired,
|
|
505
|
+
content: _pt.string.isRequired
|
|
506
|
+
}).isRequired,
|
|
507
|
+
onClose: _pt.func.isRequired,
|
|
508
|
+
onInsertContent: _pt.func.isRequired,
|
|
509
|
+
onReplaceContent: _pt.func.isRequired
|
|
510
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 - present Instructure, Inc.
|
|
3
|
+
*
|
|
4
|
+
* This file is part of Canvas.
|
|
5
|
+
*
|
|
6
|
+
* Canvas is free software: you can redistribute it and/or modify it under
|
|
7
|
+
* the terms of the GNU Affero General Public License as published by the Free
|
|
8
|
+
* Software Foundation, version 3 of the License.
|
|
9
|
+
*
|
|
10
|
+
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
11
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
12
|
+
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
13
|
+
* details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Affero General Public License along
|
|
16
|
+
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
// @ts-expect-error
|
|
19
|
+
import { IconCopyLine, IconRefreshLine } from '@instructure/ui-icons/es/svg';
|
|
20
|
+
const AIWandSVG = `<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
21
|
+
<mask id="mask0_5548_26552" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="18" height="18">
|
|
22
|
+
<path d="M8.48511 5.85958C8.34447 5.71049 8.11666 5.71049 7.97603 5.85958L6.54795 7.3735C6.40731 7.52256 6.40731 7.76409 6.54795 7.91315L8.75896 10.2571L8.75968 10.2582L8.76075 10.259L15.9574 17.8882C16.0277 17.9627 16.1198 18 16.2119 18C16.304 18 16.3961 17.9627 16.4664 17.8882L17.8945 16.3743C18.0352 16.2252 18.0352 15.9837 17.8945 15.8346L8.48511 5.85958ZM8.23057 6.66907L9.93327 8.47413L9.01436 9.44848L7.31157 7.64331L8.23057 6.66907ZM16.2119 17.0787L9.52344 9.98813L10.4423 9.01378L17.1309 16.1044L16.2119 17.0787Z" fill="#2D3B45"/>
|
|
23
|
+
<path d="M6.9677 4.52528C6.98177 4.52716 6.99581 4.52789 7.00988 4.52789C7.13082 4.52789 7.24473 4.46343 7.3119 4.35423L7.89726 3.3986L8.97165 3.3688C9.10875 3.3647 9.23182 3.27899 9.28912 3.14703C9.34641 3.01511 9.32815 2.86005 9.242 2.74714L8.56629 1.86119L8.8711 0.769191C8.91013 0.629809 8.87074 0.479228 8.77021 0.380468C8.66999 0.281678 8.52444 0.251498 8.39683 0.304431L7.39345 0.712163L6.50783 0.0674013C6.395 -0.0153617 6.24769 -0.0224389 6.12816 0.0491233C6.00862 0.119925 5.93726 0.256733 5.94426 0.401699L6.00018 1.53956L5.14798 2.23316C5.03898 2.32151 4.98731 2.46759 5.01402 2.61033C5.04075 2.75272 5.1413 2.86675 5.27383 2.90442L6.31166 3.19959L6.67062 4.27372C6.71633 4.4105 6.83164 4.50815 6.9677 4.52528ZM6.16471 2.36772L6.58872 2.0226C6.68292 1.94618 6.73531 1.82543 6.72932 1.7002L6.70157 1.13443L7.14172 1.45495C7.23946 1.52614 7.36393 1.54216 7.47466 1.49672L7.97354 1.29396L7.822 1.83698C7.78827 1.95773 7.81287 2.08781 7.88741 2.18546L8.2235 2.62601L7.68912 2.64089C7.57063 2.64425 7.46131 2.70912 7.39662 2.81458L7.10552 3.28978L6.92693 2.75571C6.88753 2.63718 6.79542 2.54699 6.68083 2.51455L6.16471 2.36772Z" fill="#2D3B45"/>
|
|
24
|
+
<path d="M5.00785 9.67232L5.31265 8.58029C5.35166 8.4409 5.31229 8.29032 5.21174 8.19156C5.11119 8.0928 4.96636 8.06262 4.83838 8.11553L3.83536 8.52329L2.94939 7.8785C2.83617 7.79614 2.68853 7.78904 2.56968 7.86025C2.45015 7.93105 2.37878 8.06783 2.38582 8.21282L2.44171 9.35068L1.5895 10.0443C1.48054 10.1326 1.42884 10.2787 1.45557 10.4215C1.48227 10.5638 1.58283 10.6779 1.71538 10.7155L2.75358 11.0107L3.11251 12.0845C3.15822 12.2212 3.27353 12.3189 3.40959 12.336C3.42366 12.3379 3.43773 12.3386 3.45179 12.3386C3.57273 12.3386 3.68664 12.2742 3.75379 12.1649L4.33915 11.2097L5.41354 11.1799C5.55067 11.1758 5.6737 11.0901 5.731 10.9582C5.78833 10.8262 5.77004 10.6712 5.68391 10.5582L5.00785 9.67232ZM4.13101 10.452C4.01255 10.4554 3.90319 10.5202 3.8385 10.6257L3.54741 11.1009L3.36881 10.5668C3.32945 10.4483 3.23734 10.3581 3.12271 10.3257L2.6066 10.1788L3.03024 9.83369C3.12448 9.7573 3.17687 9.63655 3.17088 9.51133L3.1431 8.94517L3.58363 9.26608C3.68137 9.33764 3.80581 9.35329 3.91655 9.30781L4.41509 9.10506L4.26356 9.6481C4.22982 9.76886 4.25443 9.89894 4.32894 9.99659L4.66541 10.4371L4.13101 10.452Z" fill="#2D3B45"/>
|
|
25
|
+
<path d="M1.96063 6.47752C1.97467 6.47936 1.98874 6.48012 2.00281 6.48012C2.12375 6.48012 2.23765 6.41563 2.3048 6.30643L2.89016 5.35083L3.96458 5.321C4.10168 5.3169 4.22472 5.23119 4.28204 5.09923C4.33934 4.96731 4.32105 4.81225 4.23492 4.69934L3.55922 3.81343L3.86402 2.72139C3.90303 2.58201 3.86366 2.43143 3.76311 2.33267C3.66292 2.23391 3.51701 2.2037 3.38975 2.25663L2.38637 2.66437L1.50076 2.0196C1.38754 1.93687 1.24095 1.92976 1.12106 2.00133C1.00152 2.07216 0.930156 2.20894 0.937191 2.3539L0.993081 3.49176L0.140875 4.18536C0.0319077 4.27371 -0.0197896 4.41982 0.00694182 4.56256C0.0336457 4.70493 0.134199 4.81898 0.266753 4.85662L1.30459 5.15179L1.66355 6.22592C1.70923 6.3627 1.82457 6.46035 1.96063 6.47752ZM1.15764 4.31992L1.58161 3.9748C1.67585 3.89838 1.72824 3.77763 1.72225 3.6524L1.69447 3.08666L2.13464 3.40718C2.23274 3.47872 2.35718 3.49439 2.46759 3.44892L2.96646 3.24616L2.81493 3.78918C2.78119 3.90996 2.8058 4.04001 2.88031 4.13766L3.21643 4.57821L2.68204 4.59312C2.56356 4.59646 2.45421 4.66132 2.38954 4.76678L2.09842 5.24198L1.91983 4.70791C1.88046 4.58938 1.78835 4.49919 1.67373 4.46676L1.15764 4.31992Z" fill="#2D3B45"/>
|
|
26
|
+
</mask>
|
|
27
|
+
<g mask="url(#mask0_5548_26552)">
|
|
28
|
+
<rect width="18" height="18" fill="currentColor"/>
|
|
29
|
+
</g>
|
|
30
|
+
</svg>
|
|
31
|
+
`;
|
|
32
|
+
const InsertSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none">
|
|
33
|
+
<path d="M16.9455 16.9451H12.375V18H18V12.375H16.9455V16.9451Z" fill="#2D3B45"/>
|
|
34
|
+
<path d="M1.05487 1.0545H5.625V0H0V5.625H1.0545L1.05487 1.0545Z" fill="#2D3B45"/>
|
|
35
|
+
<path d="M12.375 0V1.0545H16.9455V5.625H18V0H12.375Z" fill="#2D3B45"/>
|
|
36
|
+
<path d="M1.05487 12.375H0V18H5.625V16.9451H1.05487V12.375Z" fill="#2D3B45"/>
|
|
37
|
+
<path d="M3.59082 14.4093H14.4099V3.59058H3.59082V14.4093ZM4.64532 4.64508H13.3551V13.3548H4.64532V4.64508Z" fill="#2D3B45"/>
|
|
38
|
+
<path d="M9.52752 6.92065H8.47302V8.47278H6.9209V9.52728H8.47302V11.0794H9.52752V9.52728H11.0796V8.47278H9.52752V6.92065Z" fill="#2D3B45"/>
|
|
39
|
+
</svg>`;
|
|
40
|
+
const CopySVG = IconCopyLine === null || IconCopyLine === void 0 ? void 0 : IconCopyLine.src;
|
|
41
|
+
const RefreshSVG = IconRefreshLine === null || IconRefreshLine === void 0 ? void 0 : IconRefreshLine.src;
|
|
42
|
+
const DislikeSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none">
|
|
43
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.17647 7.41176L3.2353 7.41176L3.2353 6.35294C2.65189 6.35294 2.17647 5.87859 2.17647 5.29411C2.17647 4.70964 2.65189 4.23529 3.2353 4.23529L4.29412 4.23529L4.29412 3.17647C3.71071 3.17647 3.2353 2.70211 3.2353 2.11764C3.2353 1.53317 3.71071 1.05882 4.29412 1.05882L13.2941 1.05882C14.7532 1.05882 15.9412 2.24576 15.9412 3.70588L15.9412 9.52941L14.9417 9.52941C13.6277 9.52941 12.3698 10.0694 11.4888 11.0086C10.2267 12.3554 8.738 14.4445 8.54953 16.9412L8.20859 16.9412C7.7353 16.9412 7.28953 16.7315 6.98671 16.3652C6.68071 15.9946 6.55683 15.5107 6.64788 15.0385C6.86071 13.9267 7.21224 12.8255 7.69083 11.7656C7.91424 11.2733 7.87188 10.71 7.58071 10.2568C7.28635 9.80153 6.78659 9.52941 6.24341 9.52941L2.17647 9.52941C1.59306 9.52941 1.11765 9.05506 1.11765 8.47059C1.11765 7.88611 1.59306 7.41176 2.17647 7.41176ZM0.0588235 8.47059C0.0588234 9.63847 1.00859 10.5882 2.17647 10.5882L6.24341 10.5882C6.42765 10.5882 6.59071 10.6761 6.69024 10.8307C6.78765 10.9821 6.80141 11.1642 6.72624 11.3294C6.21377 12.4645 5.83682 13.6461 5.60706 14.8405C5.45776 15.624 5.66212 16.4255 6.17035 17.0396C6.67541 17.6495 7.41871 18 8.20859 18L9.58824 18L9.58824 17.4706C9.58824 15.0851 11.042 13.0341 12.2607 11.7328C12.9426 11.0065 13.9199 10.5882 14.9416 10.5882L17 10.5882L17 3.70588C17 1.66235 15.3376 -1.45327e-07 13.2941 -3.23979e-07L4.29412 -1.11078e-06C3.12624 -1.21288e-06 2.17647 0.949763 2.17647 2.11765C2.17647 2.55282 2.30882 2.95835 2.53435 3.29506C1.71059 3.58518 1.11765 4.37188 1.11765 5.29412C1.11765 5.72929 1.25 6.13482 1.47553 6.47153C0.651767 6.76164 0.0588235 7.54835 0.0588235 8.47059Z" fill="#2D3B45"/>
|
|
44
|
+
</svg>`;
|
|
45
|
+
const AIAvatarSVG = `
|
|
46
|
+
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
47
|
+
<g id="Avatar - AI">
|
|
48
|
+
<rect id="Rectangle 2318" x="0.5" y="0.5" width="39" height="39" rx="19.5" fill="white" stroke="#C7CDD1"/>
|
|
49
|
+
<rect id="Untitled-4 1" x="8" y="9" width="24" height="23.4915" fill="url(#pattern0_5509_72095)"/>
|
|
50
|
+
</g>
|
|
51
|
+
<defs>
|
|
52
|
+
<pattern id="pattern0_5509_72095" patternContentUnits="objectBoundingBox" width="1" height="1">
|
|
53
|
+
<use xlink:href="#image0_5509_72095" transform="scale(0.0313 0.0313)"/>
|
|
54
|
+
</pattern>
|
|
55
|
+
<image id="image0_5509_72095" data-name="Untitled-4.png" width="32" height="32" xlink:href="data:image/png;base64,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"/>
|
|
56
|
+
</defs>
|
|
57
|
+
</svg>
|
|
58
|
+
`;
|
|
59
|
+
export { AIWandSVG, AIAvatarSVG, InsertSVG, CopySVG, RefreshSVG, DislikeSVG };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 - present Instructure, Inc.
|
|
3
|
+
*
|
|
4
|
+
* This file is part of Canvas.
|
|
5
|
+
*
|
|
6
|
+
* Canvas is free software: you can redistribute it and/or modify it under
|
|
7
|
+
* the terms of the GNU Affero General Public License as published by the Free
|
|
8
|
+
* Software Foundation, version 3 of the License.
|
|
9
|
+
*
|
|
10
|
+
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
11
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
12
|
+
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
13
|
+
* details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Affero General Public License along
|
|
16
|
+
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
export * from './aiicons';
|
|
19
|
+
export * from './AIToolsTray';
|
|
20
|
+
export * from './AIResponseModal';
|