From 0722750a553409a7b82c92c840151514c58813ff Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Fri, 22 May 2026 12:16:19 +0530 Subject: [PATCH 1/2] chore: Captain reply actions not showing correctly with content (#14160) --- .../widgets/WootWriter/CopilotMenuBar.vue | 22 +++------ .../components/widgets/WootWriter/Editor.vue | 48 ++++++++++--------- .../widgets/WootWriter/ReplyTopPanel.vue | 14 +++++- .../widgets/conversation/ReplyBox.vue | 16 +++++++ .../dashboard/helper/editorHelper.js | 6 +-- .../helper/specs/editorHelper.spec.js | 27 +++++------ 6 files changed, 77 insertions(+), 56 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/WootWriter/CopilotMenuBar.vue b/app/javascript/dashboard/components/widgets/WootWriter/CopilotMenuBar.vue index af9cc9f68..524d84ede 100644 --- a/app/javascript/dashboard/components/widgets/WootWriter/CopilotMenuBar.vue +++ b/app/javascript/dashboard/components/widgets/WootWriter/CopilotMenuBar.vue @@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n'; import { useElementSize, useWindowSize } from '@vueuse/core'; import { useMapGetter } from 'dashboard/composables/store'; import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants'; -import { useCaptain } from 'dashboard/composables/useCaptain'; import Button from 'dashboard/components-next/button/Button.vue'; import DropdownBody from 'next/dropdown-menu/base/DropdownBody.vue'; @@ -19,9 +18,11 @@ const props = defineProps({ type: Boolean, default: false, }, - editorContent: { - type: String, - default: undefined, + // Signature-aware emptiness is computed by the parent (which has access to + // the signature + channel context) and passed in as a boolean. + hasContent: { + type: Boolean, + default: false, }, conversationId: { type: Number, @@ -33,17 +34,8 @@ const emit = defineEmits(['executeCopilotAction']); const { t } = useI18n(); -const { draftMessage } = useCaptain(); - const replyMode = useMapGetter('draftMessages/getReplyEditorMode'); -// When editorContent prop is passed, use it exclusively (even if empty) -// This ensures each editor instance shows menu items based on its own content -// Falls back to global draftMessage only when editorContent is not provided -const effectiveContent = computed(() => - props.editorContent !== undefined ? props.editorContent : draftMessage.value -); - // Selection-based menu items (when text is selected) const menuItems = computed(() => { const items = []; @@ -63,7 +55,7 @@ const menuItems = computed(() => { } else if ( props.conversationId && replyMode.value === REPLY_EDITOR_MODES.REPLY && - effectiveContent.value + props.hasContent ) { items.push({ label: t('INTEGRATION_SETTINGS.OPEN_AI.REPLY_OPTIONS.IMPROVE_REPLY'), @@ -72,7 +64,7 @@ const menuItems = computed(() => { }); } - if (effectiveContent.value) { + if (props.hasContent) { items.push( { label: t( diff --git a/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue b/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue index d7adb07d0..7881a0d25 100644 --- a/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue +++ b/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue @@ -354,16 +354,17 @@ function isBodyEmpty(content) { // if content is undefined, we assume that the body is empty if (!content) return true; - // if the signature is present, we need to remove it before checking - // note that we don't update the editorView, so this is safe - // Use effective channel type to match how signature was appended - const bodyWithoutSignature = props.signature - ? removeSignatureHelper( - content, - props.signature, - effectiveChannelType.value - ) - : content; + // Only strip the signature when it's actually being auto-appended for this + // draft. Otherwise an agent whose typed text happens to match their saved + // signature would be mistakenly treated as empty. + const bodyWithoutSignature = + sendWithSignature.value && props.signature + ? removeSignatureHelper( + content, + props.signature, + effectiveChannelType.value + ) + : content; // trimming should remove all the whitespaces, so we can check the length return bodyWithoutSignature.trim().length === 0; @@ -474,17 +475,6 @@ function removeSignature() { reloadState(content); } -function toggleSignatureInEditor(signatureEnabled) { - // The toggleSignatureInEditor gets the new value from the - // watcher, this means that if the value is true, the signature - // is supposed to be added, else we remove it. - if (signatureEnabled) { - addSignature(); - } else { - removeSignature(); - } -} - function setToolbarPosition() { const editorRect = editorRoot.value.getBoundingClientRect(); const rect = selectedImageNode.value.getBoundingClientRect(); @@ -559,6 +549,20 @@ function emitOnChange() { emit('update:modelValue', contentFromEditor()); } +function toggleSignatureInEditor(signatureEnabled) { + // The toggleSignatureInEditor gets the new value from the + // watcher, this means that if the value is true, the signature + // is supposed to be added, else we remove it. + if (signatureEnabled) { + addSignature(); + } else { + removeSignature(); + } + // reloadState replaces editor state directly and bypasses dispatchTransaction, + // so v-model never hears about the signature change — sync it back explicitly. + emitOnChange(); +} + function updateImgToolbarOnDelete() { // check if the selected node is present or not on keyup // this is needed because the user can select an image and then delete it @@ -899,7 +903,7 @@ useEmitter(BUS_EVENTS.INSERT_INTO_RICH_EDITOR, insertContentIntoEditor); v-on-click-outside="handleClickOutside" :has-selection="isTextSelected" :is-editor-menu-popover="isEditorMenuPopover" - :editor-content="modelValue" + :has-content="!isBodyEmpty(modelValue)" :conversation-id="conversationId" :show-selection-menu="showSelectionMenu" :show-general-menu="false" diff --git a/app/javascript/dashboard/components/widgets/WootWriter/ReplyTopPanel.vue b/app/javascript/dashboard/components/widgets/WootWriter/ReplyTopPanel.vue index cdf577c21..a2929f7f8 100644 --- a/app/javascript/dashboard/components/widgets/WootWriter/ReplyTopPanel.vue +++ b/app/javascript/dashboard/components/widgets/WootWriter/ReplyTopPanel.vue @@ -53,6 +53,10 @@ export default { type: String, default: undefined, }, + hasContent: { + type: Boolean, + default: false, + }, }, emits: ['setReplyMode', 'toggleEditorSize', 'executeCopilotAction'], setup(props, { emit }) { @@ -76,6 +80,7 @@ export default { const { captainTasksEnabled } = useCaptain(); const showCopilotMenu = ref(false); + const copilotToggleRef = ref(null); const handleCopilotAction = (actionKey, data) => { emit('executeCopilotAction', actionKey, data || props.editorContent); @@ -117,6 +122,7 @@ export default { captainTasksEnabled, handleCopilotAction, showCopilotMenu, + copilotToggleRef, toggleCopilotMenu, handleClickOutside, }; @@ -164,6 +170,7 @@ export default {
Date: Fri, 22 May 2026 13:46:43 +0700 Subject: [PATCH 2/2] chore: resolve sass and vue compiler deprecation warnings (#13794) --- .../components-next/Editor/Editor.vue | 36 +++++------ .../Pages/ArticleEditorPage/ArticleEditor.vue | 62 +++++++++---------- .../components-next/breadcrumb/Breadcrumb.vue | 1 - .../pageComponents/customTool/AuthConfig.vue | 2 +- .../pageComponents/customTool/ParamRow.vue | 2 +- .../colorpicker/ColorPicker.vue | 2 +- .../dropdown-menu/DropdownMenu.vue | 2 +- .../components-next/filter/ConditionRow.vue | 2 +- .../filter/inputs/MultiSelect.vue | 2 +- .../filter/inputs/SingleSelect.vue | 2 +- .../dashboard/components-next/flag/Flag.vue | 2 +- .../components-next/message/MessageList.vue | 2 +- .../message/TranslationToggle.vue | 2 - .../message/chips/AttachmentChips.vue | 2 +- .../components/Accordion/AccordionItem.vue | 1 - .../dashboard/components/CustomAttribute.vue | 16 +++-- .../components/IntersectionObserver.vue | 2 +- app/javascript/dashboard/components/Modal.vue | 2 +- .../components/ui/Dropdown/DropdownSearch.vue | 1 - .../components/widgets/ColorPicker.vue | 6 +- .../widgets/WootWriter/AudioRecorder.vue | 2 +- .../widgets/WootWriter/ReplyBottomPanel.vue | 2 +- .../linear/SearchableDropdown.vue | 2 +- .../widgets/mentions/MentionBox.vue | 2 +- .../components/MessageContextMenu.vue | 10 ++- .../search/components/MessageContent.vue | 4 +- .../components/SearchContactAgentSelector.vue | 2 +- .../components/SearchDateRangeSelector.vue | 2 +- .../search/components/SearchFilters.vue | 2 +- .../search/components/SearchHeader.vue | 2 +- .../search/components/SearchInboxSelector.vue | 2 +- .../SearchResultConversationsList.vue | 2 +- .../widget-preview/components/WidgetBody.vue | 2 - .../dashboard/conversation/ContactPanel.vue | 6 +- .../dashboard/settings/canned/AddCanned.vue | 16 +++-- .../dashboard/settings/canned/EditCanned.vue | 16 +++-- .../dashboard/settings/canned/Index.vue | 2 +- .../component/CustomRolePaywall.vue | 36 ++++++----- .../settings/inbox/PreChatForm/Settings.vue | 6 +- .../inbox/channels/emailChannels/Google.vue | 1 - .../channels/emailChannels/Microsoft.vue | 1 - .../inbox/components/WeeklyAvailability.vue | 2 +- .../inbox/settingsPage/ConfigurationPage.vue | 2 +- .../settingsPage/CustomerSatisfactionPage.vue | 2 +- .../integrations/SingleIntegrationHooks.vue | 1 - .../dashboard/settings/labels/AddLabel.vue | 6 +- .../dashboard/settings/labels/EditLabel.vue | 6 +- .../dashboard/settings/macros/MacroNode.vue | 2 +- .../settings/macros/MacroProperties.vue | 4 +- .../heatmaps/HeatmapDateRangeSelector.vue | 2 +- .../routes/dashboard/upgrade/UpgradePage.vue | 2 +- .../shared/components/StarRating.vue | 2 +- .../components/ui/MultiselectDropdown.vue | 2 +- .../components/ui/dropdown/DropdownItem.vue | 8 +-- app/javascript/v3/components/Form/Input.vue | 2 +- .../widget/components/GroupedAvatars.vue | 2 +- .../widget/components/UserMessageBubble.vue | 8 +-- .../Home/Article/ArticleBlock.vue | 2 +- .../Home/Article/ArticleListItem.vue | 1 - vite.config.ts | 7 +++ 60 files changed, 153 insertions(+), 179 deletions(-) diff --git a/app/javascript/dashboard/components-next/Editor/Editor.vue b/app/javascript/dashboard/components-next/Editor/Editor.vue index 847bbd600..b12d0331a 100644 --- a/app/javascript/dashboard/components-next/Editor/Editor.vue +++ b/app/javascript/dashboard/components-next/Editor/Editor.vue @@ -142,29 +142,27 @@ watch( diff --git a/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue b/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue index 831312e0b..59c710a37 100644 --- a/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue +++ b/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue @@ -145,45 +145,43 @@ const handleCreateArticle = event => { diff --git a/app/javascript/dashboard/components/IntersectionObserver.vue b/app/javascript/dashboard/components/IntersectionObserver.vue index c650a8c0e..36135bd44 100644 --- a/app/javascript/dashboard/components/IntersectionObserver.vue +++ b/app/javascript/dashboard/components/IntersectionObserver.vue @@ -1,5 +1,5 @@