open-chat-studio-widget 0.4.4 → 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 +500 -79
- 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 +380 -84
- package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
- package/dist/collection/utils/cookies.js +28 -0
- package/dist/collection/utils/cookies.js.map +1 -0
- package/dist/components/open-chat-studio-widget.js +509 -84
- 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 +500 -79
- 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 +52 -9
- package/dist/types/components.d.ts +24 -0
- package/dist/types/utils/cookies.d.ts +4 -0
- package/package.json +3 -2
- 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-19d45fe5.entry.js +0 -3
- package/dist/open-chat-studio-widget/p-19d45fe5.entry.js.map +0 -1
- package/dist/open-chat-studio-widget/p-78d09c6b.js.map +0 -1
|
@@ -1,6 +1,8 @@
|
|
|
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";
|
|
5
|
+
import { getCSRFToken } from "../../utils/cookies";
|
|
4
6
|
import { varToPixels } from "../../utils/utils";
|
|
5
7
|
export class OcsChat {
|
|
6
8
|
constructor() {
|
|
@@ -12,6 +14,10 @@ export class OcsChat {
|
|
|
12
14
|
* The shape of the chat button. 'round' makes it circular, 'square' keeps it rectangular.
|
|
13
15
|
*/
|
|
14
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?";
|
|
15
21
|
/**
|
|
16
22
|
* Whether the chat widget is visible on load.
|
|
17
23
|
*/
|
|
@@ -33,24 +39,34 @@ export class OcsChat {
|
|
|
33
39
|
* Allow the user to make the chat window full screen.
|
|
34
40
|
*/
|
|
35
41
|
this.allowFullScreen = true;
|
|
36
|
-
|
|
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";
|
|
37
50
|
this.error = "";
|
|
38
51
|
this.messages = [];
|
|
39
52
|
this.isLoading = false;
|
|
40
53
|
this.isTyping = false;
|
|
41
54
|
this.messageInput = "";
|
|
42
|
-
this.
|
|
55
|
+
this.currentPollTaskId = "";
|
|
43
56
|
this.isDragging = false;
|
|
44
57
|
this.dragOffset = { x: 0, y: 0 };
|
|
45
58
|
this.windowPosition = { x: 0, y: 0 };
|
|
46
59
|
this.fullscreenPosition = { x: 0 };
|
|
47
|
-
this.showStarterQuestions = true;
|
|
48
60
|
this.parsedWelcomeMessages = [];
|
|
49
61
|
this.parsedStarterQuestions = [];
|
|
50
62
|
this.isFullscreen = false;
|
|
63
|
+
this.showNewChatConfirmation = false;
|
|
64
|
+
this.selectedFiles = [];
|
|
65
|
+
this.isUploadingFiles = false;
|
|
51
66
|
this.chatWindowHeight = 600;
|
|
52
67
|
this.chatWindowWidth = 450;
|
|
53
68
|
this.chatWindowFullscreenWidth = 1024;
|
|
69
|
+
this.positionInitialized = false;
|
|
54
70
|
this.handleMouseDown = (event) => {
|
|
55
71
|
if (!this.isFullscreen && window.innerWidth < OcsChat.MOBILE_BREAKPOINT)
|
|
56
72
|
return;
|
|
@@ -95,11 +111,11 @@ export class OcsChat {
|
|
|
95
111
|
this.endDrag();
|
|
96
112
|
};
|
|
97
113
|
this.handleWindowResize = () => {
|
|
114
|
+
this.positionInitialized = false;
|
|
98
115
|
this.initializePosition();
|
|
99
116
|
};
|
|
100
117
|
}
|
|
101
118
|
componentWillLoad() {
|
|
102
|
-
this.loaded = this.visible;
|
|
103
119
|
if (!this.chatbotId) {
|
|
104
120
|
this.error = 'Chatbot ID is required';
|
|
105
121
|
return;
|
|
@@ -110,13 +126,22 @@ export class OcsChat {
|
|
|
110
126
|
if (sessionId && messages) {
|
|
111
127
|
this.sessionId = sessionId;
|
|
112
128
|
this.messages = messages;
|
|
113
|
-
this.showStarterQuestions = messages.length === 0;
|
|
114
129
|
}
|
|
115
130
|
}
|
|
116
131
|
this.parseWelcomeMessages();
|
|
117
132
|
this.parseStarterQuestions();
|
|
118
133
|
}
|
|
119
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
|
+
}
|
|
120
145
|
// Only auto-start session if we don't have an existing one
|
|
121
146
|
if (this.visible && !this.sessionId) {
|
|
122
147
|
this.startSession();
|
|
@@ -125,14 +150,6 @@ export class OcsChat {
|
|
|
125
150
|
// Resume polling for existing session
|
|
126
151
|
this.startPolling();
|
|
127
152
|
}
|
|
128
|
-
const computedStyle = getComputedStyle(this.host);
|
|
129
|
-
const windowHeightVar = computedStyle.getPropertyValue('--chat-window-height');
|
|
130
|
-
const windowWidthVar = computedStyle.getPropertyValue('--chat-window-width');
|
|
131
|
-
const fullscreenWidthVar = computedStyle.getPropertyValue('--chat-window-fullscreen-width');
|
|
132
|
-
this.chatWindowHeight = varToPixels(windowHeightVar, window.innerHeight, this.chatWindowHeight);
|
|
133
|
-
this.chatWindowWidth = varToPixels(windowWidthVar, window.innerWidth, this.chatWindowWidth);
|
|
134
|
-
this.chatWindowFullscreenWidth = varToPixels(fullscreenWidthVar, window.innerWidth, this.chatWindowFullscreenWidth);
|
|
135
|
-
this.initializePosition();
|
|
136
153
|
window.addEventListener('resize', this.handleWindowResize);
|
|
137
154
|
}
|
|
138
155
|
disconnectedCallback() {
|
|
@@ -140,6 +157,26 @@ export class OcsChat {
|
|
|
140
157
|
this.removeEventListeners();
|
|
141
158
|
window.removeEventListener('resize', this.handleWindowResize);
|
|
142
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
|
+
}
|
|
143
180
|
parseJSONProp(propValue, propName) {
|
|
144
181
|
try {
|
|
145
182
|
if (propValue) {
|
|
@@ -164,19 +201,28 @@ export class OcsChat {
|
|
|
164
201
|
this.parsedStarterQuestions = this.parseJSONProp(this.starterQuestions, 'starter questions');
|
|
165
202
|
}
|
|
166
203
|
cleanup() {
|
|
167
|
-
if (this.
|
|
168
|
-
clearInterval(this.
|
|
169
|
-
this.
|
|
204
|
+
if (this.pollingIntervalRef) {
|
|
205
|
+
clearInterval(this.pollingIntervalRef);
|
|
206
|
+
this.pollingIntervalRef = undefined;
|
|
170
207
|
}
|
|
171
|
-
this.
|
|
208
|
+
this.currentPollTaskId = '';
|
|
172
209
|
}
|
|
173
210
|
getApiBaseUrl() {
|
|
174
211
|
return this.apiBaseUrl || window.location.origin;
|
|
175
212
|
}
|
|
213
|
+
getApiHeaders() {
|
|
214
|
+
const headers = {
|
|
215
|
+
'Content-Type': 'application/json',
|
|
216
|
+
};
|
|
217
|
+
const csrfToken = getCSRFToken(this.getApiBaseUrl());
|
|
218
|
+
if (csrfToken) {
|
|
219
|
+
headers['X-CSRFToken'] = csrfToken;
|
|
220
|
+
}
|
|
221
|
+
return headers;
|
|
222
|
+
}
|
|
176
223
|
async startSession() {
|
|
177
224
|
try {
|
|
178
225
|
this.isLoading = true;
|
|
179
|
-
this.error = '';
|
|
180
226
|
const userId = this.getOrGenerateUserId();
|
|
181
227
|
const requestBody = {
|
|
182
228
|
chatbot_id: this.chatbotId,
|
|
@@ -191,13 +237,12 @@ export class OcsChat {
|
|
|
191
237
|
}
|
|
192
238
|
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/start/`, {
|
|
193
239
|
method: 'POST',
|
|
194
|
-
headers:
|
|
195
|
-
'Content-Type': 'application/json',
|
|
196
|
-
},
|
|
240
|
+
headers: this.getApiHeaders(),
|
|
197
241
|
body: JSON.stringify(requestBody)
|
|
198
242
|
});
|
|
199
243
|
if (!response.ok) {
|
|
200
|
-
|
|
244
|
+
this.handleError(`Failed to start session: ${response.statusText}`);
|
|
245
|
+
return;
|
|
201
246
|
}
|
|
202
247
|
const data = await response.json();
|
|
203
248
|
this.sessionId = data.session_id;
|
|
@@ -205,24 +250,99 @@ export class OcsChat {
|
|
|
205
250
|
// Handle seed message if present
|
|
206
251
|
if (data.seed_message_task_id) {
|
|
207
252
|
this.isTyping = true; // Show typing indicator for seed message
|
|
208
|
-
|
|
253
|
+
this.currentPollTaskId = data.seed_message_task_id;
|
|
254
|
+
await this.pollTaskResponse();
|
|
209
255
|
}
|
|
210
256
|
// Start polling for messages
|
|
211
257
|
this.startPolling();
|
|
212
258
|
}
|
|
213
259
|
catch (error) {
|
|
214
|
-
this.
|
|
260
|
+
this.handleError('Failed to start chat session');
|
|
215
261
|
}
|
|
216
262
|
finally {
|
|
217
263
|
this.isLoading = false;
|
|
218
264
|
}
|
|
219
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
|
+
}
|
|
220
331
|
async sendMessage(message) {
|
|
221
332
|
if (!this.sessionId || !message.trim())
|
|
222
333
|
return;
|
|
223
|
-
// Hide starter questions on any user interaction
|
|
224
|
-
this.showStarterQuestions = false;
|
|
225
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
|
+
}
|
|
226
346
|
// If this is the first user message and there are welcome messages,
|
|
227
347
|
// add them to chat history as assistant messages
|
|
228
348
|
if (this.messages.length === 0 && this.parsedWelcomeMessages.length > 0) {
|
|
@@ -235,25 +355,36 @@ export class OcsChat {
|
|
|
235
355
|
}));
|
|
236
356
|
this.messages = [...this.messages, ...welcomeMessages];
|
|
237
357
|
}
|
|
238
|
-
// Add user message immediately
|
|
358
|
+
// Add user message immediately with attachments info
|
|
239
359
|
const userMessage = {
|
|
240
360
|
created_at: new Date().toISOString(),
|
|
241
361
|
role: 'user',
|
|
242
362
|
content: message.trim(),
|
|
243
|
-
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
|
+
})) : []
|
|
244
370
|
};
|
|
245
371
|
this.messages = [...this.messages, userMessage];
|
|
246
372
|
this.saveSessionToStorage();
|
|
247
373
|
this.messageInput = '';
|
|
374
|
+
if (this.allowAttachments) {
|
|
375
|
+
this.selectedFiles = []; // Clear selected files after sending
|
|
376
|
+
}
|
|
248
377
|
this.scrollToBottom();
|
|
249
378
|
// Start typing indicator - it will stay on during task polling
|
|
250
379
|
this.isTyping = true;
|
|
380
|
+
const requestBody = { message: message.trim() };
|
|
381
|
+
if (this.allowAttachments && attachmentIds.length > 0) {
|
|
382
|
+
requestBody.attachment_ids = attachmentIds;
|
|
383
|
+
}
|
|
251
384
|
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/message/`, {
|
|
252
385
|
method: 'POST',
|
|
253
|
-
headers:
|
|
254
|
-
|
|
255
|
-
},
|
|
256
|
-
body: JSON.stringify({ message: message.trim() })
|
|
386
|
+
headers: this.getApiHeaders(),
|
|
387
|
+
body: JSON.stringify(requestBody)
|
|
257
388
|
});
|
|
258
389
|
if (!response.ok) {
|
|
259
390
|
throw new Error(`Failed to send message: ${response.statusText}`);
|
|
@@ -263,27 +394,28 @@ export class OcsChat {
|
|
|
263
394
|
throw new Error(data.error || 'Failed to send message');
|
|
264
395
|
}
|
|
265
396
|
// Poll for the response - typing indicator will be managed in pollTaskResponse
|
|
266
|
-
|
|
397
|
+
this.currentPollTaskId = data.task_id;
|
|
398
|
+
await this.pollTaskResponse();
|
|
267
399
|
}
|
|
268
400
|
catch (error) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
this.isTyping = false;
|
|
401
|
+
const errorText = error instanceof Error ? error.message : 'Failed to send message';
|
|
402
|
+
this.handleError(errorText);
|
|
272
403
|
}
|
|
273
404
|
}
|
|
274
405
|
handleStarterQuestionClick(question) {
|
|
275
406
|
this.sendMessage(question);
|
|
276
407
|
}
|
|
277
|
-
async pollTaskResponse(
|
|
278
|
-
if (!this.sessionId)
|
|
408
|
+
async pollTaskResponse() {
|
|
409
|
+
if (!this.sessionId || !this.currentPollTaskId)
|
|
279
410
|
return;
|
|
280
411
|
// Stop message polling while task polling is active
|
|
281
|
-
this.isTaskPolling = true;
|
|
282
412
|
this.pauseMessagePolling();
|
|
283
413
|
let attempts = 0;
|
|
284
414
|
const poll = async () => {
|
|
415
|
+
if (!this.sessionId || !this.currentPollTaskId)
|
|
416
|
+
return;
|
|
285
417
|
try {
|
|
286
|
-
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/${
|
|
418
|
+
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/${this.currentPollTaskId}/poll/`);
|
|
287
419
|
if (!response.ok) {
|
|
288
420
|
throw new Error(`Failed to poll task: ${response.statusText}`);
|
|
289
421
|
}
|
|
@@ -297,7 +429,7 @@ export class OcsChat {
|
|
|
297
429
|
this.scrollToBottom();
|
|
298
430
|
// Task polling complete, clear typing indicator and resume message polling
|
|
299
431
|
this.isTyping = false;
|
|
300
|
-
this.
|
|
432
|
+
this.currentPollTaskId = '';
|
|
301
433
|
this.resumeMessagePolling();
|
|
302
434
|
this.focusInput();
|
|
303
435
|
return;
|
|
@@ -307,36 +439,47 @@ export class OcsChat {
|
|
|
307
439
|
setTimeout(poll, OcsChat.TASK_POLLING_INTERVAL_MS);
|
|
308
440
|
}
|
|
309
441
|
else if (attempts >= OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
|
|
310
|
-
// 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
|
|
311
453
|
this.isTyping = false;
|
|
312
|
-
this.
|
|
454
|
+
this.currentPollTaskId = '';
|
|
313
455
|
this.resumeMessagePolling();
|
|
456
|
+
this.focusInput();
|
|
314
457
|
}
|
|
315
458
|
}
|
|
316
459
|
catch (error) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
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 = '';
|
|
321
464
|
this.resumeMessagePolling();
|
|
322
465
|
}
|
|
323
466
|
};
|
|
324
467
|
await poll();
|
|
325
468
|
}
|
|
326
469
|
startPolling() {
|
|
327
|
-
if (this.
|
|
470
|
+
if (this.pollingIntervalRef)
|
|
328
471
|
return;
|
|
329
|
-
this.
|
|
472
|
+
this.pollingIntervalRef = setInterval(async () => {
|
|
330
473
|
// Only poll for messages if not currently polling for a task
|
|
331
|
-
if (!this.
|
|
474
|
+
if (!this.currentPollTaskId) {
|
|
332
475
|
await this.pollForMessages();
|
|
333
476
|
}
|
|
334
477
|
}, OcsChat.MESSAGE_POLLING_INTERVAL_MS);
|
|
335
478
|
}
|
|
336
479
|
pauseMessagePolling() {
|
|
337
|
-
if (this.
|
|
338
|
-
clearInterval(this.
|
|
339
|
-
this.
|
|
480
|
+
if (this.pollingIntervalRef) {
|
|
481
|
+
clearInterval(this.pollingIntervalRef);
|
|
482
|
+
this.pollingIntervalRef = undefined;
|
|
340
483
|
}
|
|
341
484
|
}
|
|
342
485
|
resumeMessagePolling() {
|
|
@@ -361,15 +504,11 @@ export class OcsChat {
|
|
|
361
504
|
this.scrollToBottom();
|
|
362
505
|
this.focusInput();
|
|
363
506
|
}
|
|
364
|
-
this.lastPollTime = new Date();
|
|
365
507
|
}
|
|
366
|
-
catch (
|
|
508
|
+
catch (_a) {
|
|
367
509
|
// Silently fail for polling
|
|
368
510
|
}
|
|
369
511
|
}
|
|
370
|
-
clearError() {
|
|
371
|
-
this.error = '';
|
|
372
|
-
}
|
|
373
512
|
scrollToBottom() {
|
|
374
513
|
setTimeout(() => {
|
|
375
514
|
if (this.messageListRef) {
|
|
@@ -392,24 +531,89 @@ export class OcsChat {
|
|
|
392
531
|
}
|
|
393
532
|
handleInputChange(event) {
|
|
394
533
|
this.messageInput = event.target.value;
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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';
|
|
398
591
|
}
|
|
399
592
|
}
|
|
400
593
|
formatTime(dateString) {
|
|
401
594
|
const date = new Date(dateString);
|
|
402
595
|
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
403
596
|
}
|
|
404
|
-
|
|
597
|
+
toggleWindowVisibility() {
|
|
405
598
|
this.visible = !this.visible;
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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) {
|
|
409
610
|
await this.startSession();
|
|
410
611
|
}
|
|
411
|
-
else if (!
|
|
412
|
-
|
|
612
|
+
else if (!visible) {
|
|
613
|
+
this.pauseMessagePolling();
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
this.resumeMessagePolling();
|
|
413
617
|
}
|
|
414
618
|
}
|
|
415
619
|
setPosition(position) {
|
|
@@ -430,6 +634,7 @@ export class OcsChat {
|
|
|
430
634
|
const actualChatWidth = Math.min(windowWidth, this.chatWindowFullscreenWidth);
|
|
431
635
|
const centeredX = (windowWidth - actualChatWidth) / 2;
|
|
432
636
|
const maxOffset = (windowWidth - actualChatWidth) / 2;
|
|
637
|
+
console.log(windowWidth, actualChatWidth, centeredX, maxOffset);
|
|
433
638
|
return { windowWidth, actualChatWidth, centeredX, maxOffset };
|
|
434
639
|
}
|
|
435
640
|
getPositionStyles() {
|
|
@@ -448,6 +653,10 @@ export class OcsChat {
|
|
|
448
653
|
};
|
|
449
654
|
}
|
|
450
655
|
initializePosition() {
|
|
656
|
+
if (this.positionInitialized) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
this.positionInitialized = true;
|
|
451
660
|
const windowWidth = window.innerWidth;
|
|
452
661
|
const windowHeight = window.innerHeight;
|
|
453
662
|
const chatWidth = windowWidth < OcsChat.MOBILE_BREAKPOINT ? windowWidth : this.chatWindowWidth;
|
|
@@ -562,10 +771,10 @@ export class OcsChat {
|
|
|
562
771
|
const iconSrc = hasCustomIcon ? this.iconUrl : this.getDefaultIconUrl();
|
|
563
772
|
const buttonClasses = this.getButtonClasses();
|
|
564
773
|
if (hasText) {
|
|
565
|
-
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)));
|
|
566
775
|
}
|
|
567
776
|
else {
|
|
568
|
-
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" })));
|
|
569
778
|
}
|
|
570
779
|
}
|
|
571
780
|
getStorageKeys() {
|
|
@@ -669,13 +878,25 @@ export class OcsChat {
|
|
|
669
878
|
return false;
|
|
670
879
|
}
|
|
671
880
|
}
|
|
672
|
-
|
|
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() {
|
|
673
892
|
this.clearSessionStorage();
|
|
674
893
|
this.sessionId = undefined;
|
|
675
894
|
this.messages = [];
|
|
676
|
-
this.showStarterQuestions = true;
|
|
677
895
|
this.isTyping = false;
|
|
678
|
-
this.
|
|
896
|
+
this.currentPollTaskId = '';
|
|
897
|
+
if (this.allowAttachments) {
|
|
898
|
+
this.selectedFiles = [];
|
|
899
|
+
}
|
|
679
900
|
this.cleanup();
|
|
680
901
|
await this.startSession();
|
|
681
902
|
}
|
|
@@ -685,16 +906,22 @@ export class OcsChat {
|
|
|
685
906
|
this.fullscreenPosition = { x: 0 };
|
|
686
907
|
}
|
|
687
908
|
render() {
|
|
688
|
-
|
|
909
|
+
// Only show error state for critical errors that prevent the widget from functioning
|
|
910
|
+
if (this.error && !this.sessionId) {
|
|
689
911
|
return (h(Host, null, h("p", { class: "error-message" }, this.error)));
|
|
690
912
|
}
|
|
691
|
-
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'
|
|
692
914
|
? 'message-bubble-user'
|
|
693
915
|
: message.role === 'assistant'
|
|
694
916
|
? 'message-bubble-assistant'
|
|
695
|
-
: '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()
|
|
696
923
|
? 'send-button-enabled'
|
|
697
|
-
: '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"))))))));
|
|
698
925
|
}
|
|
699
926
|
static get is() { return "open-chat-studio-widget"; }
|
|
700
927
|
static get encapsulation() { return "shadow"; }
|
|
@@ -826,6 +1053,26 @@ export class OcsChat {
|
|
|
826
1053
|
"attribute": "header-text",
|
|
827
1054
|
"reflect": false
|
|
828
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
|
+
},
|
|
829
1076
|
"visible": {
|
|
830
1077
|
"type": "boolean",
|
|
831
1078
|
"mutable": true,
|
|
@@ -1001,35 +1248,80 @@ export class OcsChat {
|
|
|
1001
1248
|
"attribute": "allow-full-screen",
|
|
1002
1249
|
"reflect": false,
|
|
1003
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\""
|
|
1004
1291
|
}
|
|
1005
1292
|
};
|
|
1006
1293
|
}
|
|
1007
1294
|
static get states() {
|
|
1008
1295
|
return {
|
|
1009
|
-
"loaded": {},
|
|
1010
1296
|
"error": {},
|
|
1011
1297
|
"messages": {},
|
|
1012
1298
|
"sessionId": {},
|
|
1013
1299
|
"isLoading": {},
|
|
1014
1300
|
"isTyping": {},
|
|
1015
1301
|
"messageInput": {},
|
|
1016
|
-
"
|
|
1017
|
-
"lastPollTime": {},
|
|
1018
|
-
"isTaskPolling": {},
|
|
1302
|
+
"currentPollTaskId": {},
|
|
1019
1303
|
"isDragging": {},
|
|
1020
1304
|
"dragOffset": {},
|
|
1021
1305
|
"windowPosition": {},
|
|
1022
1306
|
"fullscreenPosition": {},
|
|
1023
|
-
"showStarterQuestions": {},
|
|
1024
1307
|
"parsedWelcomeMessages": {},
|
|
1025
1308
|
"parsedStarterQuestions": {},
|
|
1026
1309
|
"generatedUserId": {},
|
|
1027
|
-
"isFullscreen": {}
|
|
1310
|
+
"isFullscreen": {},
|
|
1311
|
+
"showNewChatConfirmation": {},
|
|
1312
|
+
"selectedFiles": {},
|
|
1313
|
+
"isUploadingFiles": {}
|
|
1028
1314
|
};
|
|
1029
1315
|
}
|
|
1030
1316
|
static get elementRef() { return "host"; }
|
|
1317
|
+
static get watchers() {
|
|
1318
|
+
return [{
|
|
1319
|
+
"propName": "visible",
|
|
1320
|
+
"methodName": "visibilityHandler"
|
|
1321
|
+
}];
|
|
1322
|
+
}
|
|
1031
1323
|
}
|
|
1032
|
-
OcsChat.TASK_POLLING_MAX_ATTEMPTS =
|
|
1324
|
+
OcsChat.TASK_POLLING_MAX_ATTEMPTS = 120;
|
|
1033
1325
|
OcsChat.TASK_POLLING_INTERVAL_MS = 1000;
|
|
1034
1326
|
OcsChat.MESSAGE_POLLING_INTERVAL_MS = 30000;
|
|
1035
1327
|
OcsChat.SCROLL_DELAY_MS = 100;
|
|
@@ -1037,4 +1329,8 @@ OcsChat.FOCUS_DELAY_MS = 100;
|
|
|
1037
1329
|
OcsChat.MOBILE_BREAKPOINT = 640;
|
|
1038
1330
|
OcsChat.WINDOW_MARGIN = 20;
|
|
1039
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'];
|
|
1040
1336
|
//# sourceMappingURL=ocs-chat.js.map
|