open-chat-studio-widget 0.4.5 → 0.4.6
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/README.md +118 -94
- package/dist/cjs/{index-bcb28089.js → index-c9203be6.js} +29 -3
- package/dist/cjs/index-c9203be6.js.map +1 -0
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js +314 -73
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js.map +1 -1
- package/dist/cjs/open-chat-studio-widget.cjs.js +2 -2
- package/dist/collection/components/ocs-chat/heroicons.js +11 -2
- package/dist/collection/components/ocs-chat/heroicons.js.map +1 -1
- package/dist/collection/components/ocs-chat/ocs-chat.css +1042 -129
- package/dist/collection/components/ocs-chat/ocs-chat.js +367 -78
- package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
- package/dist/components/open-chat-studio-widget.js +323 -78
- package/dist/components/open-chat-studio-widget.js.map +1 -1
- package/dist/esm/{index-205c77bc.js → index-0349ca51.js} +29 -3
- package/dist/esm/index-0349ca51.js.map +1 -0
- package/dist/esm/loader.js +3 -3
- package/dist/esm/open-chat-studio-widget.entry.js +314 -73
- package/dist/esm/open-chat-studio-widget.entry.js.map +1 -1
- package/dist/esm/open-chat-studio-widget.js +3 -3
- package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js +1 -1
- package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js.map +1 -1
- package/dist/open-chat-studio-widget/p-16df1b20.entry.js +4 -0
- package/dist/open-chat-studio-widget/p-16df1b20.entry.js.map +1 -0
- package/dist/open-chat-studio-widget/{p-78d09c6b.js → p-3dc66a9a.js} +3 -3
- package/dist/open-chat-studio-widget/p-3dc66a9a.js.map +1 -0
- package/dist/types/components/ocs-chat/heroicons.d.ts +4 -1
- package/dist/types/components/ocs-chat/ocs-chat.d.ts +51 -9
- package/dist/types/components.d.ts +24 -0
- package/package.json +1 -1
- package/dist/cjs/index-bcb28089.js.map +0 -1
- package/dist/esm/index-205c77bc.js.map +0 -1
- package/dist/open-chat-studio-widget/p-5d6bd56a.entry.js +0 -4
- package/dist/open-chat-studio-widget/p-5d6bd56a.entry.js.map +0 -1
- package/dist/open-chat-studio-widget/p-78d09c6b.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1
2
|
import { Host, h } from "@stencil/core";
|
|
2
|
-
import { XMarkIcon, GripDotsVerticalIcon,
|
|
3
|
+
import { XMarkIcon, GripDotsVerticalIcon, PlusWithCircleIcon, ArrowsPointingOutIcon, ArrowsPointingInIcon, PaperClipIcon, CheckDocumentIcon, XIcon } from "./heroicons";
|
|
3
4
|
import { renderMarkdownSync as renderMarkdownComplete } from "../../utils/markdown";
|
|
4
5
|
import { getCSRFToken } from "../../utils/cookies";
|
|
5
6
|
import { varToPixels } from "../../utils/utils";
|
|
@@ -13,6 +14,10 @@ export class OcsChat {
|
|
|
13
14
|
* The shape of the chat button. 'round' makes it circular, 'square' keeps it rectangular.
|
|
14
15
|
*/
|
|
15
16
|
this.buttonShape = 'square';
|
|
17
|
+
/**
|
|
18
|
+
* The message to display in the new chat confirmation dialog.
|
|
19
|
+
*/
|
|
20
|
+
this.newChatConfirmationMessage = "Starting a new chat will clear your current conversation. Continue?";
|
|
16
21
|
/**
|
|
17
22
|
* Whether the chat widget is visible on load.
|
|
18
23
|
*/
|
|
@@ -34,24 +39,34 @@ export class OcsChat {
|
|
|
34
39
|
* Allow the user to make the chat window full screen.
|
|
35
40
|
*/
|
|
36
41
|
this.allowFullScreen = true;
|
|
37
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Allow the user to attach files to their messages.
|
|
44
|
+
*/
|
|
45
|
+
this.allowAttachments = false;
|
|
46
|
+
/**
|
|
47
|
+
* The text to display while the assistant is typing/preparing a response.
|
|
48
|
+
*/
|
|
49
|
+
this.typingIndicatorText = "Preparing response";
|
|
38
50
|
this.error = "";
|
|
39
51
|
this.messages = [];
|
|
40
52
|
this.isLoading = false;
|
|
41
53
|
this.isTyping = false;
|
|
42
54
|
this.messageInput = "";
|
|
43
|
-
this.
|
|
55
|
+
this.currentPollTaskId = "";
|
|
44
56
|
this.isDragging = false;
|
|
45
57
|
this.dragOffset = { x: 0, y: 0 };
|
|
46
58
|
this.windowPosition = { x: 0, y: 0 };
|
|
47
59
|
this.fullscreenPosition = { x: 0 };
|
|
48
|
-
this.showStarterQuestions = true;
|
|
49
60
|
this.parsedWelcomeMessages = [];
|
|
50
61
|
this.parsedStarterQuestions = [];
|
|
51
62
|
this.isFullscreen = false;
|
|
63
|
+
this.showNewChatConfirmation = false;
|
|
64
|
+
this.selectedFiles = [];
|
|
65
|
+
this.isUploadingFiles = false;
|
|
52
66
|
this.chatWindowHeight = 600;
|
|
53
67
|
this.chatWindowWidth = 450;
|
|
54
68
|
this.chatWindowFullscreenWidth = 1024;
|
|
69
|
+
this.positionInitialized = false;
|
|
55
70
|
this.handleMouseDown = (event) => {
|
|
56
71
|
if (!this.isFullscreen && window.innerWidth < OcsChat.MOBILE_BREAKPOINT)
|
|
57
72
|
return;
|
|
@@ -96,11 +111,11 @@ export class OcsChat {
|
|
|
96
111
|
this.endDrag();
|
|
97
112
|
};
|
|
98
113
|
this.handleWindowResize = () => {
|
|
114
|
+
this.positionInitialized = false;
|
|
99
115
|
this.initializePosition();
|
|
100
116
|
};
|
|
101
117
|
}
|
|
102
118
|
componentWillLoad() {
|
|
103
|
-
this.loaded = this.visible;
|
|
104
119
|
if (!this.chatbotId) {
|
|
105
120
|
this.error = 'Chatbot ID is required';
|
|
106
121
|
return;
|
|
@@ -111,13 +126,22 @@ export class OcsChat {
|
|
|
111
126
|
if (sessionId && messages) {
|
|
112
127
|
this.sessionId = sessionId;
|
|
113
128
|
this.messages = messages;
|
|
114
|
-
this.showStarterQuestions = messages.length === 0;
|
|
115
129
|
}
|
|
116
130
|
}
|
|
117
131
|
this.parseWelcomeMessages();
|
|
118
132
|
this.parseStarterQuestions();
|
|
119
133
|
}
|
|
120
134
|
componentDidLoad() {
|
|
135
|
+
const computedStyle = getComputedStyle(this.host);
|
|
136
|
+
const windowHeightVar = computedStyle.getPropertyValue('--chat-window-height');
|
|
137
|
+
const windowWidthVar = computedStyle.getPropertyValue('--chat-window-width');
|
|
138
|
+
const fullscreenWidthVar = computedStyle.getPropertyValue('--chat-window-fullscreen-width');
|
|
139
|
+
this.chatWindowHeight = varToPixels(windowHeightVar, window.innerHeight, this.chatWindowHeight);
|
|
140
|
+
this.chatWindowWidth = varToPixels(windowWidthVar, window.innerWidth, this.chatWindowWidth);
|
|
141
|
+
this.chatWindowFullscreenWidth = varToPixels(fullscreenWidthVar, window.innerWidth, this.chatWindowFullscreenWidth);
|
|
142
|
+
if (this.visible) {
|
|
143
|
+
this.initializePosition();
|
|
144
|
+
}
|
|
121
145
|
// Only auto-start session if we don't have an existing one
|
|
122
146
|
if (this.visible && !this.sessionId) {
|
|
123
147
|
this.startSession();
|
|
@@ -126,14 +150,6 @@ export class OcsChat {
|
|
|
126
150
|
// Resume polling for existing session
|
|
127
151
|
this.startPolling();
|
|
128
152
|
}
|
|
129
|
-
const computedStyle = getComputedStyle(this.host);
|
|
130
|
-
const windowHeightVar = computedStyle.getPropertyValue('--chat-window-height');
|
|
131
|
-
const windowWidthVar = computedStyle.getPropertyValue('--chat-window-width');
|
|
132
|
-
const fullscreenWidthVar = computedStyle.getPropertyValue('--chat-window-fullscreen-width');
|
|
133
|
-
this.chatWindowHeight = varToPixels(windowHeightVar, window.innerHeight, this.chatWindowHeight);
|
|
134
|
-
this.chatWindowWidth = varToPixels(windowWidthVar, window.innerWidth, this.chatWindowWidth);
|
|
135
|
-
this.chatWindowFullscreenWidth = varToPixels(fullscreenWidthVar, window.innerWidth, this.chatWindowFullscreenWidth);
|
|
136
|
-
this.initializePosition();
|
|
137
153
|
window.addEventListener('resize', this.handleWindowResize);
|
|
138
154
|
}
|
|
139
155
|
disconnectedCallback() {
|
|
@@ -141,6 +157,26 @@ export class OcsChat {
|
|
|
141
157
|
this.removeEventListeners();
|
|
142
158
|
window.removeEventListener('resize', this.handleWindowResize);
|
|
143
159
|
}
|
|
160
|
+
addErrorMessage(errorText) {
|
|
161
|
+
const errorMessage = {
|
|
162
|
+
created_at: new Date().toISOString(),
|
|
163
|
+
role: 'system',
|
|
164
|
+
content: `**Error:** ${errorText}\nPlease try again.`,
|
|
165
|
+
attachments: []
|
|
166
|
+
};
|
|
167
|
+
this.messages = [...this.messages, errorMessage];
|
|
168
|
+
this.saveSessionToStorage();
|
|
169
|
+
this.scrollToBottom();
|
|
170
|
+
}
|
|
171
|
+
handleError(errorText) {
|
|
172
|
+
// show as system message
|
|
173
|
+
this.addErrorMessage(errorText);
|
|
174
|
+
// Clear any loading/typing states
|
|
175
|
+
this.isLoading = false;
|
|
176
|
+
this.isTyping = false;
|
|
177
|
+
this.isUploadingFiles = false;
|
|
178
|
+
this.currentPollTaskId = '';
|
|
179
|
+
}
|
|
144
180
|
parseJSONProp(propValue, propName) {
|
|
145
181
|
try {
|
|
146
182
|
if (propValue) {
|
|
@@ -165,11 +201,11 @@ export class OcsChat {
|
|
|
165
201
|
this.parsedStarterQuestions = this.parseJSONProp(this.starterQuestions, 'starter questions');
|
|
166
202
|
}
|
|
167
203
|
cleanup() {
|
|
168
|
-
if (this.
|
|
169
|
-
clearInterval(this.
|
|
170
|
-
this.
|
|
204
|
+
if (this.pollingIntervalRef) {
|
|
205
|
+
clearInterval(this.pollingIntervalRef);
|
|
206
|
+
this.pollingIntervalRef = undefined;
|
|
171
207
|
}
|
|
172
|
-
this.
|
|
208
|
+
this.currentPollTaskId = '';
|
|
173
209
|
}
|
|
174
210
|
getApiBaseUrl() {
|
|
175
211
|
return this.apiBaseUrl || window.location.origin;
|
|
@@ -187,7 +223,6 @@ export class OcsChat {
|
|
|
187
223
|
async startSession() {
|
|
188
224
|
try {
|
|
189
225
|
this.isLoading = true;
|
|
190
|
-
this.error = '';
|
|
191
226
|
const userId = this.getOrGenerateUserId();
|
|
192
227
|
const requestBody = {
|
|
193
228
|
chatbot_id: this.chatbotId,
|
|
@@ -206,7 +241,8 @@ export class OcsChat {
|
|
|
206
241
|
body: JSON.stringify(requestBody)
|
|
207
242
|
});
|
|
208
243
|
if (!response.ok) {
|
|
209
|
-
|
|
244
|
+
this.handleError(`Failed to start session: ${response.statusText}`);
|
|
245
|
+
return;
|
|
210
246
|
}
|
|
211
247
|
const data = await response.json();
|
|
212
248
|
this.sessionId = data.session_id;
|
|
@@ -214,24 +250,99 @@ export class OcsChat {
|
|
|
214
250
|
// Handle seed message if present
|
|
215
251
|
if (data.seed_message_task_id) {
|
|
216
252
|
this.isTyping = true; // Show typing indicator for seed message
|
|
217
|
-
|
|
253
|
+
this.currentPollTaskId = data.seed_message_task_id;
|
|
254
|
+
await this.pollTaskResponse();
|
|
218
255
|
}
|
|
219
256
|
// Start polling for messages
|
|
220
257
|
this.startPolling();
|
|
221
258
|
}
|
|
222
259
|
catch (error) {
|
|
223
|
-
this.
|
|
260
|
+
this.handleError('Failed to start chat session');
|
|
224
261
|
}
|
|
225
262
|
finally {
|
|
226
263
|
this.isLoading = false;
|
|
227
264
|
}
|
|
228
265
|
}
|
|
266
|
+
markPendingFilesWithError(errorMessage) {
|
|
267
|
+
this.selectedFiles = this.selectedFiles.map(sf => {
|
|
268
|
+
if (!sf.error && !sf.uploaded) {
|
|
269
|
+
return Object.assign(Object.assign({}, sf), { error: errorMessage });
|
|
270
|
+
}
|
|
271
|
+
return sf;
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
async uploadFiles() {
|
|
275
|
+
if (this.selectedFiles.length === 0 || !this.sessionId || !this.allowAttachments) {
|
|
276
|
+
return [];
|
|
277
|
+
}
|
|
278
|
+
this.isUploadingFiles = true;
|
|
279
|
+
const uploadedIds = [];
|
|
280
|
+
try {
|
|
281
|
+
const formData = new FormData();
|
|
282
|
+
// Add all files to form data
|
|
283
|
+
for (const selectedFile of this.selectedFiles) {
|
|
284
|
+
if (!selectedFile.error && !selectedFile.uploaded) {
|
|
285
|
+
formData.append('files', selectedFile.file);
|
|
286
|
+
}
|
|
287
|
+
else if (selectedFile.uploaded) {
|
|
288
|
+
uploadedIds.push(selectedFile.uploaded.id);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Add user ID and name to the form data
|
|
292
|
+
const userId = this.getOrGenerateUserId();
|
|
293
|
+
formData.append('participant_remote_id', userId);
|
|
294
|
+
if (this.userName) {
|
|
295
|
+
formData.append('participant_name', this.userName);
|
|
296
|
+
}
|
|
297
|
+
// Only upload if there are new files
|
|
298
|
+
if (formData.has('files')) {
|
|
299
|
+
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/upload/`, {
|
|
300
|
+
method: 'POST',
|
|
301
|
+
body: formData,
|
|
302
|
+
});
|
|
303
|
+
if (!response.ok) {
|
|
304
|
+
const errorData = await response.json();
|
|
305
|
+
const errorMessage = errorData.error || 'Failed to upload files';
|
|
306
|
+
this.markPendingFilesWithError(errorMessage);
|
|
307
|
+
return uploadedIds;
|
|
308
|
+
}
|
|
309
|
+
const data = await response.json();
|
|
310
|
+
// Update selected files with upload results
|
|
311
|
+
let fileIndex = 0;
|
|
312
|
+
this.selectedFiles = this.selectedFiles.map(sf => {
|
|
313
|
+
if (!sf.error && !sf.uploaded) {
|
|
314
|
+
return Object.assign(Object.assign({}, sf), { uploaded: data.files[fileIndex++] });
|
|
315
|
+
}
|
|
316
|
+
return sf;
|
|
317
|
+
});
|
|
318
|
+
uploadedIds.push(...data.files.map((f) => f.id));
|
|
319
|
+
}
|
|
320
|
+
return uploadedIds;
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';
|
|
324
|
+
this.markPendingFilesWithError(errorMessage);
|
|
325
|
+
return uploadedIds;
|
|
326
|
+
}
|
|
327
|
+
finally {
|
|
328
|
+
this.isUploadingFiles = false;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
229
331
|
async sendMessage(message) {
|
|
230
332
|
if (!this.sessionId || !message.trim())
|
|
231
333
|
return;
|
|
232
|
-
// Hide starter questions on any user interaction
|
|
233
|
-
this.showStarterQuestions = false;
|
|
234
334
|
try {
|
|
335
|
+
let attachmentIds = [];
|
|
336
|
+
if (this.allowAttachments && this.selectedFiles.length > 0) {
|
|
337
|
+
attachmentIds = await this.uploadFiles();
|
|
338
|
+
// Check if any files have errors after upload attempt
|
|
339
|
+
const hasErrors = this.selectedFiles.some(sf => sf.error);
|
|
340
|
+
if (hasErrors) {
|
|
341
|
+
// Don't send the message, let user fix file issues first
|
|
342
|
+
this.handleError('Please remove or fix file errors before sending your message.');
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
235
346
|
// If this is the first user message and there are welcome messages,
|
|
236
347
|
// add them to chat history as assistant messages
|
|
237
348
|
if (this.messages.length === 0 && this.parsedWelcomeMessages.length > 0) {
|
|
@@ -244,23 +355,36 @@ export class OcsChat {
|
|
|
244
355
|
}));
|
|
245
356
|
this.messages = [...this.messages, ...welcomeMessages];
|
|
246
357
|
}
|
|
247
|
-
// Add user message immediately
|
|
358
|
+
// Add user message immediately with attachments info
|
|
248
359
|
const userMessage = {
|
|
249
360
|
created_at: new Date().toISOString(),
|
|
250
361
|
role: 'user',
|
|
251
362
|
content: message.trim(),
|
|
252
|
-
attachments:
|
|
363
|
+
attachments: this.allowAttachments ? this.selectedFiles
|
|
364
|
+
.filter(sf => !sf.error && sf.uploaded)
|
|
365
|
+
.map(sf => ({
|
|
366
|
+
name: sf.file.name,
|
|
367
|
+
content_type: sf.file.type,
|
|
368
|
+
size: sf.file.size,
|
|
369
|
+
})) : []
|
|
253
370
|
};
|
|
254
371
|
this.messages = [...this.messages, userMessage];
|
|
255
372
|
this.saveSessionToStorage();
|
|
256
373
|
this.messageInput = '';
|
|
374
|
+
if (this.allowAttachments) {
|
|
375
|
+
this.selectedFiles = []; // Clear selected files after sending
|
|
376
|
+
}
|
|
257
377
|
this.scrollToBottom();
|
|
258
378
|
// Start typing indicator - it will stay on during task polling
|
|
259
379
|
this.isTyping = true;
|
|
380
|
+
const requestBody = { message: message.trim() };
|
|
381
|
+
if (this.allowAttachments && attachmentIds.length > 0) {
|
|
382
|
+
requestBody.attachment_ids = attachmentIds;
|
|
383
|
+
}
|
|
260
384
|
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/message/`, {
|
|
261
385
|
method: 'POST',
|
|
262
386
|
headers: this.getApiHeaders(),
|
|
263
|
-
body: JSON.stringify(
|
|
387
|
+
body: JSON.stringify(requestBody)
|
|
264
388
|
});
|
|
265
389
|
if (!response.ok) {
|
|
266
390
|
throw new Error(`Failed to send message: ${response.statusText}`);
|
|
@@ -270,27 +394,28 @@ export class OcsChat {
|
|
|
270
394
|
throw new Error(data.error || 'Failed to send message');
|
|
271
395
|
}
|
|
272
396
|
// Poll for the response - typing indicator will be managed in pollTaskResponse
|
|
273
|
-
|
|
397
|
+
this.currentPollTaskId = data.task_id;
|
|
398
|
+
await this.pollTaskResponse();
|
|
274
399
|
}
|
|
275
400
|
catch (error) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
this.isTyping = false;
|
|
401
|
+
const errorText = error instanceof Error ? error.message : 'Failed to send message';
|
|
402
|
+
this.handleError(errorText);
|
|
279
403
|
}
|
|
280
404
|
}
|
|
281
405
|
handleStarterQuestionClick(question) {
|
|
282
406
|
this.sendMessage(question);
|
|
283
407
|
}
|
|
284
|
-
async pollTaskResponse(
|
|
285
|
-
if (!this.sessionId)
|
|
408
|
+
async pollTaskResponse() {
|
|
409
|
+
if (!this.sessionId || !this.currentPollTaskId)
|
|
286
410
|
return;
|
|
287
411
|
// Stop message polling while task polling is active
|
|
288
|
-
this.isTaskPolling = true;
|
|
289
412
|
this.pauseMessagePolling();
|
|
290
413
|
let attempts = 0;
|
|
291
414
|
const poll = async () => {
|
|
415
|
+
if (!this.sessionId || !this.currentPollTaskId)
|
|
416
|
+
return;
|
|
292
417
|
try {
|
|
293
|
-
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/${
|
|
418
|
+
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/${this.currentPollTaskId}/poll/`);
|
|
294
419
|
if (!response.ok) {
|
|
295
420
|
throw new Error(`Failed to poll task: ${response.statusText}`);
|
|
296
421
|
}
|
|
@@ -304,7 +429,7 @@ export class OcsChat {
|
|
|
304
429
|
this.scrollToBottom();
|
|
305
430
|
// Task polling complete, clear typing indicator and resume message polling
|
|
306
431
|
this.isTyping = false;
|
|
307
|
-
this.
|
|
432
|
+
this.currentPollTaskId = '';
|
|
308
433
|
this.resumeMessagePolling();
|
|
309
434
|
this.focusInput();
|
|
310
435
|
return;
|
|
@@ -314,36 +439,47 @@ export class OcsChat {
|
|
|
314
439
|
setTimeout(poll, OcsChat.TASK_POLLING_INTERVAL_MS);
|
|
315
440
|
}
|
|
316
441
|
else if (attempts >= OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
|
|
317
|
-
// Task polling timed out
|
|
442
|
+
// Task polling timed out - add timeout message and resume polling
|
|
443
|
+
const timeoutMessage = {
|
|
444
|
+
created_at: new Date().toISOString(),
|
|
445
|
+
role: 'system',
|
|
446
|
+
content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
|
|
447
|
+
attachments: []
|
|
448
|
+
};
|
|
449
|
+
this.messages = [...this.messages, timeoutMessage];
|
|
450
|
+
this.saveSessionToStorage();
|
|
451
|
+
this.scrollToBottom();
|
|
452
|
+
// Clear typing indicator and resume message polling
|
|
318
453
|
this.isTyping = false;
|
|
319
|
-
this.
|
|
454
|
+
this.currentPollTaskId = '';
|
|
320
455
|
this.resumeMessagePolling();
|
|
456
|
+
this.focusInput();
|
|
321
457
|
}
|
|
322
458
|
}
|
|
323
459
|
catch (error) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
this.
|
|
460
|
+
const errorText = error instanceof Error ? error.message : 'Failed to get response';
|
|
461
|
+
this.handleError(errorText);
|
|
462
|
+
// Clear states and resume polling
|
|
463
|
+
this.currentPollTaskId = '';
|
|
328
464
|
this.resumeMessagePolling();
|
|
329
465
|
}
|
|
330
466
|
};
|
|
331
467
|
await poll();
|
|
332
468
|
}
|
|
333
469
|
startPolling() {
|
|
334
|
-
if (this.
|
|
470
|
+
if (this.pollingIntervalRef)
|
|
335
471
|
return;
|
|
336
|
-
this.
|
|
472
|
+
this.pollingIntervalRef = setInterval(async () => {
|
|
337
473
|
// Only poll for messages if not currently polling for a task
|
|
338
|
-
if (!this.
|
|
474
|
+
if (!this.currentPollTaskId) {
|
|
339
475
|
await this.pollForMessages();
|
|
340
476
|
}
|
|
341
477
|
}, OcsChat.MESSAGE_POLLING_INTERVAL_MS);
|
|
342
478
|
}
|
|
343
479
|
pauseMessagePolling() {
|
|
344
|
-
if (this.
|
|
345
|
-
clearInterval(this.
|
|
346
|
-
this.
|
|
480
|
+
if (this.pollingIntervalRef) {
|
|
481
|
+
clearInterval(this.pollingIntervalRef);
|
|
482
|
+
this.pollingIntervalRef = undefined;
|
|
347
483
|
}
|
|
348
484
|
}
|
|
349
485
|
resumeMessagePolling() {
|
|
@@ -368,15 +504,11 @@ export class OcsChat {
|
|
|
368
504
|
this.scrollToBottom();
|
|
369
505
|
this.focusInput();
|
|
370
506
|
}
|
|
371
|
-
this.lastPollTime = new Date();
|
|
372
507
|
}
|
|
373
|
-
catch (
|
|
508
|
+
catch (_a) {
|
|
374
509
|
// Silently fail for polling
|
|
375
510
|
}
|
|
376
511
|
}
|
|
377
|
-
clearError() {
|
|
378
|
-
this.error = '';
|
|
379
|
-
}
|
|
380
512
|
scrollToBottom() {
|
|
381
513
|
setTimeout(() => {
|
|
382
514
|
if (this.messageListRef) {
|
|
@@ -399,24 +531,89 @@ export class OcsChat {
|
|
|
399
531
|
}
|
|
400
532
|
handleInputChange(event) {
|
|
401
533
|
this.messageInput = event.target.value;
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
534
|
+
}
|
|
535
|
+
handleFileSelect(event) {
|
|
536
|
+
var _a;
|
|
537
|
+
if (!this.allowAttachments)
|
|
538
|
+
return;
|
|
539
|
+
const input = event.target;
|
|
540
|
+
if (!input.files || input.files.length === 0)
|
|
541
|
+
return;
|
|
542
|
+
const newFiles = [];
|
|
543
|
+
let totalSize = this.selectedFiles.reduce((sum, f) => sum + f.file.size, 0);
|
|
544
|
+
for (let i = 0; i < input.files.length; i++) {
|
|
545
|
+
const file = input.files[i];
|
|
546
|
+
const ext = '.' + ((_a = file.name.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase());
|
|
547
|
+
if (!OcsChat.SUPPORTED_FILE_EXTENSIONS.includes(ext)) {
|
|
548
|
+
newFiles.push({
|
|
549
|
+
file,
|
|
550
|
+
error: `File type ${ext} not supported`
|
|
551
|
+
});
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
const fileSizeMB = file.size / (1024 * 1024);
|
|
555
|
+
if (fileSizeMB > OcsChat.MAX_FILE_SIZE_MB) {
|
|
556
|
+
newFiles.push({
|
|
557
|
+
file,
|
|
558
|
+
error: `File exceeds ${OcsChat.MAX_FILE_SIZE_MB}MB limit`
|
|
559
|
+
});
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
totalSize += file.size;
|
|
563
|
+
const totalSizeMB = totalSize / (1024 * 1024);
|
|
564
|
+
if (totalSizeMB > OcsChat.MAX_TOTAL_SIZE_MB) {
|
|
565
|
+
newFiles.push({
|
|
566
|
+
file,
|
|
567
|
+
error: `Total size exceeds ${OcsChat.MAX_TOTAL_SIZE_MB}MB limit`
|
|
568
|
+
});
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
newFiles.push({ file });
|
|
572
|
+
}
|
|
573
|
+
this.selectedFiles = [...this.selectedFiles, ...newFiles];
|
|
574
|
+
input.value = '';
|
|
575
|
+
}
|
|
576
|
+
removeSelectedFile(index) {
|
|
577
|
+
if (!this.allowAttachments)
|
|
578
|
+
return;
|
|
579
|
+
this.selectedFiles = this.selectedFiles.filter((_, i) => i !== index);
|
|
580
|
+
}
|
|
581
|
+
formatFileSize(bytes) {
|
|
582
|
+
if (bytes === 0)
|
|
583
|
+
return '0 KB';
|
|
584
|
+
const k = 1024;
|
|
585
|
+
if (bytes < k * k) {
|
|
586
|
+
// Less than 1MB, show in KB
|
|
587
|
+
return Math.round(bytes / k * 100) / 100 + ' KB';
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
return Math.round(bytes / (k * k) * 100) / 100 + ' MB';
|
|
405
591
|
}
|
|
406
592
|
}
|
|
407
593
|
formatTime(dateString) {
|
|
408
594
|
const date = new Date(dateString);
|
|
409
595
|
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
410
596
|
}
|
|
411
|
-
|
|
597
|
+
toggleWindowVisibility() {
|
|
412
598
|
this.visible = !this.visible;
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Watch for changes to the `visible` attribute and update accordingly.
|
|
602
|
+
*
|
|
603
|
+
* @param visible - The new value for the field.
|
|
604
|
+
*/
|
|
605
|
+
async visibilityHandler(visible) {
|
|
606
|
+
if (visible) {
|
|
607
|
+
this.initializePosition();
|
|
608
|
+
}
|
|
609
|
+
if (visible && !this.sessionId) {
|
|
416
610
|
await this.startSession();
|
|
417
611
|
}
|
|
418
|
-
else if (!
|
|
419
|
-
|
|
612
|
+
else if (!visible) {
|
|
613
|
+
this.pauseMessagePolling();
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
this.resumeMessagePolling();
|
|
420
617
|
}
|
|
421
618
|
}
|
|
422
619
|
setPosition(position) {
|
|
@@ -437,6 +634,7 @@ export class OcsChat {
|
|
|
437
634
|
const actualChatWidth = Math.min(windowWidth, this.chatWindowFullscreenWidth);
|
|
438
635
|
const centeredX = (windowWidth - actualChatWidth) / 2;
|
|
439
636
|
const maxOffset = (windowWidth - actualChatWidth) / 2;
|
|
637
|
+
console.log(windowWidth, actualChatWidth, centeredX, maxOffset);
|
|
440
638
|
return { windowWidth, actualChatWidth, centeredX, maxOffset };
|
|
441
639
|
}
|
|
442
640
|
getPositionStyles() {
|
|
@@ -455,6 +653,10 @@ export class OcsChat {
|
|
|
455
653
|
};
|
|
456
654
|
}
|
|
457
655
|
initializePosition() {
|
|
656
|
+
if (this.positionInitialized) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
this.positionInitialized = true;
|
|
458
660
|
const windowWidth = window.innerWidth;
|
|
459
661
|
const windowHeight = window.innerHeight;
|
|
460
662
|
const chatWidth = windowWidth < OcsChat.MOBILE_BREAKPOINT ? windowWidth : this.chatWindowWidth;
|
|
@@ -569,10 +771,10 @@ export class OcsChat {
|
|
|
569
771
|
const iconSrc = hasCustomIcon ? this.iconUrl : this.getDefaultIconUrl();
|
|
570
772
|
const buttonClasses = this.getButtonClasses();
|
|
571
773
|
if (hasText) {
|
|
572
|
-
return (h("button", { class: buttonClasses, onClick: () => this.
|
|
774
|
+
return (h("button", { class: buttonClasses, onClick: () => this.toggleWindowVisibility(), "aria-label": `Open chat - ${this.buttonText}`, title: this.buttonText }, h("img", { src: iconSrc, alt: "" }), h("span", null, this.buttonText)));
|
|
573
775
|
}
|
|
574
776
|
else {
|
|
575
|
-
return (h("button", { class: buttonClasses, onClick: () => this.
|
|
777
|
+
return (h("button", { class: buttonClasses, onClick: () => this.toggleWindowVisibility(), "aria-label": "Open chat", title: "Open chat" }, h("img", { src: iconSrc, alt: "Chat" })));
|
|
576
778
|
}
|
|
577
779
|
}
|
|
578
780
|
getStorageKeys() {
|
|
@@ -676,13 +878,25 @@ export class OcsChat {
|
|
|
676
878
|
return false;
|
|
677
879
|
}
|
|
678
880
|
}
|
|
679
|
-
|
|
881
|
+
showConfirmationDialog() {
|
|
882
|
+
this.showNewChatConfirmation = true;
|
|
883
|
+
}
|
|
884
|
+
hideConfirmationDialog() {
|
|
885
|
+
this.showNewChatConfirmation = false;
|
|
886
|
+
}
|
|
887
|
+
async confirmNewChat() {
|
|
888
|
+
this.hideConfirmationDialog();
|
|
889
|
+
await this.actuallyStartNewChat();
|
|
890
|
+
}
|
|
891
|
+
async actuallyStartNewChat() {
|
|
680
892
|
this.clearSessionStorage();
|
|
681
893
|
this.sessionId = undefined;
|
|
682
894
|
this.messages = [];
|
|
683
|
-
this.showStarterQuestions = true;
|
|
684
895
|
this.isTyping = false;
|
|
685
|
-
this.
|
|
896
|
+
this.currentPollTaskId = '';
|
|
897
|
+
if (this.allowAttachments) {
|
|
898
|
+
this.selectedFiles = [];
|
|
899
|
+
}
|
|
686
900
|
this.cleanup();
|
|
687
901
|
await this.startSession();
|
|
688
902
|
}
|
|
@@ -692,16 +906,22 @@ export class OcsChat {
|
|
|
692
906
|
this.fullscreenPosition = { x: 0 };
|
|
693
907
|
}
|
|
694
908
|
render() {
|
|
695
|
-
|
|
909
|
+
// Only show error state for critical errors that prevent the widget from functioning
|
|
910
|
+
if (this.error && !this.sessionId) {
|
|
696
911
|
return (h(Host, null, h("p", { class: "error-message" }, this.error)));
|
|
697
912
|
}
|
|
698
|
-
return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.headerText), h("div", { class: "header-buttons" }, this.allowFullScreen && h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? "Exit fullscreen" : "Enter fullscreen", "aria-label": this.isFullscreen ? "Exit fullscreen" : "Enter fullscreen" }, this.isFullscreen ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null)),
|
|
913
|
+
return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.headerText), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: "Start new chat", "aria-label": "Start new chat" }, h(PlusWithCircleIcon, null))), this.allowFullScreen && h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? "Exit fullscreen" : "Enter fullscreen", "aria-label": this.isFullscreen ? "Exit fullscreen" : "Enter fullscreen" }, this.isFullscreen ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null)), h("button", { class: "header-button", onClick: () => this.visible = false, "aria-label": "Close" }, h(XMarkIcon, null)))), this.showNewChatConfirmation && (h("div", { class: "confirmation-overlay" }, h("div", { class: "confirmation-dialog" }, h("div", { class: "confirmation-content" }, h("h3", { class: "confirmation-title" }, "Start New Chat"), h("p", { class: "confirmation-message" }, this.newChatConfirmationMessage), h("div", { class: "confirmation-buttons" }, h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, "Cancel"), h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, "Continue")))))), h("div", { class: "chat-content" }, this.isLoading && !this.sessionId && (h("div", { class: "loading-container" }, h("div", { class: "loading-spinner" }), h("span", { class: "loading-text" }, "Starting chat..."))), (h("div", { ref: (el) => this.messageListRef = el, class: "messages-container" }, this.messages.length === 0 && this.parsedWelcomeMessages.length > 0 && (h("div", { class: "welcome-messages" }, this.parsedWelcomeMessages.map((message, index) => (h("div", { key: `welcome-${index}`, class: "message-row message-row-assistant" }, h("div", { class: "message-bubble message-bubble-assistant" }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message) }))))))), this.messages.map((message, index) => (h("div", { key: index, class: `message-row ${message.role === 'user' ? 'message-row-user' : 'message-row-assistant'}` }, h("div", { class: `message-bubble ${message.role === 'user'
|
|
699
914
|
? 'message-bubble-user'
|
|
700
915
|
: message.role === 'assistant'
|
|
701
916
|
? 'message-bubble-assistant'
|
|
702
|
-
: 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("
|
|
917
|
+
: 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, h("span", { class: "message-attachment-icon" }, h(PaperClipIcon, null)), h("span", { class: "message-attachment-name" }, attachment.name)))))), h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (h("div", null, h("div", { class: "typing-indicator" }, h("div", { class: "typing-progress" })), h("div", { class: "typing-text" }, h("span", null, this.typingIndicatorText), h("span", { class: "typing-dots" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (h("div", { class: "starter-questions" }, this.parsedStarterQuestions.map((question, index) => (h("div", { key: `starter-${index}`, class: "starter-question-row" }, h("button", { class: "starter-question", onClick: () => this.handleStarterQuestionClick(question) }, question)))))), this.allowAttachments && this.selectedFiles.length > 0 && (h("div", { class: "selected-files-container" }, h("div", { class: "space-y-[0.25em]" }, this.selectedFiles.map((selectedFile, index) => (h("div", { key: index, class: "selected-file-item" }, h("div", { class: "flex items-center gap-[0.5em]" }, h("span", { class: "selected-file-icon" }, h(PaperClipIcon, null)), h("span", null, selectedFile.file.name), h("span", { class: "selected-file-size" }, "(", this.formatFileSize(selectedFile.file.size), ")"), selectedFile.error && (h("span", { class: "selected-file-error" }, selectedFile.error)), selectedFile.uploaded && (h("span", { class: "selected-file-success-icon" }, h(CheckDocumentIcon, null)))), h("button", { onClick: () => this.removeSelectedFile(index), class: "selected-file-remove-button", "aria-label": "Remove file" }, h(XIcon, null)))))))), this.sessionId && (h("div", { class: "input-area" }, h("div", { class: "input-container" }, h("textarea", { ref: (el) => this.textareaRef = el, class: "message-textarea", rows: 1, placeholder: "Type your message...", value: this.messageInput, onInput: (e) => this.handleInputChange(e), onKeyPress: (e) => this.handleKeyPress(e), disabled: this.isTyping || this.isUploadingFiles }), this.allowAttachments && (h("input", { ref: (el) => {
|
|
918
|
+
// Unclear why but after removing all attachments this is being set to `null`.
|
|
919
|
+
if (el) {
|
|
920
|
+
this.fileInputRef = el;
|
|
921
|
+
}
|
|
922
|
+
}, id: "ocs-file-input", type: "file", multiple: true, accept: OcsChat.SUPPORTED_FILE_EXTENSIONS.join(','), onChange: (e) => this.handleFileSelect(e), class: "hidden" })), this.allowAttachments && (h("button", { class: "file-attachment-button", onClick: () => { var _a; return (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: this.isTyping || this.isUploadingFiles, title: "Attach files", "aria-label": "Attach files" }, h(PaperClipIcon, null))), h("button", { class: `send-button ${!this.isTyping && !!this.messageInput.trim()
|
|
703
923
|
? 'send-button-enabled'
|
|
704
|
-
: 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || !this.messageInput.trim() },
|
|
924
|
+
: 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || !this.messageInput.trim() }, this.isUploadingFiles ? 'Uploading...' : 'Send')))), h("div", { class: "flex items-center justify-center text-[0.8em] font-light w-full text-slate-500 py-[2px]" }, h("p", null, "Powered by ", h("a", { class: "underline", href: "https://www.dimagi.com", target: "_blank" }, "Dimagi"))))))));
|
|
705
925
|
}
|
|
706
926
|
static get is() { return "open-chat-studio-widget"; }
|
|
707
927
|
static get encapsulation() { return "shadow"; }
|
|
@@ -833,6 +1053,26 @@ export class OcsChat {
|
|
|
833
1053
|
"attribute": "header-text",
|
|
834
1054
|
"reflect": false
|
|
835
1055
|
},
|
|
1056
|
+
"newChatConfirmationMessage": {
|
|
1057
|
+
"type": "string",
|
|
1058
|
+
"mutable": false,
|
|
1059
|
+
"complexType": {
|
|
1060
|
+
"original": "string",
|
|
1061
|
+
"resolved": "string",
|
|
1062
|
+
"references": {}
|
|
1063
|
+
},
|
|
1064
|
+
"required": false,
|
|
1065
|
+
"optional": true,
|
|
1066
|
+
"docs": {
|
|
1067
|
+
"tags": [],
|
|
1068
|
+
"text": "The message to display in the new chat confirmation dialog."
|
|
1069
|
+
},
|
|
1070
|
+
"getter": false,
|
|
1071
|
+
"setter": false,
|
|
1072
|
+
"attribute": "new-chat-confirmation-message",
|
|
1073
|
+
"reflect": false,
|
|
1074
|
+
"defaultValue": "\"Starting a new chat will clear your current conversation. Continue?\""
|
|
1075
|
+
},
|
|
836
1076
|
"visible": {
|
|
837
1077
|
"type": "boolean",
|
|
838
1078
|
"mutable": true,
|
|
@@ -1008,35 +1248,80 @@ export class OcsChat {
|
|
|
1008
1248
|
"attribute": "allow-full-screen",
|
|
1009
1249
|
"reflect": false,
|
|
1010
1250
|
"defaultValue": "true"
|
|
1251
|
+
},
|
|
1252
|
+
"allowAttachments": {
|
|
1253
|
+
"type": "boolean",
|
|
1254
|
+
"mutable": false,
|
|
1255
|
+
"complexType": {
|
|
1256
|
+
"original": "boolean",
|
|
1257
|
+
"resolved": "boolean",
|
|
1258
|
+
"references": {}
|
|
1259
|
+
},
|
|
1260
|
+
"required": false,
|
|
1261
|
+
"optional": false,
|
|
1262
|
+
"docs": {
|
|
1263
|
+
"tags": [],
|
|
1264
|
+
"text": "Allow the user to attach files to their messages."
|
|
1265
|
+
},
|
|
1266
|
+
"getter": false,
|
|
1267
|
+
"setter": false,
|
|
1268
|
+
"attribute": "allow-attachments",
|
|
1269
|
+
"reflect": false,
|
|
1270
|
+
"defaultValue": "false"
|
|
1271
|
+
},
|
|
1272
|
+
"typingIndicatorText": {
|
|
1273
|
+
"type": "string",
|
|
1274
|
+
"mutable": false,
|
|
1275
|
+
"complexType": {
|
|
1276
|
+
"original": "string",
|
|
1277
|
+
"resolved": "string",
|
|
1278
|
+
"references": {}
|
|
1279
|
+
},
|
|
1280
|
+
"required": false,
|
|
1281
|
+
"optional": true,
|
|
1282
|
+
"docs": {
|
|
1283
|
+
"tags": [],
|
|
1284
|
+
"text": "The text to display while the assistant is typing/preparing a response."
|
|
1285
|
+
},
|
|
1286
|
+
"getter": false,
|
|
1287
|
+
"setter": false,
|
|
1288
|
+
"attribute": "typing-indicator-text",
|
|
1289
|
+
"reflect": false,
|
|
1290
|
+
"defaultValue": "\"Preparing response\""
|
|
1011
1291
|
}
|
|
1012
1292
|
};
|
|
1013
1293
|
}
|
|
1014
1294
|
static get states() {
|
|
1015
1295
|
return {
|
|
1016
|
-
"loaded": {},
|
|
1017
1296
|
"error": {},
|
|
1018
1297
|
"messages": {},
|
|
1019
1298
|
"sessionId": {},
|
|
1020
1299
|
"isLoading": {},
|
|
1021
1300
|
"isTyping": {},
|
|
1022
1301
|
"messageInput": {},
|
|
1023
|
-
"
|
|
1024
|
-
"lastPollTime": {},
|
|
1025
|
-
"isTaskPolling": {},
|
|
1302
|
+
"currentPollTaskId": {},
|
|
1026
1303
|
"isDragging": {},
|
|
1027
1304
|
"dragOffset": {},
|
|
1028
1305
|
"windowPosition": {},
|
|
1029
1306
|
"fullscreenPosition": {},
|
|
1030
|
-
"showStarterQuestions": {},
|
|
1031
1307
|
"parsedWelcomeMessages": {},
|
|
1032
1308
|
"parsedStarterQuestions": {},
|
|
1033
1309
|
"generatedUserId": {},
|
|
1034
|
-
"isFullscreen": {}
|
|
1310
|
+
"isFullscreen": {},
|
|
1311
|
+
"showNewChatConfirmation": {},
|
|
1312
|
+
"selectedFiles": {},
|
|
1313
|
+
"isUploadingFiles": {}
|
|
1035
1314
|
};
|
|
1036
1315
|
}
|
|
1037
1316
|
static get elementRef() { return "host"; }
|
|
1317
|
+
static get watchers() {
|
|
1318
|
+
return [{
|
|
1319
|
+
"propName": "visible",
|
|
1320
|
+
"methodName": "visibilityHandler"
|
|
1321
|
+
}];
|
|
1322
|
+
}
|
|
1038
1323
|
}
|
|
1039
|
-
OcsChat.TASK_POLLING_MAX_ATTEMPTS =
|
|
1324
|
+
OcsChat.TASK_POLLING_MAX_ATTEMPTS = 120;
|
|
1040
1325
|
OcsChat.TASK_POLLING_INTERVAL_MS = 1000;
|
|
1041
1326
|
OcsChat.MESSAGE_POLLING_INTERVAL_MS = 30000;
|
|
1042
1327
|
OcsChat.SCROLL_DELAY_MS = 100;
|
|
@@ -1044,4 +1329,8 @@ OcsChat.FOCUS_DELAY_MS = 100;
|
|
|
1044
1329
|
OcsChat.MOBILE_BREAKPOINT = 640;
|
|
1045
1330
|
OcsChat.WINDOW_MARGIN = 20;
|
|
1046
1331
|
OcsChat.LOCALSTORAGE_TEST_KEY = '__ocs_test__';
|
|
1332
|
+
OcsChat.MAX_FILE_SIZE_MB = 50;
|
|
1333
|
+
OcsChat.MAX_TOTAL_SIZE_MB = 50;
|
|
1334
|
+
OcsChat.SUPPORTED_FILE_EXTENSIONS = ['.txt', '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.csv', '.jpg', '.jpeg',
|
|
1335
|
+
'.png', '.gif', '.bmp', '.webp', '.svg', '.mp4', '.mov', '.avi', '.mp3', '.wav'];
|
|
1047
1336
|
//# sourceMappingURL=ocs-chat.js.map
|