open-chat-studio-widget 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/cjs/{index-CC3Krx2K.js → index-Ctja7z-R.js} +3 -3
  2. package/dist/cjs/{index-CC3Krx2K.js.map → index-Ctja7z-R.js.map} +1 -1
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/open-chat-studio-widget.cjs.entry.js +45 -38
  5. package/dist/cjs/open-chat-studio-widget.cjs.entry.js.map +1 -1
  6. package/dist/cjs/open-chat-studio-widget.cjs.js +1 -1
  7. package/dist/cjs/open-chat-studio-widget.entry.cjs.js.map +1 -1
  8. package/dist/collection/components/ocs-chat/ocs-chat.js +44 -37
  9. package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
  10. package/dist/collection/services/chat-session-service.js.map +1 -1
  11. package/dist/collection/utils/translations.js +2 -2
  12. package/dist/collection/utils/translations.js.map +1 -1
  13. package/dist/components/open-chat-studio-widget.js +44 -37
  14. package/dist/components/open-chat-studio-widget.js.map +1 -1
  15. package/dist/esm/{index-BF7CYZiN.js → index-BbCwiO7g.js} +3 -3
  16. package/dist/esm/{index-BF7CYZiN.js.map → index-BbCwiO7g.js.map} +1 -1
  17. package/dist/esm/loader.js +2 -2
  18. package/dist/esm/open-chat-studio-widget.entry.js +45 -38
  19. package/dist/esm/open-chat-studio-widget.entry.js.map +1 -1
  20. package/dist/esm/open-chat-studio-widget.js +2 -2
  21. package/dist/open-chat-studio-widget/open-chat-studio-widget.entry.esm.js.map +1 -1
  22. package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js +1 -1
  23. package/dist/open-chat-studio-widget/{p-400b1f47.entry.js → p-96920183.entry.js} +4 -4
  24. package/dist/open-chat-studio-widget/p-96920183.entry.js.map +1 -0
  25. package/dist/open-chat-studio-widget/{p-BF7CYZiN.js → p-BbCwiO7g.js} +2 -2
  26. package/dist/open-chat-studio-widget/{p-BF7CYZiN.js.map → p-BbCwiO7g.js.map} +1 -1
  27. package/dist/types/components/ocs-chat/ocs-chat.d.ts +5 -1
  28. package/dist/types/services/chat-session-service.d.ts +0 -1
  29. package/package.json +2 -2
  30. package/dist/open-chat-studio-widget/p-400b1f47.entry.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { b as bootstrapLazy } from './index-BF7CYZiN.js';
2
- export { s as setNonce } from './index-BF7CYZiN.js';
1
+ import { b as bootstrapLazy } from './index-BbCwiO7g.js';
2
+ export { s as setNonce } from './index-BbCwiO7g.js';
3
3
  import { g as globalScripts } from './app-globals-DQuL1Twl.js';
4
4
 
