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) <noreply@anthropic.com>

* 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) <noreply@anthropic.com>

* 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) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Gabriel Jablonski 2026-04-14 13:51:31 -03:00 committed by GitHub
parent 02f70ff611
commit 4f33deb978
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 26 additions and 6 deletions

View File

@ -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?

View File

@ -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 }}
</p>

View File

@ -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')