Admin configura em Account Settings → Agents → Editar quais inboxes
disparam o banner agressivo (reopened + inatividade) pra cada agente.
- user.ui_settings.aggressive_alert_inbox_ids: null (todas) | [] (nenhuma) | [1,2,3]
- Filtro aplicado no actionCable.feedInactivityTracker, maybeTriggerAggressiveAlert
e no hydrate do AggressiveConversationBanner
- Backend aceita ui_settings no agents#update e serializa em _agent.json.jbuilder
- UI no EditAgent com toggle "todas inboxes" + multiselect
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug reportado em 2026-04-24: só o banner vermelho status→open
funcionava. 5/15/28min nunca disparavam.
Causa: o tracker só era alimentado via websocket ao vivo
(message.created). Se a msg do cliente chegou ANTES da aba carregar
(ou depois de F5), o tracker ficava vazio, setInterval nunca começava,
thresholds nunca disparavam.
Fix:
- Nova função `hydrateFromConversations(convs)` no tracker. Varre
conversas em 'open', pega a última msg não-activity, se for de
Contact registra com timestamp REAL (msg.created_at), não Date.now().
Isso fecha o gap de tempo: se o cliente falou 7min atrás, o YELLOW
já dispara na hora.
- AggressiveConversationBanner.vue tem agora `watch: allConversations`
chamando hydrate toda vez que a lista muda (boot + F5 + navegação).
- parseCreatedAt() suporta Unix seconds + ISO.
- findLastNonActivityMessage() ignora mensagens de sistema.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Banner agressivo passa de uma notificação só ("status→open") pra
um sistema de escalada baseado em inatividade quando o cliente é
o último a falar.
Níveis:
- 5 min sem resposta → AMARELO, sem som
- 15 min sem resposta → LARANJA, beep 1x + notificação do SO
- 28 min sem resposta → VERMELHO pulsante + som em loop infinito
- status→open (reabertura) → VERMELHO imediato
Por conversa, o banner mostra um item com nome do contato, inbox
e contexto ("reabriu agora" / "15 min sem resposta"). Headline
grande e explicação clara sobre como limpa.
Comportamento do × dismiss:
- Antes: apagava o alerta de vez. Agente podia "fingir que viu".
- Agora: esconde temporariamente. Volta quando escalar (próximo
threshold) ou nova mensagem. A única forma de LIMPAR de vez é
responder o cliente (tracker detecta msg outgoing do User ou
AgentBot e chama dismissForReply).
Permissões:
- account.settings.aggressive_alert_enabled (master switch admin)
- user.ui_settings.aggressive_alert_enabled (toggle do próprio agente)
- Default true pros dois; um false em qualquer bloqueia alertas.
Settings UI:
- Conta → General: novo card "Alerta agressivo (master switch)"
- Perfil do usuário: novo card "Receber alertas agressivos"
Arquivos:
- helper/aggressiveAlert.js: multi-level state, hide vs dismiss-for-reply
- helper/inactivityAlertTracker.js: timer único, thresholds declarativos
- helper/actionCable.js: hook em onMessageCreated (feed tracker) +
isAggressiveAlertEnabled() + limpa tracker em status_changed != open
- components/app/AggressiveConversationBanner.vue: variantes de cor,
headline grande, explanation, × temp-hide
- account.rb + accounts_controller.rb: store_accessor + permitted
- settings UI components (account + profile): switches auto-persist
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Banner persistente + som em loop + OS notification + title flash
+ vibração mobile quando conversa transiciona pra 'open' vindo de
pending/snoozed/resolved. Exige interação pra dismissar — atendente
não perde evento de reabertura.
- AggressiveConversationBanner.vue: banner full-width no topo,
dismissable, mostra nome do contato + inbox + status anterior
- aggressiveAlert.js: manager do som (loop infinito), title flash
(intervalo 1s), Notification API (requireInteraction: true),
navigator.vibrate (padrão 500-200-500-200-500)
- actionCable.onStatusChange: detecta transição pra 'open' e dispara
trigger via BUS_EVENTS (só se status anterior ≠ open, pra não
alertar conversa nova criada já em open)
- i18n pt_BR + en: chaves de notificação (title/body/dismiss)
- busEvents: AGGRESSIVE_ALERT_TRIGGER + AGGRESSIVE_ALERT_DISMISS
Camada 1 da feature. Camada 2 (escalation SMS/WhatsApp se não
dismissar em X segundos) fica pra outro PR.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Pull Request Template
## Description
### Issue
The Community Edition (CE) dashboard was making API requests to
enterprise-only endpoints, causing 404 errors:
* `/enterprise/api/v1/accounts/1/limits`
* `/api/v1/accounts/1/captain/assistants?page=1`
### Solution
1. Added conditional checks to prevent these calls.
2. Remove unused component
`app/javascript/dashboard/components/app/UpgradeBanner.vue`
Fixes
[CW-4695](https://linear.app/chatwoot/issue/CW-4695/440-ce-dashboard-calls-enterprise-urls),
https://github.com/chatwoot/chatwoot/issues/12023
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Pranav <pranavrajs@gmail.com>
These fixes are all auto generated and can be merged directly
Fixes the following issues
1. Event used on components should be hypenated
2. Attribute orders in components
3. Use `unmounted` instead of `destroyed`
4. Add explicit `emits` declarations for components, autofixed [using
this
script](https://gist.github.com/scmmishra/6f549109b96400006bb69bbde392eddf)
We ignore the top level v-if for now, we will fix it later
# Pull Request Template
## Description
This PR will replace the usage of `alertMixin` from the code base with
the `useAlert` composable.
Fixes
https://linear.app/chatwoot/issue/CW-3462/replace-alertmixin-usage-with-usealert
## Type of change
- [x] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
## How Has This Been Tested?
Please refer this issue description
https://linear.app/chatwoot/issue/CW-3462/replace-alertmixin-usage-with-usealert
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Sojan Jose <sojan@pepalo.com>