5
5
  const defineCustomElements = async (win, options) => {
@@ -1,4 +1,4 @@
1
- import { h, r as registerInstance, E as Env, H as Host, g as getElement } from './index-BF7CYZiN.js';
1
+ import { h, r as registerInstance, E as Env, H as Host, g as getElement } from './index-BbCwiO7g.js';
2
2
 
3
3
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
4
  const OcsWidgetAvatar = () => {
@@ -5400,17 +5400,16 @@ const OcsChat = class {
5400
5400
  this.chatWindowFullscreenWidth = varToPixels(fullscreenWidthVar, window.innerWidth, this.chatWindowFullscreenWidth);
5401
5401
  // Initialize button position from computed styles
5402
5402
  this.initializeButtonPosition();
5403
- if (this.visible) {
5404
- this.initializePosition();
5405
- }
5406
- // Only auto-start session if we don't have an existing one
5407
- if (this.visible && !this.sessionId) {
5408
- this.startSession();
5409
- }
5410
- else if (this.visible && this.sessionId) {
5411
- // Resume polling for existing session
5412
- this.startMessagePolling();
5413
- }
5403
+ // Defer position initialization to avoid state changes during componentDidLoad
5404
+ setTimeout(() => {
5405
+ if (this.visible) {
5406
+ this.initializePosition();
5407
+ }
5408
+ // Resume polling for existing session (don't auto-start new sessions)
5409
+ if (this.visible && this.sessionId) {
5410
+ this.startMessagePolling();
5411
+ }
5412
+ }, 0);
5414
5413
  window.addEventListener('resize', this.handleWindowResize);
5415
5414
  }
5416
5415
  disconnectedCallback() {
@@ -5522,13 +5521,7 @@ const OcsChat = class {
5522
5521
  const data = await this.getChatService().startSession(requestBody);
5523
5522
  this.sessionId = data.session_id;
5524
5523
  this.saveSessionToStorage();
5525
- // Handle seed message if present
5526
- if (data.seed_message_task_id) {
5527
- this.startTaskPolling(data.seed_message_task_id);
5528
- }
5529
- else {
5530
- this.startMessagePolling();
5531
- }
5524
+ this.startMessagePolling();
5532
5525
  }
5533
5526
  catch (_error) {
5534
5527
  this.handleError('Failed to start chat session');
@@ -5557,8 +5550,20 @@ const OcsChat = class {
5557
5550
  }
5558
5551
  }
5559
5552
  async sendMessage(message) {
5560
- if (!this.sessionId || !message.trim())
5553
+ if (!message.trim())
5561
5554
  return;
5555
+ // Start session if we don't have one yet
5556
+ if (!this.sessionId) {
5557
+ // Prevent concurrent session initialization
5558
+ if (this.isLoading) {
5559
+ return;
5560
+ }
5561
+ await this.startSession();
5562
+ // Check if session started successfully
5563
+ if (!this.sessionId) {
5564
+ return; // startSession already handled the error
5565
+ }
5566
+ }
5562
5567
  try {
5563
5568
  let attachmentIds = [];
5564
5569
  if (this.allowAttachments && this.selectedFiles.length > 0) {
@@ -5573,10 +5578,11 @@ const OcsChat = class {
5573
5578
  }
5574
5579
  // If this is the first user message and there are welcome messages,
5575
5580
  // add them to chat history as assistant messages
5576
- if (this.messages.length === 0 && this.parsedWelcomeMessages.length > 0) {
5581
+ const welcomeMessagesToAdd = this.getWelcomeMessages();
5582
+ if (this.messages.length === 0 && welcomeMessagesToAdd.length > 0) {
5577
5583
  const now = new Date();
5578
- const welcomeMessages = this.parsedWelcomeMessages.map((welcomeMsg, index) => ({
5579
- created_at: new Date(now.getTime() - (this.parsedWelcomeMessages.length - index) * 1000).toISOString(),
5584
+ const welcomeMessages = welcomeMessagesToAdd.map((welcomeMsg, index) => ({
5585
+ created_at: new Date(now.getTime() - (welcomeMessagesToAdd.length - index) * 1000).toISOString(),
5580
5586
  role: 'assistant',
5581
5587
  content: welcomeMsg,
5582
5588
  attachments: []
@@ -5710,16 +5716,14 @@ const OcsChat = class {
5710
5716
  }
5711
5717
  if (visible) {
5712
5718
  this.initializePosition();
5713
- }
5714
- if (visible && !this.sessionId) {
5715
- await this.startSession();
5716
- }
5717
- else if (!visible) {
5718
- this.stopMessagePolling();
5719
+ // Resume polling for existing session (don't auto-start new sessions)
5720
+ if (this.sessionId) {
5721
+ this.scrollToBottom(true);
5722
+ this.startMessagePolling();
5723
+ }
5719
5724
  }
5720
5725
  else {
5721
- this.scrollToBottom(true);
5722
- this.startMessagePolling();
5726
+ this.stopMessagePolling();
5723
5727
  }
5724
5728
  }
5725
5729
  startTaskPolling(taskId) {
@@ -6222,9 +6226,13 @@ const OcsChat = class {
6222
6226
  }
6223
6227
  async confirmNewChat() {
6224
6228
  this.hideConfirmationDialog();
6225
- await this.actuallyStartNewChat();
6229
+ await this.clearSession();
6226
6230
  }
6227
- async actuallyStartNewChat() {
6231
+ /**
6232
+ * This clears out all data related to the previous session. A new session
6233
+ * will start when the user sends a message.
6234
+ */
6235
+ async clearSession() {
6228
6236
  this.clearSessionStorage();
6229
6237
  this.sessionId = undefined;
6230
6238
  this.messages = [];
@@ -6234,7 +6242,6 @@ const OcsChat = class {
6234
6242
  this.selectedFiles = [];
6235
6243
  }
6236
6244
  this.cleanup();
6237
- await this.startSession();
6238
6245
  }
6239
6246
  toggleFullscreen() {
6240
6247
  this.isFullscreen = !this.isFullscreen;
@@ -6246,18 +6253,18 @@ const OcsChat = class {
6246
6253
  if (this.error && !this.sessionId) {
6247
6254
  return (h(Host, null, h("p", { class: "error-message" }, this.error)));
6248
6255
  }
6249
- 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.translationManager.get('branding.headerText', this.headerText)), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: this.translationManager.get('window.newChat'), "aria-label": this.translationManager.get('window.newChat') }, h(PlusWithCircleIcon, null))), this.allowFullScreen && h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen'), "aria-label": this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen') }, this.isFullscreen ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null)), h("button", { class: "header-button", onClick: () => this.visible = false, "aria-label": this.translationManager.get('window.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" }, this.translationManager.get('modal.newChatTitle')), h("p", { class: "confirmation-message" }, this.translationManager.get('modal.newChatBody', this.newChatConfirmationMessage)), h("div", { class: "confirmation-buttons" }, h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, this.translationManager.get('modal.cancel')), h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, this.translationManager.get('modal.confirm'))))))), h("div", { class: "chat-content" }, this.isLoading && !this.sessionId && (h("div", { class: "loading-container" }, h("div", { class: "loading-spinner" }), h("span", { class: "loading-text" }, this.translationManager.get('status.starting')))), (h("div", { ref: (el) => this.messageListRef = el, class: "messages-container" }, this.messages.length === 0 && this.parsedWelcomeMessages.length > 0 && (h("div", { class: "welcome-messages" }, this.getWelcomeMessages().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: renderMarkdownSync(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'
6256
+ 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.translationManager.get('branding.headerText', this.headerText)), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: this.translationManager.get('window.newChat'), "aria-label": this.translationManager.get('window.newChat') }, h(PlusWithCircleIcon, null))), this.allowFullScreen && h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen'), "aria-label": this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen') }, this.isFullscreen ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null)), h("button", { class: "header-button", onClick: () => this.visible = false, "aria-label": this.translationManager.get('window.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" }, this.translationManager.get('modal.newChatTitle')), h("p", { class: "confirmation-message" }, this.translationManager.get('modal.newChatBody', this.newChatConfirmationMessage)), h("div", { class: "confirmation-buttons" }, h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, this.translationManager.get('modal.cancel')), h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, this.translationManager.get('modal.confirm'))))))), h("div", { class: "chat-content" }, this.isLoading && !this.sessionId && (h("div", { class: "loading-container" }, h("div", { class: "loading-spinner" }), h("span", { class: "loading-text" }, this.translationManager.get('status.starting')))), (h("div", { ref: (el) => this.messageListRef = el, class: "messages-container" }, this.messages.length === 0 && this.getWelcomeMessages().length > 0 && (h("div", { class: "welcome-messages" }, this.getWelcomeMessages().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: renderMarkdownSync(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'
6250
6257
  ? 'message-bubble-user'
6251
6258
  : message.role === 'assistant'
6252
6259
  ? 'message-bubble-assistant'
6253
- : 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(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.translationManager.get('status.typing', this.typingIndicatorText)), h("span", { class: "typing-dots loading" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (h("div", { class: "starter-questions" }, this.getStarterQuestions().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": this.translationManager.get('attach.remove') }, 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: this.translationManager.get('composer.placeholder'), value: this.messageInput, onInput: (e) => this.handleInputChange(e), onKeyPress: (e) => this.handleKeyPress(e), disabled: this.isTyping || this.isUploadingFiles }), this.allowAttachments && (h("input", { ref: (el) => {
6260
+ : 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(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.translationManager.get('status.typing', this.typingIndicatorText)), h("span", { class: "typing-dots loading" })))))), this.messages.length === 0 && this.getStarterQuestions().length > 0 && (h("div", { class: "starter-questions" }, this.getStarterQuestions().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": this.translationManager.get('attach.remove') }, h(XIcon, null)))))))), h("div", { class: "input-area" }, h("div", { class: "input-container" }, h("textarea", { ref: (el) => this.textareaRef = el, class: "message-textarea", rows: 1, placeholder: this.translationManager.get('composer.placeholder'), value: this.messageInput, onInput: (e) => this.handleInputChange(e), onKeyPress: (e) => this.handleKeyPress(e), disabled: this.isTyping || this.isUploadingFiles || this.isLoading }), this.allowAttachments && (h("input", { ref: (el) => {
6254
6261
  // Unclear why but after removing all attachments this is being set to `null`.
6255
6262
  if (el) {
6256
6263
  this.fileInputRef = el;
6257
6264
  }
6258
- }, 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: this.translationManager.get('attach.add'), "aria-label": this.translationManager.get('attach.add') }, h(PaperClipIcon, null))), h("button", { class: `send-button ${!this.isTyping && !!this.messageInput.trim()
6265
+ }, 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 || this.isLoading, title: this.translationManager.get('attach.add'), "aria-label": this.translationManager.get('attach.add') }, h(PaperClipIcon, null))), h("button", { class: `send-button ${!this.isTyping && !this.isLoading && !!this.messageInput.trim()
6259
6266
  ? 'send-button-enabled'
6260
- : 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || !this.messageInput.trim() }, this.isUploadingFiles ? `${this.translationManager.get('status.uploading')}...` : this.translationManager.get('composer.send'))))), h("div", { class: "flex items-center justify-center text-[0.8em] font-light w-full text-slate-500 py-[2px]" }, h("p", null, this.translationManager.get('branding.poweredBy'), ' ', " ", h("a", { class: "underline", href: "https://www.dimagi.com", target: "_blank" }, "Dimagi"))))))));
6267
+ : 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || this.isLoading || !this.messageInput.trim() }, this.isUploadingFiles ? `${this.translationManager.get('status.uploading')}...` : this.translationManager.get('composer.send')))), h("div", { class: "flex items-center justify-center text-[0.8em] font-light w-full text-slate-500 py-[2px]" }, h("p", null, this.translationManager.get('branding.poweredBy'), ' ', " ", h("a", { class: "underline", href: "https://www.dimagi.com", target: "_blank" }, "Dimagi"))))))));
6261
6268
  }
6262
6269
  get host() { return getElement(this); }
6263
6270
  static get watchers() { return {