Commit Graph

131 Commits

Author SHA1 Message Date
Gabriel Jablonski
a996b920e8
feat: group conversations (#228)
* feat: add group and conversation types to contacts and conversations, and implement conversation group membership model

* chore: add factory and specs for conversation group member model

* chore: add group type checks and associations for contacts and conversations

* refactor: remove scopes from ConversationGroupMember model

* refactor: remove scopes from ConversationGroupMember model specs

* refactor: enhance conversation type migration with concurrent indexing

* feat: add is_active index and scopes to ConversationGroupMember model

* feat: implement GroupConversationHandler for managing group conversations

* feat: add group_type attribute to contact creation

* fix: update WHATSAPP_CHANNEL_REGEX to allow up to 20 digits to handle group jid

* feat: handle group JID format in remote_jid method

* chore: update group contact info when finding or creating group contact

* chore: refactor and implement contact message handling and message creation logic for baileys single contact conversation

* feat: implement group message handling and metadata fetching in WhatsApp service

* chore: add spec for group type handling in contact creation for individual and group contacts

* chore: add specs for test scopes in conversation group members

* chore: update documentation for sender phone extraction in group conversation handler

* chore: move GroupConversationHandler concern to correct dir

* chore: implement specs for recipient_id handling to individual and group contacts

* chore: add group message handling specs for incoming messages

* chore: enhance group message handling to prevent race conditions

* chore: add group_metadata method to with error handling

* chore: add test for sending messages to group recipients in WhatsappBaileysService

* chore: raise error for unsuccessful response in group_metadata method

* chore: adds tests for group metadata retrieval and error handling

* chore: refactor build_sender_contact_attributes to avoid double call methods

* chore: update error handling for attachment download failure in message creation

* chore: optimize update_contact_info method to use compact hash for updates

* chore: simplify find_or_create_sender_contact method return values

* chore: rename group and individual contact message handlers

* chore: remove pointless comments from group contact message handler methods

* chore: refine sender JID extraction logic to remove unnecessary checks

* chore: remove phone number in spec for group contact attributes

* chore: implement sync_group route

* chore: implement get group_members route

* fix: sync_group participants creation handling

* chore: update contact avatar handling in group message processing

* chore: move sync_group functionality for conversation model

* feat: add sync_group action to ConversationsController and route

* fix: set contact name to phone in group message processing

* chore: refine group member retrieval logic in sync_group service and view

* feat: implement group participants update handling

* feat: implement group updates handling and localization for group activities

* chore: add handling for group membership requests and icon changes

* chore: add authorization for sync_group action in ContactsController

* chore: add sync_group endpoint specs for contact management

* chore: add authorization for sync_group action in ConversationsController

* chore: add specs for sync_group endpoint in ConversationsController

* chore: refactor index action in GroupMembersController for improved conversation filtering

* chore: add request specs for group_members endpoint in ContactsController

* chore: add specs for sync_group method in Conversation model

* chore: add specs for sync_group method in Channel::Whatsapp model

* chore: remove comments in find_or_create_group_conversation method

* chore: add specs for Contacts::SyncGroupService to validate group contact behavior

* chore: add specs for Whatsapp::BaileysHandlers::GroupsUpdate to validate group updates

* chore: add specs for Whatsapp::BaileysHandlers::GroupParticipantsUpdate to handle group participant actions

* chore: add fallback for identifier when contact has no phone_number in SendOnWhatsappService

* chore: add specs for group membership request and icon change handling in MessagesUpsert

* chore: add specs for sync_group method to handle group metadata and participant updates

* chore: update sync_group method to retrieve group members and adjust JSON response

* chore: update conversation query to filter by group type in GroupMembersController

* chore: update conversation creation in group_members_controller_spec to specify conversation_type as group

* chore: update find_or_create_group_conversation to include pending conversations

* chore: refactor sync_group method and enhance specs for group conversation handling

* feat: add GroupEventHelper module for managing group activities and contacts

* chore: refactor group contact inbox and conversation creation methods in group handlers

* chore: remove unnecessary check for blank participant contacts in sync_group_members method

* feat: implement message receipt update handling for WhatsApp integration

* chore: resolve rubocop rule for update_last_seen_at method

* chore: update swagger with endpoints for syncing group information and listing group members

* chore: integrate Contacts::SyncGroupService in group members controller, enhance error handling and update swagger

* chore: include participant information in reaction and quoted message keys for send message in group conversations

* chore: enhance whatsapp_baileys_service with participant handling for message keys

* feat: add skill for writing RSpec tests in the project

* fix: update recipient_id logic to directly use contact identifier for group contacts

* chore: implement group stub message handling for membership requests and icon changes

* fix: update whatsapp inbox source_id validation regex spec

* chore: fix spec for contact syncing group

* chore: remove readTimestamp handling and related tests for message read updates in group

* Cayo oliveira/cu 86af01932/4 backend gerenciamento dos grupos (#221)

* feat: add is_active index and scopes to ConversationGroupMember model

* feat: implement GroupConversationHandler for managing group conversations

* feat: add group_type attribute to contact creation

* fix: update WHATSAPP_CHANNEL_REGEX to allow up to 20 digits to handle group jid

* feat: handle group JID format in remote_jid method

* chore: update group contact info when finding or creating group contact

* chore: refactor and implement contact message handling and message creation logic for baileys single contact conversation

* feat: implement group message handling and metadata fetching in WhatsApp service

* chore: add spec for group type handling in contact creation for individual and group contacts

* chore: add specs for test scopes in conversation group members

* chore: update documentation for sender phone extraction in group conversation handler

* chore: move GroupConversationHandler concern to correct dir

* chore: implement specs for recipient_id handling to individual and group contacts

* chore: add group message handling specs for incoming messages

* chore: enhance group message handling to prevent race conditions

* chore: add group_metadata method to with error handling

* chore: add test for sending messages to group recipients in WhatsappBaileysService

* chore: raise error for unsuccessful response in group_metadata method

* chore: adds tests for group metadata retrieval and error handling

* chore: refactor build_sender_contact_attributes to avoid double call methods

* chore: update error handling for attachment download failure in message creation

* chore: optimize update_contact_info method to use compact hash for updates

* chore: simplify find_or_create_sender_contact method return values

* chore: rename group and individual contact message handlers

* chore: remove pointless comments from group contact message handler methods

* chore: refine sender JID extraction logic to remove unnecessary checks

* chore: remove phone number in spec for group contact attributes

* chore: implement sync_group route

* chore: implement get group_members route

* fix: sync_group participants creation handling

* chore: update contact avatar handling in group message processing

* chore: move sync_group functionality for conversation model

* feat: add sync_group action to ConversationsController and route

* fix: set contact name to phone in group message processing

* chore: refine group member retrieval logic in sync_group service and view

* feat: implement group participants update handling

* feat: implement group updates handling and localization for group activities

* chore: add handling for group membership requests and icon changes

* chore: add authorization for sync_group action in ContactsController

* chore: add sync_group endpoint specs for contact management

* chore: add authorization for sync_group action in ConversationsController

* chore: add specs for sync_group endpoint in ConversationsController

* chore: refactor index action in GroupMembersController for improved conversation filtering

* chore: add request specs for group_members endpoint in ContactsController

* chore: add specs for sync_group method in Conversation model

* chore: add specs for sync_group method in Channel::Whatsapp model

* chore: remove comments in find_or_create_group_conversation method

* chore: add specs for Contacts::SyncGroupService to validate group contact behavior

* chore: add specs for Whatsapp::BaileysHandlers::GroupsUpdate to validate group updates

* chore: add specs for Whatsapp::BaileysHandlers::GroupParticipantsUpdate to handle group participant actions

* chore: add fallback for identifier when contact has no phone_number in SendOnWhatsappService

* chore: add specs for group membership request and icon change handling in MessagesUpsert

* chore: add specs for sync_group method to handle group metadata and participant updates

* chore: update sync_group method to retrieve group members and adjust JSON response

* chore: update conversation query to filter by group type in GroupMembersController

* chore: update conversation creation in group_members_controller_spec to specify conversation_type as group

* chore: update find_or_create_group_conversation to include pending conversations

* chore: refactor sync_group method and enhance specs for group conversation handling

* feat: add GroupEventHelper module for managing group activities and contacts

* chore: refactor group contact inbox and conversation creation methods in group handlers

* chore: remove unnecessary check for blank participant contacts in sync_group_members method

* chore: update swagger with endpoints for syncing group information and listing group members

* chore: integrate Contacts::SyncGroupService in group members controller, enhance error handling and update swagger

* fix: update recipient_id logic to directly use contact identifier for group contacts

* chore: implement group stub message handling for membership requests and icon changes

* fix: update whatsapp inbox source_id validation regex spec

* chore: fix spec for contact syncing group

* fix: optimize update_last_seen_at method to use update_columns

* feat: Implement full frontend and backend support for group conversations

- Added PRD for group conversations detailing frontend and backend requirements.
- Created new Baileys TypeScript definitions for group-related functions.
- Renamed `conversation_type` to `group_type` in the database and updated all references.
- Implemented API serialization for `group_type` in conversation and contact responses.
- Developed Vuex store module for managing group members.
- Created UI components for group management, including group creation, member management, and metadata editing.
- Integrated @mention functionality for group conversations and real-time updates via ActionCable.

* feat: [US-001] - Rename conversation_type to group_type on conversations

- Add migration to rename column and indexes
- Update Conversation model enum to group_type
- Update GroupConversationHandler concern
- Update controllers (contacts, group_members)
- Update all backend specs

* chore: mark US-001 complete, update progress log, fix rubocop annotation

* feat: [US-002] - Serialize group_type fields in API responses

* feat: [US-003] - Add group_type filter to conversations index

* feat: [US-004] - Add group_type to filter_keys.yml and FilterService

* feat: US-005 - Backend group creation endpoint

- Add POST /api/v1/accounts/:account_id/groups endpoint
- Add Groups::CreateService to orchestrate Baileys group creation
- Extend WhatsappBaileysService and BaseService with group management methods
- Add routes for group members, metadata, invite, and join requests
- Returns 403 when agent lacks inbox access, 422 when provider is unavailable

* feat: US-006 - Backend add/remove members and role management endpoints

- Add create/destroy/update actions to GroupMembersController
- Delegate group management methods from Channel::Whatsapp to provider_service
- create adds members via Baileys and creates ConversationGroupMember records
- destroy removes a member by ID and sets is_active false
- update promotes/demotes a member and updates their role

* feat: US-007 - Backend group metadata update endpoint

- Add PATCH /contacts/:id/group_metadata endpoint
- Updates group subject via Baileys and syncs contact name
- Updates group description via Baileys and syncs additional_attributes.description
- Returns 422 when provider is unavailable

* feat: US-008 - Backend invite link management endpoints

- Add GET /contacts/:id/group_invite to retrieve current invite code/url
- Add POST /contacts/:id/group_invite/revoke to revoke and get new invite code/url
- Returns 422 when provider is unavailable

* feat: US-009 - Backend join request management endpoints

- Add GET /contacts/:id/group_join_requests to list pending join requests
- Add POST /contacts/:id/group_join_requests/handle to approve/reject requests
- Uses request_action param to avoid conflict with Rails reserved params[:action]
- Returns 422 when provider is unavailable

* feat: US-010 - Extend MentionService for contact mentions

- Extract mention://contact/ID/Name URIs from message content
- Store mentioned contact IDs in message.content_attributes[mentioned_contacts]
- Existing user/team mention handling unchanged

* feat: US-011 - Frontend API clients for all group endpoints

- Add app/javascript/dashboard/api/groupMembers.js
- Exports 11 methods: getGroupMembers, syncGroup, createGroup, updateGroupMetadata,
  addMembers, removeMembers, updateMemberRole, getInviteLink, revokeInviteLink,
  getPendingRequests, handleJoinRequest

* feat: US-012 - Frontend Vuex store module groupMembers

- Add groupMembers store module with fetch, sync, addMembers, removeMembers, updateMemberRole actions
- Add SET_GROUP_MEMBERS and SET_GROUP_MEMBERS_UI_FLAG mutation types
- Register module in store index

* feat: US-013 - Frontend i18n keys for group features

- Add groups.json with keys for group info, filter, creation modal, metadata editing, invite link, member management, join requests, and mention dropdown
- Register groups.json in i18n locale en/index.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: US-014 - Frontend group_type filter in ConversationBasicFilter

- Add chatGroupTypeFilter state, getter, mutation, and action to conversations store
- Add getChatGroupTypeFilter getter
- Add group_type param to ConversationApi.get()
- Add Type filter section to ConversationBasicFilter with All/Individual/Group options
- Persist group_type to UI settings under conversations_filter_by.group_type
- Restore group_type from UI settings on page load
- Include groupType in conversationFilters and pass as group_type param to API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: US-013 - Frontend — i18n keys for group features (en + pt-BR)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: [US-014] - Frontend — add group_type filter to ConversationBasicFilter

All implementation was already in place from prior work:
- ConversationBasicFilter.vue has Type section with All/Individual/Group options
- ChatList.vue handles group_type in conversationFilters and restores from UI settings
- Store has setChatGroupTypeFilter action, getChatGroupTypeFilter getter
- API maps groupType → group_type query param

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-015 - Frontend — add group_type to advanced filter system

- Add GROUP_TYPE to CONVERSATION_ATTRIBUTES in filterHelper.js
- Add group_type filter definition in provider.js (components-next)
- Add group_type to legacy advancedFilterItems/index.js and filterAttributeGroups
- Add group_type to automationHelper conditionFilterMaps
- Add group_type to customViewsHelper getValuesForFilter
- Add group_type options to ChatList setParamsForEditFolderModal
- Add GROUP_TYPE i18n key in en and pt_BR advancedFilters.json

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-016 - Frontend — GroupContactInfo basic display

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-017 - Frontend — GroupContactInfo sync button

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-018 - integrate GroupContactInfo in ContactPanel

- Import GroupContactInfo component
- Conditionally render GroupContactInfo when group_type === 'group'
- Keep ContactInfo for individual conversations (no regression)
- Dynamic sidebar title: 'Group' for groups, 'Contact' for individual
- contact_notes and contact_attributes accordion sections unchanged

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-019 - Frontend — group creation UI modal

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-020 - Frontend — member management UI in GroupContactInfo

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-021 - Frontend — group metadata editing UI

Add inline editing for group name, description, and avatar in GroupContactInfo:
- Click group name to edit inline, save on Enter/blur
- Click description to edit inline with textarea, save on blur
- Click avatar to open file picker for upload via contacts/update
- Loading states on all fields during save
- Success/error alerts for all operations
- updateGroupMetadata action added to groupMembers store

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-022 - Frontend — invite link management UI

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-023 - Frontend — join request management UI

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-024 - Frontend — group message bubbles: sender name with color

- Add sender name display above incoming message bubbles in group conversations
- Deterministic color per sender using AVATAR_COLORS palette (name.length % 6)
- Sender name hidden for consecutive messages from the same sender
- Individual conversation bubbles unchanged
- Pass groupWithPrevious and isGroupConversation props through MessageList → Message

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-025 - Frontend — group message bubbles: sender avatar

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: Add Ralph Wiggum AI agent script for managing tool execution and progress tracking

* feat: US-026 - Frontend — @mention dropdown for group conversations

- Create TagGroupMembers.vue component for group member mention suggestions
- Modify Editor.vue: add isGroupConversation/groupContactId props, render
  TagGroupMembers for group non-private context
- Modify ReplyBox.vue: compute isGroupConversation and groupContactId from
  currentChat, pass to WootMessageEditor
- @ mention plugin isAllowed now triggers for group conversations
- In individual conversations or private notes, existing behavior unchanged

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-027 - Frontend — mention rendering in group message bubbles

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-028 - Frontend ActionCable handler for contact.group_synced event

- Backend: Include group_members data in contact.group_synced ActionCable payload
- Frontend: Register contact.group_synced handler in ActionCableConnector
- Frontend: Add setGroupMembers action to groupMembers store for direct commits
- Tests: ActionCable handler spec + groupMembers store spec for new action

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: Update progress tracking for group conversations feature - mark tests as passing

* fix: sender click case mismatch and filter dropdown spacing

- Message.vue: use case-insensitive comparison for sender type check
  (Contact.push_event_data returns 'contact' but SENDER_TYPES.CONTACT is 'Contact')
- ConversationBasicFilter.vue: replace last:mt-4 with flex-col gap-4
  for consistent spacing between all three filter sections

* fix: four bugs found during manual testing review

- ContactPanel.vue: fix i18n key GROUP.INFO.SIDEBAR_TITLE → GROUP.SIDEBAR_TITLE
- groupMembers.js API: fix syncGroup HTTP method GET → POST to match backend route
- group_members_controller.rb: remove SyncGroupService from index action
- filterHelpers.js: add missing group_type case to getValueFromConversation

* docs: update progress with bug fix learnings

* chore: implement group creation functionality in UI components

* chore: add copy invite link functionality and update UI components

* feat: US-041 - Backend — ensure group_type is set on existing contacts and conversations

GroupConversationHandler#update_group_contact_info now sets group_type: :group
on contacts that are incorrectly typed as individual.

GroupConversationHandler#find_or_create_group_conversation updates existing
conversation's group_type to :group if it is currently :individual.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: mark US-041 as complete

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-029 - i18n keys for You badge and group settings (en + pt-BR)

All i18n keys already existed from prior iterations. Verified presence
and updated PRD status.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-030 - fix Baileys API route/method mismatches

Fix on_whatsapp to dig('data') before accessing first element.
Update spec stubs to match { data: [...] } response envelope.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-031 - group_leave, group_setting_update, group_join_approval_mode methods

All methods, delegates, and error handling already implemented.
Verified specs pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-032 - persist group settings, invite code, and profile picture during sync

Add try_update_group_avatar to fetch and attach group profile picture
during sync_group. Update spec stubs for profile-picture-url endpoint.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-033 - GroupSettingsController with leave, update, toggle

Controller and routes already implemented. Verified rubocop passes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-034 - remove inbox_contact_id from provider_config and jbuilder

Already removed in prior iterations. Verified no references remain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-035 - refactor TagGroupMembers to phone_number matching

Already implemented. Verified excludePhoneNumber prop and filtering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-036 - remove InboxContact.vue and settings tab

Already removed in prior iterations. Verified no references remain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-037 - add You badge in GroupContactInfo member list

Already implemented with isOwnMember check and blue badge styling.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-038 - fix inline edit for group name and description

Already implemented with phone number normalization. Verified code.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-039 - group settings section UI with toggles

Already implemented. Settings toggles, API calls, and i18n verified.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-040 - leave group UI with confirmation and auto-resolve

Already implemented. Leave button, confirmation, and API call verified.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-050 - Create GroupMember model and migration

New group_members table with group_contact_id, contact_id, role, is_active.
Unique index on (group_contact_id, contact_id). Associations added to Contact.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-064 - Helper method to find channel from group contact

Add Contact#group_channel to decouple channel lookup from conversations.
Update GroupMembersController and GroupSettingsController to use it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-052 - Update GroupConversationHandler to use GroupMember

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-057 - Update GroupMembersController to query GroupMember

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-058 - Update GroupSettingsController to not depend on conversations

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-060 - Update group_members jbuilder views

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-059 - Remove group_members association from Conversation model

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: US-051 - Remove ConversationGroupMember model and table

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: mark all stories complete, update progress

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(groups): real-time group panel, avatar refresh on icon change, editable name/description

- Add group_type to Conversations::EventDataPresenter#push_data and
  Contact#push_event_data so WebSocket events carry the field, enabling
  the frontend to switch to GroupContactInfo in real-time
- Update handle_icon_change_stub to call try_update_group_avatar with
  force: true, purging the cached avatar and fetching the new one
- Add force parameter to try_update_group_avatar to support re-fetching
- Remove isInboxAdmin gate from name/description editing in
  GroupContactInfo so any user can click to edit (server validates)

* fix(groups): rewrite SyncGroupService and simplify group metadata channel lookup

- Rewrite SyncGroupService to use contact.group_channel directly instead
  of iterating conversations; find or create a conversation for sync
- Simplify GroupMetadataController to use @contact.group_channel instead
  of querying conversations; remove local contact/attribute updates since
  the Baileys API handles persistence via webhook events

* feat(groups): resolve conversations when inbox phone leaves or is removed

- Add resolve_conversations_if_inbox_left to GroupParticipantsUpdate
- Resolves all open/pending conversations when the inbox phone number
  is removed from or leaves a group

* feat(groups): add paginated member list with infinite scroll

- Backend: add pagination to GroupMembersController (page/per_page,
  default 10, ordered admins first); add meta with pagination info
  to the jbuilder response
- Frontend: update groupMembers API to accept page param; add
  APPEND_GROUP_MEMBERS and SET_GROUP_MEMBERS_META mutations; implement
  paginated fetch with append and isFetchingMore flag in store

* feat(groups): support Ctrl+Click on group message sender to open in new tab

- navigateToGroupSender now accepts the event and checks for
  Ctrl/Cmd+Click to open the sender contact in a new tab

* chore(i18n): update leave group confirmation text in en and pt_BR

* fix(groups): handle phone format differences in You badge and admin detection

- Extract phonesMatch helper that compares last 8 digits as fallback,
  handling Brazilian 9th digit discrepancy (e.g. +5587988465072 vs
  +558788465072)
- Apply to both isOwnMember and isInboxAdmin computed properties

* feat(groups): auto-sync members on mount, show existing members immediately

- On mount, fetch existing DB members first so they display instantly
- Then silently attempt a background sync to refresh from WhatsApp
- If sync fails (e.g. WhatsApp disconnected), existing members remain
  displayed without any user-facing error

* fix(groups): pin own member on first page and return inbox phone in meta

The "You" badge was not appearing because the inbox's own member could be
missing from the first paginated page in large groups (admins sorted first).

Backend:
- Pin the inbox's own member at the top of page 1 regardless of sort order
- Return inbox_phone_number in the group members meta response
- Use last-8-digit SQL fallback for Brazilian 9th-digit phone mismatches

Frontend:
- Use meta.inbox_phone_number for the inboxPhone computed
- Fix declaration order to satisfy no-use-before-define lint rule

* fix(groups): fix member action dropdown clipped by overflow container

The promote/demote/remove dropdown menu was invisible because the member
list had `overflow-y-auto max-h-80`, clipping any absolutely-positioned
dropdown rendered inside it.

- Remove overflow container from member list; let the sidebar scroll
- Replace scroll-based infinite loading with IntersectionObserver on a
  sentinel element for cleaner pagination trigger
- All member action logic (promote, demote, remove) was already wired;
  the dropdown is now visible on hover

* fix(groups): keep member action dropdown visible when menu is open

The opacity-0/group-hover classes on the action menu wrapper caused the
DropdownMenu to become invisible as soon as the mouse left the row.
Now the wrapper stays fully opaque while the menu is active.

* fix(groups): move clickaway to member list wrapper to prevent instant close

v-on-clickaway was bound to every member's action div individually.
Clicking the three-dot button on one member fired closeMemberMenu from
all other members' clickaway handlers, closing the menu instantly.

Moved the directive to the single member list container instead.

* feat: add WhatsApp mention conversion (incoming + outgoing)

- New MentionConverterService for bidirectional mention handling
- Incoming: converts @phone/mentionedJid to mention://contact/ URIs
- Outgoing: extracts mention://contact/ URIs into WhatsApp mentions array
- Supports @everyone/todos group mentions
- WhatsApp renderer preserves mention display text instead of raw URI

* fix: preserve mention display text in WhatsApp renderer

mention:// URIs now render as display name text instead of the raw URL
when converting markdown to WhatsApp format

* feat: add @everyone mention option in group conversations

- Everyone item shown at top of mention dropdown
- Searchable by 'all', 'todos', 'everyone' keywords
- i18n keys added for en and pt-BR

* refactor: use Switch component for group settings toggles

- Add disabled prop to Switch component
- Replace custom toggle buttons in GroupContactInfo with Switch
- Loading spinner shown alongside toggle while toggling

* feat(whatsapp): add group sync status tracking (group_left, group_last_synced_at)

* feat(whatsapp): hide group management UI when group_left is true

* fix(groupMembers): include inbox phone number in group members state and sync event

* feat(whatsapp): wrap group settings and leave in Accordion component

* feat(groupMembers): handle group creator modification errors and update error messages

* feat(groupMembers): enhance invite link functionality and clean up UI state after copying

* refactor: remove sync_group functionality from conversations and related specs

* feat(GroupContactInfo): implement scroll-based loading for group members

* docs(swagger): add group API endpoints and remove conversation sync_group

- Remove dead conversation/{id}/sync_group swagger entry and file
- Update group_members.yml with pagination params, POST operation, and $ref schema
- Add swagger for: group_members_member (PATCH/DELETE), group_metadata,
  group_invite, group_invite_revoke, group_join_requests,
  group_join_requests_handle, group_settings, group_settings_leave,
  group_settings_toggle_join_approval, groups/create
- Add group_member schema definition
- Add Groups tag to application tag_groups
- Register all 12 group endpoints in paths/index.yml

* feat(WhatsappBaileysService): enhance mention handling by replacing @DisplayName with @lid/@phone in outgoing text

* feat(groups): move group sync to background job with 15-min cooldown

- Create Contacts::SyncGroupJob that checks group_last_synced_at
  before calling SyncGroupService (skips if < 15 min)
- Controller sync_group now enqueues the job and returns 202 Accepted
- Delete sync_group.json.jbuilder (no longer needed)
- Frontend sync action is fire-and-forget; results via ActionCable
- Auto-trigger sync on conversation select and panel mount
- Remove manual sync button from GroupContactInfo

* fix: show group members list even after leaving group\n\nKeep the members section visible in read-only mode when\ngroup_left is true. Admin actions (add member, promote,\ndemote, remove) remain hidden. Pending Join Requests and\nAdvanced Options also stay hidden.

* fix: disable group name/description/avatar editing when group_left is true

* fix: remove @all mention and fix Enter key in group mention dropdown\n\n- Remove the @all/everyone special mention from TagGroupMembers since\n  no channel provider currently supports mentioning all participants\n- Fix Enter key sending message instead of inserting selected mention\n  in group conversations. The root cause was Editor.vue only emitting\n  toggleUserMention=true for private notes (isPrivate), leaving\n  ReplyBox unaware the group mention dropdown was open. Now also\n  emits for isGroupConversation.\n- Add TagGroupMembers spec covering filtering, exclusion, and emission"

* fix: address PR review feedback for group conversations

- Fix nil safety in group_invites and group_join_requests controllers
  by replacing group_conversation.inbox.channel with @contact.group_channel
- Add before_action guard in group_members_controller to validate
  contact is a group with identifier before create/update/destroy
- Persist metadata locally in group_metadata_controller after
  provider calls (subject -> name, description -> additional_attributes)
- Add server-side allow_group_creation? check in groups_controller
- Add word boundary to mention regex to prevent matching inside words
- Remove useless catch clauses in groupMembers store (try/finally only)
- Default groupType to [] in customViewsHelper to prevent crash
- Fix swagger parameter name mismatch (contact_id -> id) across
  all group endpoint YML files for consistency

* fix: address PR #228 review feedback - strong params, guards, and safety fixes

* fix: dispatch real-time events for Baileys group participant and metadata updates

Both group-participants.update and groups.update handlers were updating
backend data (GroupMember records, Contact attributes) but never
dispatching ActionCable events, leaving the frontend member list and
group metadata stale until manual sync.

Changes:
- Add dispatch_group_synced_event helper to GroupEventHelper concern
- Dispatch CONTACT_GROUP_SYNCED after participant add/remove/promote/demote
- Dispatch CONTACT_GROUP_SYNCED after group subject/description/settings changes
- Frontend: onContactGroupSynced also dispatches contacts/updateContact
  to refresh group name, description and settings in the sidebar

* fix: enhance member menu positioning and close behavior on sidebar scroll

* feat: implement group property updates and enhance toast notifications

* fix: update WhatsApp channel regex to allow optional hyphenated numbers

* feat: implement group admin functionalities including leave, update properties, and toggle join approval

* refactor: simplify group message handling by removing metadata fetching and syncing methods

* chore: remove raph files

* feat: update Portuguese translations for 'Read More' and 'Insert Read More' phrases

* feat: enhance group admin functionalities with join approval and member add modes

* feat: enhance group join request handling by adding removal of handled requests and updating pending join requests

* feat: restrict message sending in announcement mode groups

When a Baileys WhatsApp group has announcement mode enabled (announce=true),
only admin members can send messages. This adds:
- Frontend: disabled editor + banner for non-admin inbox in announcement groups
- Backend: validation in SendOnWhatsappService to reject messages
- Shared phone helper utility extracted from GroupContactInfo
- i18n keys for en and pt_BR

* feat: add group sync job enqueueing and improve avatar update handling

* feat: add functionality to reset invite link and confirm member addition restrictions

* feat: update group name extraction logic to handle nil values

* feat: add inbox admin status handling and update related components

* feat: remove group conversation resolution on leave action

* feat: enhance group sender avatar interaction with tooltip and cursor pointer

* feat: add force option to SyncGroupJob and update related specs

* feat: enhance invite link handling and avatar update logic in group conversations

* chore: remove prd.json

* fix: change group sender name display from block to inline-block for better layout

* feat: add group members loading check and fetch logic in MessagesView and ReplyBox components

* feat: allow id and firstUnreadId props to accept both Number and String types
feat: add vOnClickOutside import to Editor component
feat: enhance Portuguese translations for integrations and settings
fix: change button color in GroupContactInfo component from green to teal

* feat: soft-disabled group conversations with activity tracking

Groups start in a soft-disabled state by default when using Baileys.
Chatwoot still creates group conversations but does not process every
incoming message. Instead, Baileys accumulates group messages and sends
periodic groups.activity webhook events to update last_activity_at.

Backend:
- Add WHATSAPP_GROUPS_ENABLED env var and groups_enabled? class method
- Send groupsEnabled in Baileys connection setup
- Create groups.activity handler to update conversation last_activity_at
- Gate group message processing behind groups_enabled? check
- Expose groups_enabled via inbox API

Frontend:
- Add warning banner with CTA to app.fazer.ai on disabled group conversations
- Disable reply editor for non-private-note mode when groups disabled
- Add i18n strings for en and pt_BR

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use method for groups disabled banner action to avoid window scope issue

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: broadcast conversation update after groups.activity event

update_columns bypasses ActiveRecord callbacks, so the ActionCable
broadcast was never triggered when last_activity_at changed. Dispatch
a CONVERSATION_UPDATED event explicitly so the sidebar updates in
real-time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: show unread dot for soft-disabled group conversations with activity

Since soft-disabled groups don't create messages, unread_count is
always 0 and the standard badge won't show. Detect unread state by
comparing last_activity_at > agent_last_seen_at for these groups
and display a teal dot indicator instead of a count badge.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: clear unread dot when agent opens soft-disabled group conversation

The update_last_seen endpoint skipped updating agent_last_seen_at when
there were no unread messages (the throttle path). For soft-disabled
groups that never create messages, this meant the dot indicator could
never be cleared. Add an unseen_activity? check that bypasses the
throttle when last_activity_at > agent_last_seen_at.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: group avatar upload to provider and fix icon change sync

- Route avatar upload through GroupMetadataController to push to WhatsApp
  provider before saving locally
- Add update_group_picture to baileys service and base service
- Fix buildContactFormData crash when social_profiles is undefined
- Make try_update_group_avatar public so GROUP_CHANGE_ICON stub handler
  can call it from outside the service class

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update specs for group conversations feature changes

- Add groupsEnabled param to setup_channel_provider and handle_channel_error WebMock stubs
- Add group-request-participants-list stub for sync_group tests
- Add group_type to push_event_data expected hash
- Set last_activity_at in throttle tests to prevent unseen_activity? bypass
- Update sync_group delegation expectation to include soft: false
- Stub groups_enabled? in group message handling tests
- Update WhatsApp source_id regex expectation for group contact IDs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add settings file for additional directories configuration

* chore: undo unrelated changes

* chore: remove planning doc, fix migration version, fix swagger param consistency

- Remove planejamento-chat-interno.md (unrelated planning document)
- Fix CreateGroupMembers migration API version from 7.0 to 7.1
- Fix swagger.json: normalize group endpoint paths from {contact_id} to {id}
  to match YAML sources and existing contact sub-resource conventions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: CayoPOliveira <cayoproliveira@gmail.com>
Co-authored-by: Cayo P. R. Oliveira <cayo@fazer.ai>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-19 21:56:58 -03:00
Sivin Varghese
4e0b091ef8
fix: Prevent unsupported file types on clipboard paste (#13182)
# Pull Request Template

## Description

This PR adds file type validation for clipboard-pasted attachments and
prevents unsupported file types from being attached across channels.

https://developers.chatwoot.com/self-hosted/supported-features#outgoing-attachments-supported-file-types

Fixes
https://linear.app/chatwoot/issue/CW-6233/bug-unsupported-file-types-allowed-via-clipboard-paste

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

**Loom video**

**Before**
https://www.loom.com/share/882c335be4894d86b9e149d9f7560e72

**After**
https://www.loom.com/share/90ad9605fc4446afb94a5b8bbe48f7db


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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: Muhsin Keloth <muhsinkeramam@gmail.com>
2026-01-14 13:07:46 +04:00
Mazen Khalil
ca5e112a8c
feat: TikTok channel (#12741)
fixes: #11834

This pull request introduces TikTok channel integration, enabling users
to connect and manage TikTok business accounts similarly to other
supported social channels. The changes span backend API endpoints,
authentication helpers, webhook handling, configuration, and frontend
components to support TikTok as a first-class channel.


**Key Notes**
* This integration is only compatible with TikTok Business Accounts
* Special permissions are required to access the TikTok [Business
Messaging
API](https://business-api.tiktok.com/portal/docs?id=1832183871604753).
* The Business Messaging API is region-restricted and is currently
unavailable to users in the EU.
* Only TEXT, IMAGE, and POST_SHARE messages are currently supported due
to limitations in the TikTok Business Messaging API
* A message will be successfully sent only if it contains text alone or
one image attachment. Messages with multiple attachments or those
combining text and attachments will fail and receive a descriptive error
status.
* Messages sent directly from the TikTok App will be synced into the
system
* Initiating a new conversation from the system is not permitted due to
limitations from the TikTok Business Messaging API.


**Backend: TikTok Channel Integration**

* Added `Api::V1::Accounts::Tiktok::AuthorizationsController` to handle
TikTok OAuth authorization initiation, returning the TikTok
authorization URL.
* Implemented `Tiktok::CallbacksController` to handle TikTok OAuth
callback, process authorization results, create or update channel/inbox,
and handle errors or denied scopes.
* Added `Webhooks::TiktokController` to receive and verify TikTok
webhook events, including signature verification and event dispatching.
* Created `Tiktok::IntegrationHelper` module for JWT-based token
generation and verification for secure TikTok OAuth state management.

**Configuration and Feature Flags**

* Added TikTok app credentials (`TIKTOK_APP_ID`, `TIKTOK_APP_SECRET`) to
allowed configs and app config, and registered TikTok as a feature in
the super admin features YAML.
[[1]](diffhunk://#diff-5e46e1d248631a1147521477d84a54f8ba6846ea21c61eca5f70042d960467f4R43)
[[2]](diffhunk://#diff-8bf37a019cab1dedea458c437bd93e34af1d6e22b1672b1d43ef6eaa4dcb7732R69)
[[3]](diffhunk://#diff-123164bea29f3c096b0d018702b090d5ae670760c729141bd4169a36f5f5c1caR74-R79)

**Frontend: TikTok Channel UI and Messaging Support**

* Added `TiktokChannel` API client for frontend TikTok authorization
requests.
* Updated channel icon mappings and tests to include TikTok
(`Channel::Tiktok`).
[[1]](diffhunk://#diff-b852739ed45def61218d581d0de1ba73f213f55570aa5eec52aaa08f380d0e16R16)
[[2]](diffhunk://#diff-3cd3ae32e94ef85f1f2c4435abf0775cc0614fb37ee25d97945cd51573ef199eR64-R69)
* Enabled TikTok as a supported channel in contact forms, channel
widgets, and feature toggles.
[[1]](diffhunk://#diff-ec59c85e1403aaed1a7de35971fe16b7033d5cd763be590903ebf8f1ca25a010R47)
[[2]](diffhunk://#diff-ec59c85e1403aaed1a7de35971fe16b7033d5cd763be590903ebf8f1ca25a010R69)
[[3]](diffhunk://#diff-725b90ca7e3a6837ec8291e9f57094f6a46b3ee00e598d16564f77f32cf354b0R26-R29)
[[4]](diffhunk://#diff-725b90ca7e3a6837ec8291e9f57094f6a46b3ee00e598d16564f77f32cf354b0R51-R54)
[[5]](diffhunk://#diff-725b90ca7e3a6837ec8291e9f57094f6a46b3ee00e598d16564f77f32cf354b0R68)
* Updated message meta logic to support TikTok-specific message statuses
(sent, delivered, read).
[[1]](diffhunk://#diff-e41239cf8dda36c1bd1066dbb17588ae8868e56289072c74b3a6d7ef5abdd696R23)
[[2]](diffhunk://#diff-e41239cf8dda36c1bd1066dbb17588ae8868e56289072c74b3a6d7ef5abdd696L63-R65)
[[3]](diffhunk://#diff-e41239cf8dda36c1bd1066dbb17588ae8868e56289072c74b3a6d7ef5abdd696L81-R84)
[[4]](diffhunk://#diff-e41239cf8dda36c1bd1066dbb17588ae8868e56289072c74b3a6d7ef5abdd696L103-R107)
* Added support for embedded message attachments (e.g., TikTok embeds)
with a new `EmbedBubble` component and updated message rendering logic.
[[1]](diffhunk://#diff-c3d701caf27d9c31e200c6143c11a11b9d8826f78aa2ce5aa107470e6fdb9d7fR31)
[[2]](diffhunk://#diff-047859f9368a46d6d20177df7d6d623768488ecc38a5b1e284f958fad49add68R1-R19)
[[3]](diffhunk://#diff-c3d701caf27d9c31e200c6143c11a11b9d8826f78aa2ce5aa107470e6fdb9d7fR316)
[[4]](diffhunk://#diff-cbc85e7c4c8d56f2a847d0b01cd48ef36e5f87b43023bff0520fdfc707283085R52)
* Adjusted reply policy and UI messaging for TikTok's 48-hour reply
window.
[[1]](diffhunk://#diff-0d691f6a983bd89502f91253ecf22e871314545d1e3d3b106fbfc76bf6d8e1c7R208-R210)
[[2]](diffhunk://#diff-0d691f6a983bd89502f91253ecf22e871314545d1e3d3b106fbfc76bf6d8e1c7R224-R226)

These changes collectively enable end-to-end TikTok channel support,
from configuration and OAuth flow to webhook processing and frontend
message handling.


------------

# TikTok App Setup & Configuration
1. Grant access to the Business Messaging API
([Documentation](https://business-api.tiktok.com/portal/docs?id=1832184145137922))
2. Set the app authorization redirect URL to
`https://FRONTEND_URL/tiktok/callback`
3. Update the installation config with TikTok App ID and Secret
4. Create a Business Messaging Webhook configuration and set the
callback url to `https://FRONTEND_URL/webhooks/tiktok`
([Documentation](https://business-api.tiktok.com/portal/docs?id=1832190670631937))
. You can do this by calling
`Tiktok::AuthClient.update_webhook_callback` from rails console once you
finish Tiktok channel configuration in super admin ( will be automated
in future )
5. Enable TikTok channel feature in an account

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
2025-12-17 07:54:50 -08:00
Sojan Jose
bf806f0c28
feat: allow configuring attachment upload limit (#12835)
## Summary
- add a configurable MAXIMUM_FILE_UPLOAD_SIZE installation setting and
surface it through super admin and global config payloads
- apply the configurable limit to attachment validations and shared
upload helpers on dashboard and widget
- introduce a reusable helper with unit tests for parsing the limit and
extend attachment specs for configurability


------
[Codex
Task](https://chatgpt.com/codex/tasks/task_e_6912644786b08326bc8dee9401af6d0a)

---------

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
2025-11-17 14:03:08 -08:00
Tanmay Deep Sharma
4014a846f0
feat: Add the frontend support for MFA (#12372)
FE support for https://github.com/chatwoot/chatwoot/pull/12290
## Linear:
- https://github.com/chatwoot/chatwoot/issues/486

## Description
This PR implements Multi-Factor Authentication (MFA) support for user
accounts, enhancing security by requiring a second form of verification
during login. The feature adds TOTP (Time-based One-Time Password)
authentication with QR code generation and backup codes for account
recovery.

## Type of change

- [ ] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

- Added comprehensive RSpec tests for MFA controller functionality
- Tested MFA setup flow with QR code generation
- Verified OTP validation and backup code generation
- Tested login flow with MFA enabled/disabled

## Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] 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
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] 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 <pranav@chatwoot.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2025-09-18 21:16:06 +05:30
Sivin Varghese
d45527b851
feat: Retry failed messages within 24h (#12436)
Fixes [CW-5540](https://linear.app/chatwoot/issue/CW-5540/feat-allow-retry-a-failed-message-sendout),
https://github.com/chatwoot/chatwoot/issues/12333

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

### Screenshot
<img width="196" height="113" alt="image"
src="https://github.com/user-attachments/assets/8b4a1aa9-c75c-4169-b4a2-e89148647e91"
/>



## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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: Muhsin Keloth <muhsinkeramam@gmail.com>
2025-09-16 21:00:15 +05:30
Tanmay Deep Sharma
2f3b4ad215
feat: add FE changes for captain pdf support for faq generation (#12115)
Linked PR
https://github.com/chatwoot/chatwoot/pull/12113

## Linear Link
https://linear.app/chatwoot/issue/CW-4515/upload-pdfs-to-captain

## Description

This PR adds support for PDF file uploads to the Captain document
knowledge base system. The feature enables users to upload PDF files
directly to the knowledge base for FAQ generation and document
processing, expanding beyond the existing URL-based document ingestion.

## Type of change

- [ ] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

- Unit Tests
- Manually via UI



## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [x] 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
- [x] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
2025-09-02 19:01:16 +05:30
Sivin Varghese
f9c258f1a0
fix: Prevent [object Object] when copying custom attributes (#12323)
# Pull Request Template

## Description

This PR fixes custom conversation attributes copying as `[object
Object]` by enhancing the clipboard helper to properly serialize objects
and handle different data types.


Fixes
[CW-5428](https://linear.app/chatwoot/issue/CW-5428/copying-custom-conversation-attribute-returns-object-object-instead-of),
https://github.com/chatwoot/chatwoot/issues/12202

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

### Loom video

https://www.loom.com/share/f52db17d4d524b3cbb5badb2b6f381eb?sid=2b34f38f-e95d-4981-be5f-6cb42a0212b9


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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
2025-09-01 13:02:35 +05:30
Sivin Varghese
24ea968b00
chore: Remove older UI (#11720) 2025-07-01 09:43:44 +05:30
Sivin Varghese
cc8866a84e
feat: Sync Popular Articles locale with widget locale (#11754)
# Pull Request Template

## Description

This PR includes the following improvements:
* **Popular Articles Locale Selection based on Widget Locale**
  * Implements priority-based locale matching:
    * Exact locale match (e.g., "fr" === "fr")
    * Base language match (e.g., "fr" when selected is "fr_CA")
    * Variant match (e.g., "fr_BE" when selected is "fr")
* Removes default locale fallback - if no locale match is found, popular
articles section is hidden.
    
* Fixed **API** filter issue where the locale parameter was previously
ignored

* Hides Popular Articles section completely when no locale match is
found and Only shows relevant articles in the user's language


* **RTL Direction Handling Improvements**
* Now directly reads the `lang` attribute from HTML element `<html
lang="en">` instead of relying on `.locale-switcher` and sets direction
attribute based on language.

* Adds `data-dir-applied` attribute to prevent overlapping direction
settings between global helpers and components (eg case: Insert article
in editor dashboard)

* Update `IframeLoader.vue` to Composition API and improve the **dir**
logic

Fixes 
1.
[CW-4505](https://linear.app/chatwoot/issue/CW-4505/popular-articles-not-displayed-based-on-user-locale-in-live-chat),
https://github.com/chatwoot/chatwoot/issues/11745
2. RTL direction is not working in widget article view after merging
this PR https://github.com/chatwoot/chatwoot/pull/11692

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

### Loom video

**Popular Articles**

https://www.loom.com/share/7cecbaaa77eb48e19263398b6ba8ddef?sid=a2452b8e-7d7e-46a3-b5c8-aed5ab5bc801

**RTL improvements**

https://www.loom.com/share/3ccad77174a0412097e802641df5f3e0?sid=e10ac57f-5c49-4084-84d3-5ad58aee54fa

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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: Muhsin Keloth <muhsinkeramam@gmail.com>
2025-06-24 19:52:44 +05:30
Sivin Varghese
2ee63656e2
feat: Prevent saving preferences and status when impersonating (#11164)
This PR will prevent saving user preferences and online status when impersonating. Previously, these settings could be updated during impersonation, causing the user to see a different view or UI settings.

Fixes https://linear.app/chatwoot/issue/CW-4163/impersonation-improvements
2025-05-20 17:34:30 -07:00
Sivin Varghese
73f768e0bf
fix: Handle slug validation errors in Help Center (#11368)
# Pull Request Template

## Description

This PR fixes an issue with slug validation in the Help Center portal
settings. Previously, users were able to create or update slugs with
invalid characters such as spaces, slashes, and special symbols, which
cause help center to crash.

With this update, slug creation and updates are now properly validated.
Only slugs that match the allowed pattern will be accepted. No spaces,
underscores, slashes, or special characters are allowed.

Examples: **user**, **user-guide**

---

Fixes
https://linear.app/chatwoot/issue/CW-4273/add-validation-for-help-centre-slugs

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

### Loom video

https://www.loom.com/share/a2ca5e2104984f28b29539293ffed33a?sid=e5064cb8-6220-4c43-99da-242c25d32027


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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
2025-04-24 16:58:05 +05:30
Muhsin Keloth
0a394e16ca
chore: Audit message characters across all channels (#11343)
- Audited message characters across all channels.
- Replaced `isAInstagramChannel` with `isAnInstagramChannel`
2025-04-21 14:46:51 +05:30
Muhsin Keloth
41d6f9a200
chore: Add cache to improve widget performance (#11163)
- Add dynamic importing for routes.
- Added caching for `campaign`, `articles` and `inbox_members` API end
points.

---------

Co-authored-by: Pranav <pranavrajs@gmail.com>
2025-03-24 16:04:49 -07:00
Tarush Nagpal
11a7414dc0
feat: Upgrade Dyte apis to v2 (#10706)
# Pull Request Template

## Description

Dyte V1 API's are soon going to be deprecated, hence making sure we
update Chatwoot before that happens

Fixes #10704

## Type of change

Please delete options that are not relevant.

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

1. Open a new or existing conversation from the inbox
2. Press the video call icon on the message composer
3. Verify that the message dialog shows up with the join video call
button
4. Verify that clicking on join call does join the call

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [ ] New and existing unit tests pass locally with my changes (Unable
to run this locally)

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2025-02-19 14:47:48 -08:00
Sivin Varghese
b429ce0ad5
fix: Prevent template variables from becoming links (#10725)
# Pull Request Template

## Description

**Issue**
This PR fixes template variables in messages (e.g., {{customer.name}})
that were being incorrectly converted to clickable links by the
`MessageFormatter's linkify` functionality. This caused formatting
issues and broken links.

**Solution**
Added a `linkify` parameter to `MessageFormatter` to optionally disable
link conversion

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

**Screenshots**

**Before**
<img width="1012" alt="image"
src="https://github.com/user-attachments/assets/70abb238-b4d9-439d-9e51-c7513cf482fb"
/>


**After**
<img width="1012" alt="image"
src="https://github.com/user-attachments/assets/387acb74-674e-4b26-85cc-2d7190d256b1"
/>




## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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
2025-01-23 18:18:14 +05:30
Shivam Mishra
42f6621afb
feat: Vite + vue 3 💚 (#10047)
Fixes https://github.com/chatwoot/chatwoot/issues/8436
Fixes https://github.com/chatwoot/chatwoot/issues/9767
Fixes https://github.com/chatwoot/chatwoot/issues/10156
Fixes https://github.com/chatwoot/chatwoot/issues/6031
Fixes https://github.com/chatwoot/chatwoot/issues/5696
Fixes https://github.com/chatwoot/chatwoot/issues/9250
Fixes https://github.com/chatwoot/chatwoot/issues/9762

---------

Co-authored-by: Pranav <pranavrajs@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2024-10-02 00:36:30 -07:00
Sojan Jose
bb74c621b5
chore: Bump up character limit for email channel (#10082) 2024-09-07 08:41:18 +05:30
Sivin Varghese
d1d1398d80
feat: Rewrite customAttributeMixin to validation helper (#9916)
# Pull Request Template

## Description

This PR will replace the use of `customAttributeMixin` with
`shared/helpers/Validators` helper.

Fixes
https://linear.app/chatwoot/issue/CW-3446/rewrite-customattributemixin-mixin-to-a-composable

**Files updated**
1. widget/components/PreChat/Form.vue
2. dashboard/components/CustomAttribute.vue
3. dashboard/routes/dashboard/settings/attributes/EditAttribute.vue

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

Test the custom validation is working or not with the custom attributes.


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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
2024-08-09 18:37:26 +05:30
Sivin Varghese
e0b67bb552
feat: Rewrite keyboardEventListener mixin to a composable (#9831) 2024-08-05 18:59:47 +05:30
Sivin Varghese
79381b08cc
feat: Move timeMixin to a helper (#9799)
# Pull Request Template

## Description

This PR will replace the usage of `timeMixin` with `timeHelper`

Fixes
https://linear.app/chatwoot/issue/CW-3451/move-time-mixin-to-a-helper

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

Please refer to this issue description.
https://linear.app/chatwoot/issue/CW-3451/move-time-mixin-to-a-helper

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] 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>
2024-07-22 13:07:29 +05:30
Pranav
9de8c27368
feat: Use vitest instead of jest, run all the specs anywhere in app/ folder in the CI (#9722)
Due to the pattern `**/specs/*.spec.js` defined in CircleCI, none of the
frontend spec in the folders such as
`specs/<domain-name>/getters.spec.js` were not executed in Circle CI.

This PR fixes the issue, along with the following changes: 
- Use vitest instead of jest
- Remove jest dependancies
- Update tests to work with vitest

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2024-07-10 08:32:16 -07:00
Sivin Varghese
af90f21cfd
feat: Reconnect logic (#9453)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
2024-06-03 15:54:19 +05:30
Fayaz Ahmed
b474929f5e
chore: Replace eventBus with mitt.js [CW-3275] (#9539)
# Replace the deprecated `eventBus` with mitt.js

## Description

Since eventBus and it's respective methods are deprecated and removed
from all future releases of vue, this was blocking us from migrating.
This PR replaces eventBus with
[mitt](https://github.com/developit/mitt). I have created a wrapper
mitt.js to simulate the same old event names so it's backwards
compatible, without making a lot of changes.


Fixes # (issue)

## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## How Has This Been Tested?

1. Made sure all the places we're listening to bus events are working as
expected.
2. Respective specsf or the events from mitt.


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [x] 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
- [x] Any dependent changes have been merged and published in downstream
modules
2024-05-31 15:50:36 +05:30
Shivam Mishra
47f8b2cd0c
refactor: handling keyboard shortcuts (#9242)
* fix: Resolve and go next keyboard shortcuts doesn't work

* refactor: use buildHotKeys instead of  hasPressedCommandPlusAltAndEKey

* feat: install tinykeys

* refactor: use tinykeys

* test: update buildKeyEvents

* fix: remove stray import

* feat: handle action list globally

* feat: allow configuring `allowOnFocusedInput`

* chore: Navigate chat list item

* chore: Navigate dashboard

* feat: Navigate editor top panel

* feat: Toggle file upload

* chore: More keyboard shortcuts

* chore: Update mention selection mixin

* chore: Phone input

* chore: Clean up

* chore: Clean up

* chore: Dropdown and editor

* chore: Enter key to send and clean up

* chore: Rename mixin

* chore: Review fixes

* chore: Removed unused shortcut from modal

* fix: Specs

---------

Co-authored-by: iamsivin <iamsivin@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2024-04-26 15:41:02 +05:30
Sivin Varghese
3adaa2d602
fix: Retry message not working if the conversation has an external issue (#8529) 2023-12-13 15:46:10 +05:30
Sivin Varghese
2d1f70eb79
feat: Update public portal colors with new design (#8230) 2023-11-23 08:16:52 +05:30
Sivin Varghese
e0f33e62af
feat: Adds support for image resize in the message bubble (#8182) 2023-11-08 14:11:47 +05:30
Shivam Mishra
cbae95422d
feat: Implement reply to for reply editor (#8063)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2023-10-10 19:13:12 +05:30
Shivam Mishra
081c845c56
chore: Remove twitter actions (#8079) 2023-10-10 16:48:58 +05:30
Shivam Mishra
a88d155dd7
feat: update tool-chain to latest (#7975)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2023-09-27 14:02:34 +05:30
Shivam Mishra
c83105ce4f
feat: dismiss label suggestions only for 24 hours (#7579)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2023-07-24 17:51:09 +05:30
Sivin Varghese
1176e5eb8a
feat: Custom phone input in pre-chat form (#7275)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2023-06-26 10:26:06 +05:30
Shivam Mishra
996325f35b
feat: multiple UX improvements to labels (#7358)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2023-06-25 18:49:49 +05:30
Muhsin Keloth
2c34dca347
fix: NS_ERROR_STORAGE_BUSY warnings in firefox (#7319)
Fixes: https://linear.app/chatwoot/issue/CW-2075/ns-error-storage-busy-no-error-message
2023-06-15 17:53:26 +05:30
Sivin Varghese
b333d0c986
feat: Attachments view (#7156)
* feat: Attachments view with key shortcuts and dynamically updates when user delete or sent new attachments

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2023-06-05 19:21:47 +05:30
Sojan
1f4d096804 Merge branch 'hotfix/2.17.1' into develop 2023-05-19 20:56:16 +05:30
Sivin Varghese
1bcc438b21
fix: Problem when using Brazilian Portuguese (#7135)
Fixes:  #7127
2023-05-19 20:55:01 +05:30
Shivam Mishra
105f9a27d2
feat: more CSAT filters (#7038)
* refactor: use grid instead of flex

* refactor: let the parent layout decide the spacing

* feat: add a separate date-range component

* refactor: use new date-range component

* fix: destructure all options

* refactor: separate group by component

* refactor: better handle group by data

* fix: defaul group by

* refactor: variable naming

* refactor: use DATE_RANGE_OPTIONS directly

* chore: update platform in gemfile.lock

* refactor: trigger fetch on filter change

* refactor: remove redundant method

* refactor: simplify methods and emitting

* refactor: simplify filter logic

* refactor: simplify fetching

* refactor: imports

* refactor: prop name

* refactor: CSAT response to use new APIs

* refactor: use common filter event

* refactor: use computed value for validGroupBy

* refactor: better function names

* refactor: rename prop

* refactor: remove redundant props

* refactor: separate agents filter component

* feat: add labels filter

* feat: add inboxes filter

* fix: event

* refactor: send label and inbox along with request payload

* feat: add inbox filter

* feat: add inbox to download

* refactor: use request payload from computed property

* refactor: params

* feat: add team to csat filters

* feat: add team to csat filters

* feat: add filter for rating

* feat: reverse options

* feat: add labels for ratings and translations

* feat: update translation

* fix: margin and spacing

* fix: trailing whitespace

* feat: add tests for filters

* chore: move files

* feat: add try catch with alerts

* feat: update import

* fix: imports

* Updates broken imports

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2023-05-18 22:50:46 +05:30
Sivin Varghese
198cd9b28d
feat: Show next available day/hour and minutes on widget (#6902)
* feat: Show next available hour and minutes on widget

* chore: Adds spec

* chore: Show days

* chore: Code clean up

* chore: Review fixes

* chore: Minor fixes

* chore: Review suggestion fixes

* chore: Minor fixes

* Added timezone to widget payload

* chore: Adds time zone

* chore: Review fixes

* chore: Adds comments

* chore: Rounded up min with nearest multiple of 5

* chore: Review fixes

* chore: Review fixes

* chore: Review fixes

* chore: Review fixes

* chore: Fix specs

* chore: Review fixes

* chore: Fix specs

* chore: Review fixes

* chore: Moved day names to i18n

* chore: Review fixes

* chore: Fix specs

---------

Co-authored-by: Tejaswini Chile <tejaswini@chatwoot.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
2023-05-12 19:25:51 +05:30
Muhsin Keloth
13fe439d9f
Move the reconnect logic from the update presence (#6992) 2023-04-28 14:02:30 +05:30
Muhsin Keloth
815322b27a
feat: Refetch the active conversation messages on action cable reconnect (#6790) 2023-04-24 10:17:12 +05:30
Sivin Varghese
c9ce9e5b8f
feat: Improved country code in contact form view. (#6801)
* feat: Improved country code in contact.

* chore: Minor fixes

* chore: Minor fixes

* chore: Adds arrow key navigation and cursor pointer

* chore: Minor fix

* chore: Code clean up

* chore: Handle outside click

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>, Nithin David
2023-04-17 20:32:09 +05:30
Nithin David Thomas
09ce85b30d
Chore: moves localstorage helper as a shared utility (#6838)
* Chore: moves localstorage helper as a shared utility and refactors constants

* Refactors constants file

* Fixes merge conflicts

* Delete constants.js

---------

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2023-04-11 15:50:46 +05:30
balawa
2ca8726005
feat: Extend the message limit for the Facebook Channels (#6816) 2023-04-04 12:07:13 -07:00
Shivam Mishra
c88792f4a3
feat: add Conversation traffic heatmap (#6508)
* feat: add heatmap component

* feat: add heatmap component

* feat: add dummy heatmap

* refactor: compact tiles

* feat: allow hour

* feat: wire up heatmap query

* feat: allow arbritrary number of weeks

* feat: update position of the widget

* chore: update heatmap title

* refactor: move traffic heatmap to overview

* chore: add comment for perf

* feat: add reconcile logic for heatmap fetching

Fetching the data for the last 6 days all the time is wasteful
So we fetch only the data for today and reconcile it with the data we already have

* refactor: re-org code for new utils

* feat: add translations

* feat: translate days of the week

* chore: update chatwoot utils

* feat: add markers to heatmap

* refactor: update class names

* refactor: move flatten as a separate method

* test: Heatmap Helpers

* chore: add comments

* refactor: method naming

* refactor: use heatmap-level mixin

* refactor: cleanup css

* chore: remove log

* refactor: reports.js to use object instead of separate params

* refactor: report store to use new API design

* refactor: rename HeatmapHelper -> ReportsDataHelper

* refactor: separate clampDataBetweenTimeline

* feat: add tests

* fix: group by hour

* feat: add scroll for smaller screens

* refactor: add base data to reconcile with

* fix: tests

* fix: overflow only on smaller screens

* feat: translate tooltip

* refactor: simplify reconcile

* chore: add docs

* chore: remoev heatmap from account report

* feat: let Heatmap handle loading state

* chore: Apply suggestions from code review

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

* feat: update css

* refactor: color assignment to range

* feat: add short circuit

* Update app/javascript/dashboard/routes/dashboard/settings/reports/components/Heatmap.vue

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2023-03-07 09:01:58 +05:30
Pranav Raj S
2a385f377c
chore: Use markdown-it instead of marked (#6123)
* chore: Use markdown-it instead of marked

* Adds styling for markdown rendered content

* fixes codeclimate issue

* Fixes blockquote styles for widget in darkmode

* fix: issue block quote color issue in light mode

* fix: issue block quote color issue in light mode

* Fixes blockquote color in dark mode

* Remove usage of dark mode mixin in user bubble

* chore: code clean up

---------

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
2023-03-03 13:26:54 +05:30
Sivin Varghese
14382ad881
fix: Not able to create a portal if the custom domain is empty (#6224) 2023-01-10 20:50:35 +05:30
Pranav Raj S
ffb4bd0109
feat: Add the support for video calls with Dyte in the live-chat widget (#6208)
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
2023-01-09 11:52:31 -08:00
Sivin Varghese
0a65a233d7
fix: Invalid portal domain validation (#6166)
* fix: Invalid portal domain validation


Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2023-01-09 13:42:19 +05:30