From 4f33deb978adcf008666567bc02a0d54e84aba89 Mon Sep 17 00:00:00 2001 From: Gabriel Jablonski Date: Tue, 14 Apr 2026 13:51:31 -0300 Subject: [PATCH] release v4.12.0-fazer-ai.54 (#265) * fix(whatsapp): preserve green color on chat list typing indicator The messagePreviewClass computed includes text-n-slate-11/12, which overrode text-green-500 in the compiled Tailwind order. Split padding into a dedicated computed and apply only it on the typing preview. Co-Authored-By: Claude Opus 4.6 (1M context) * fix(whatsapp): clear contact typing indicator when message is received Dispatch CONVERSATION_TYPING_OFF after a new incoming message is persisted from baileys messages.upsert, so the dashboard clears the typing/recording indicator without waiting for a paused/unavailable presence event. Co-Authored-By: Claude Opus 4.6 (1M context) * fix(conversations): dispatch messages.read event when unread messages exist The throttling introduced in upstream #13355 returned early for the "has unread" branches, skipping dispatch_messages_read_event. That meant the MESSAGES_READ event only fired when there were no unread messages, so ChannelListener never called channel.read_messages on the baileys provider when an agent actually read a conversation. Consolidate the unread/throttle guard so the dispatch runs in all paths where update_last_seen_on_conversation runs. Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../api/v1/accounts/conversations_controller.rb | 5 ++--- .../widgets/conversation/ConversationCard.vue | 12 +++++++++--- .../individual_contact_message_handler.rb | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/v1/accounts/conversations_controller.rb b/app/controllers/api/v1/accounts/conversations_controller.rb index 38bb5d1d0..e6a4bdbc0 100644 --- a/app/controllers/api/v1/accounts/conversations_controller.rb +++ b/app/controllers/api/v1/accounts/conversations_controller.rb @@ -126,11 +126,10 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro # High-traffic accounts generate excessive DB writes when agents frequently switch between conversations. # Throttle last_seen updates to once per hour when there are no unread messages to reduce DB load. # Always update immediately if there are unread messages to maintain accurate read/unread state. - return update_last_seen_on_conversation(DateTime.now.utc, true) if assignee? && @conversation.assignee_unread_messages.any? - return update_last_seen_on_conversation(DateTime.now.utc, false) if !assignee? && @conversation.unread_messages.any? + has_unread = assignee? ? @conversation.assignee_unread_messages.any? : @conversation.unread_messages.any? # No unread messages - apply throttling to limit DB writes - return unless should_update_last_seen? + return if !has_unread && !should_update_last_seen? dispatch_messages_read_event if assignee? diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue index fca692d0d..0297d64fe 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue @@ -161,11 +161,17 @@ const showLabelsSection = computed(() => { return props.chat.labels?.length > 0 || hasSlaPolicyId.value; }); +const messagePreviewPaddingClass = computed(() => { + return [ + !props.compact && hasUnread.value ? 'ltr:pr-4 rtl:pl-4' : '', + props.compact && hasUnread.value ? 'ltr:pr-6 rtl:pl-6' : '', + ]; +}); + const messagePreviewClass = computed(() => { return [ hasUnread.value ? 'font-medium text-n-slate-12' : 'text-n-slate-11', - !props.compact && hasUnread.value ? 'ltr:pr-4 rtl:pl-4' : '', - props.compact && hasUnread.value ? 'ltr:pr-6 rtl:pl-6' : '', + ...messagePreviewPaddingClass.value, ]; }); @@ -370,7 +376,7 @@ const deleteConversation = () => { v-else-if="isAnyoneTyping" key="typing-preview" class="text-green-500 text-sm font-medium my-0 mx-2 leading-6 h-6 flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap" - :class="messagePreviewClass" + :class="messagePreviewPaddingClass" > {{ typingPreviewText }}

diff --git a/app/services/whatsapp/baileys_handlers/concerns/individual_contact_message_handler.rb b/app/services/whatsapp/baileys_handlers/concerns/individual_contact_message_handler.rb index 113adf193..19df6c7f4 100644 --- a/app/services/whatsapp/baileys_handlers/concerns/individual_contact_message_handler.rb +++ b/app/services/whatsapp/baileys_handlers/concerns/individual_contact_message_handler.rb @@ -1,6 +1,7 @@ module Whatsapp::BaileysHandlers::Concerns::IndividualContactMessageHandler extend ActiveSupport::Concern include Whatsapp::BaileysHandlers::Concerns::MessageCreationHandler + include Events::Types private @@ -30,11 +31,25 @@ module Whatsapp::BaileysHandlers::Concerns::IndividualContactMessageHandler set_conversation handle_create_message + dispatch_incoming_typing_off end ensure clear_message_source_id_from_redis if @lock_acquired end + def dispatch_incoming_typing_off + return unless incoming? + return unless @conversation && @contact + + Rails.configuration.dispatcher.dispatch( + CONVERSATION_TYPING_OFF, + Time.zone.now, + conversation: @conversation, + user: @contact, + is_private: false + ) + end + def set_contact phone = extract_from_jid(type: 'pn') source_id = extract_from_jid(type: 'lid')