Merge branch 'develop' into fix/next-message-bubbles

This commit is contained in:
Sivin Varghese
2025-02-21 12:08:03 +05:30
committed by GitHub
18 changed files with 195 additions and 61 deletions
@@ -10,7 +10,7 @@ class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseControl
def create
authorize @inbox, :create?
ActiveRecord::Base.transaction do
agents_to_be_added_ids.map { |user_id| @inbox.add_member(user_id) }
@inbox.add_members(agents_to_be_added_ids)
end
fetch_updated_agents
end
@@ -24,7 +24,7 @@ class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseControl
def destroy
authorize @inbox, :destroy?
ActiveRecord::Base.transaction do
params[:user_ids].map { |user_id| @inbox.remove_member(user_id) }
@inbox.remove_members(params[:user_ids])
end
head :ok
end
@@ -41,8 +41,8 @@ class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseControl
# the missing ones are the agents which are to be deleted from the inbox
# the new ones are the agents which are to be added to the inbox
ActiveRecord::Base.transaction do
agents_to_be_added_ids.each { |user_id| @inbox.add_member(user_id) }
agents_to_be_removed_ids.each { |user_id| @inbox.remove_member(user_id) }
@inbox.add_members(agents_to_be_added_ids)
@inbox.remove_members(agents_to_be_removed_ids)
end
end
@@ -9,14 +9,14 @@ class Api::V1::Accounts::TeamMembersController < Api::V1::Accounts::BaseControll
def create
ActiveRecord::Base.transaction do
@team_members = members_to_be_added_ids.map { |user_id| @team.add_member(user_id) }
@team_members = @team.add_members(members_to_be_added_ids)
end
end
def update
ActiveRecord::Base.transaction do
members_to_be_added_ids.each { |user_id| @team.add_member(user_id) }
members_to_be_removed_ids.each { |user_id| @team.remove_member(user_id) }
@team.add_members(members_to_be_added_ids)
@team.remove_members(members_to_be_removed_ids)
end
@team_members = @team.members
render action: 'create'
@@ -24,7 +24,7 @@ class Api::V1::Accounts::TeamMembersController < Api::V1::Accounts::BaseControll
def destroy
ActiveRecord::Base.transaction do
params[:user_ids].map { |user_id| @team.remove_member(user_id) }
@team.remove_members(params[:user_ids])
end
head :ok
end
@@ -479,7 +479,7 @@ provideMessageContext({
>
<div
v-if="!shouldGroupWithNext && shouldShowAvatar"
v-tooltip.left-end="avatarTooltip"
v-tooltip.right-end="avatarTooltip"
class="[grid-area:avatar] flex items-end"
>
<Avatar v-bind="avatarInfo" :size="20" />
@@ -31,7 +31,7 @@ const senderName = computed(() => {
<template>
<BaseBubble class="overflow-hidden p-3" data-bubble-name="attachment">
<div class="grid gap-4 min-w-64">
<div class="grid gap-3 z-20">
<div class="grid gap-3">
<div
class="size-8 rounded-lg grid place-content-center"
:class="iconBgColor"
@@ -34,7 +34,7 @@ const joinTheCall = async () => {
};
const leaveTheRoom = () => {
this.dyteAuthToken = '';
dyteAuthToken.value = '';
};
const action = computed(() => ({
label: t('INTEGRATION_SETTINGS.DYTE.CLICK_HERE_TO_JOIN'),
@@ -60,7 +60,7 @@ const action = computed(() => ({
allow="camera;microphone;fullscreen;display-capture;picture-in-picture;clipboard-write;"
/>
<button
class="px-4 py-2 text-sm rounded-lg bg-n-solid-3"
class="px-4 py-2 text-sm rounded-lg bg-n-solid-3 mt-3"
@click="leaveTheRoom"
>
{{ $t('INTEGRATION_SETTINGS.DYTE.LEAVE_THE_ROOM') }}
@@ -266,7 +266,7 @@
"ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>."
},
"SEARCH": {
"ERROR": "ERROR_MESSAGE"
"ERROR_MESSAGE": "Something went wrong. Please try again later."
},
"FORM": {
"SUBMIT": " Merge contacts",
@@ -112,21 +112,32 @@ export default {
};
},
getChartOptions(metric) {
let tooltips = {};
if (this.isAverageMetricType(metric.KEY)) {
tooltips.callbacks = {
label: tooltipItem => {
return this.$t(metric.TOOLTIP_TEXT, {
metricValue: formatTime(tooltipItem.yLabel),
conversationCount:
this.accountReport.data[metric.KEY][tooltipItem.index].count,
});
},
};
const baseOptions = METRIC_CHART[metric.KEY].scales;
// If not an average metric type, return base options early
if (!this.isAverageMetricType(metric.KEY)) {
return baseOptions;
}
// Only create tooltip config for time-based metrics
return {
scales: METRIC_CHART[metric.KEY].scales,
tooltips: tooltips,
...baseOptions,
plugins: {
tooltip: {
callbacks: {
label: ({ raw, dataIndex }) => {
const value = raw || 0;
const count =
this.accountReport.data[metric.KEY][dataIndex]?.count || 0;
return this.$t(metric.TOOLTIP_TEXT, {
metricValue: formatTime(value),
conversationCount: count,
});
},
},
},
},
};
},
},
+12 -6
View File
@@ -82,14 +82,20 @@ class Inbox < ApplicationRecord
scope :order_by_name, -> { order('lower(name) ASC') }
def add_member(user_id)
member = inbox_members.new(user_id: user_id)
member.save!
# Adds multiple members to the inbox
# @param user_ids [Array<Integer>] Array of user IDs to add as members
# @return [void]
def add_members(user_ids)
inbox_members.create!(user_ids.map { |user_id| { user_id: user_id } })
update_account_cache
end
def remove_member(user_id)
member = inbox_members.find_by!(user_id: user_id)
member.try(:destroy)
# Removes multiple members from the inbox
# @param user_ids [Array<Integer>] Array of user IDs to remove
# @return [void]
def remove_members(user_ids)
inbox_members.where(user_id: user_ids).destroy_all
update_account_cache
end
def facebook?
+16 -4
View File
@@ -31,12 +31,24 @@ class Team < ApplicationRecord
self.name = name.downcase if attribute_present?('name')
end
def add_member(user_id)
team_members.find_or_create_by(user_id: user_id)&.user
# Adds multiple members to the team
# @param user_ids [Array<Integer>] Array of user IDs to add as members
# @return [Array<User>] Array of newly added members
def add_members(user_ids)
team_members_to_create = user_ids.map { |user_id| { user_id: user_id } }
created_members = team_members.create(team_members_to_create)
added_users = created_members.filter_map(&:user)
update_account_cache
added_users
end
def remove_member(user_id)
team_members.find_by(user_id: user_id)&.destroy!
# Removes multiple members from the team
# @param user_ids [Array<Integer>] Array of user IDs to remove
# @return [void]
def remove_members(user_ids)
team_members.where(user_id: user_ids).destroy_all
update_account_cache
end
def messages
@@ -1,7 +1,7 @@
json.payload do
json.array! @contactable_inboxes do |contactable_inbox|
json.inbox do
json.partial! 'api/v1/models/inbox', formats: [:json], resource: contactable_inbox[:inbox]
json.partial! 'api/v1/models/inbox_slim', formats: [:json], resource: contactable_inbox[:inbox]
end
json.source_id contactable_inbox[:source_id]
end
@@ -1,4 +1,4 @@
json.source_id resource.source_id
json.inbox do
json.partial! 'api/v1/models/inbox', formats: [:json], resource: resource.inbox
json.partial! 'api/v1/models/inbox_slim', formats: [:json], resource: resource.inbox
end
@@ -0,0 +1,7 @@
json.id resource.id
json.avatar_url resource.try(:avatar_url)
json.channel_id resource.channel_id
json.name resource.name
json.channel_type resource.channel_type
json.provider resource.channel.try(:provider)
json.email resource.channel.try(:email) if resource.email?
@@ -2,7 +2,7 @@ class Captain::Documents::CrawlJob < ApplicationJob
queue_as :low
def perform(document)
if InstallationConfig.find_by(name: 'CAPTAIN_FIRECRAWL_API_KEY').present?
if InstallationConfig.find_by(name: 'CAPTAIN_FIRECRAWL_API_KEY')&.value.present?
perform_firecrawl_crawl(document)
else
perform_simple_crawl(document)
@@ -67,6 +67,38 @@ RSpec.describe 'Contacts API', type: :request do
expect(contact_inboxes).to eq([])
end
it 'returns limited information on inboxes' do
get "/api/v1/accounts/#{account.id}/contacts?include_contact_inboxes=true",
headers: admin.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
response_body = response.parsed_body
contact_emails = response_body['payload'].pluck('email')
contact_inboxes = response_body['payload'].pluck('contact_inboxes').flatten.compact
expect(contact_emails).to include(contact.email)
first_inbox = contact_inboxes[0]['inbox']
expect(first_inbox).to be_a(Hash)
expect(first_inbox).to include('id', 'channel_id', 'channel_type', 'name', 'avatar_url', 'provider')
expect(first_inbox).not_to include('imap_login',
'imap_password',
'imap_address',
'imap_port',
'imap_enabled',
'imap_enable_ssl')
expect(first_inbox).not_to include('smtp_login',
'smtp_password',
'smtp_address',
'smtp_port',
'smtp_enabled',
'smtp_domain')
expect(first_inbox).not_to include('hmac_token', 'provider_config')
end
it 'returns all contacts with company name desc order' do
get "/api/v1/accounts/#{account.id}/contacts?include_contact_inboxes=false&sort=-company",
headers: admin.create_new_auth_token,
@@ -255,28 +255,30 @@ RSpec.describe 'Inbox Member API', type: :request do
expect(response).to have_http_status(:not_found)
end
it 'renders error on invalid params' do
it 'ignores invalid params' do
params = { inbox_id: inbox.id, user_ids: ['invalid'] }
original_count = inbox.inbox_members&.count
delete "/api/v1/accounts/#{account.id}/inbox_members",
headers: administrator.create_new_auth_token,
params: params,
as: :json
expect(response).to have_http_status(:not_found)
expect(response.body).to include('Resource could not be found')
expect(response).to have_http_status(:success)
expect(inbox.inbox_members&.count).to eq(original_count)
end
it 'renders error on non member params' do
it 'ignores non member params' do
params = { inbox_id: inbox.id, user_ids: [non_member_agent.id] }
original_count = inbox.inbox_members&.count
delete "/api/v1/accounts/#{account.id}/inbox_members",
headers: administrator.create_new_auth_token,
params: params,
as: :json
expect(response).to have_http_status(:not_found)
expect(response.body).to include('Resource could not be found')
expect(response).to have_http_status(:success)
expect(inbox.inbox_members&.count).to eq(original_count)
end
end
end
+33 -12
View File
@@ -41,29 +41,50 @@ RSpec.describe Inbox do
it_behaves_like 'avatarable'
end
describe '#add_member' do
describe '#add_members' do
let(:inbox) { FactoryBot.create(:inbox) }
let(:user) { FactoryBot.create(:user) }
it do
expect(inbox.inbox_members.size).to eq(0)
before do
allow(Rails.configuration.dispatcher).to receive(:dispatch)
end
inbox.add_member(user.id)
expect(inbox.reload.inbox_members.size).to eq(1)
it 'handles adds all members and resets cache keys' do
users = FactoryBot.create_list(:user, 3)
inbox.add_members(users.map(&:id))
expect(inbox.reload.inbox_members.size).to eq(3)
expect(Rails.configuration.dispatcher).to have_received(:dispatch).at_least(:once)
.with(
'account.cache_invalidated',
kind_of(Time),
account: inbox.account,
cache_keys: inbox.account.cache_keys
)
end
end
describe '#remove_member' do
describe '#remove_members' do
let(:inbox) { FactoryBot.create(:inbox) }
let(:user) { FactoryBot.create(:user) }
let(:users) { FactoryBot.create_list(:user, 3) }
before { inbox.add_member(user.id) }
before do
inbox.add_members(users.map(&:id))
allow(Rails.configuration.dispatcher).to receive(:dispatch)
end
it do
expect(inbox.inbox_members.size).to eq(1)
it 'removes the members and resets cache keys' do
expect(inbox.reload.inbox_members.size).to eq(3)
inbox.remove_member(user.id)
inbox.remove_members(users.map(&:id))
expect(inbox.reload.inbox_members.size).to eq(0)
expect(Rails.configuration.dispatcher).to have_received(:dispatch).at_least(:once)
.with(
'account.cache_invalidated',
kind_of(Time),
account: inbox.account,
cache_keys: inbox.account.cache_keys
)
end
end
+47
View File
@@ -6,4 +6,51 @@ RSpec.describe Team do
it { is_expected.to have_many(:conversations) }
it { is_expected.to have_many(:team_members) }
end
describe '#add_members' do
let(:team) { FactoryBot.create(:team) }
before do
allow(Rails.configuration.dispatcher).to receive(:dispatch)
end
it 'handles adds all members and resets cache keys' do
users = FactoryBot.create_list(:user, 3)
team.add_members(users.map(&:id))
expect(team.reload.team_members.size).to eq(3)
expect(Rails.configuration.dispatcher).to have_received(:dispatch).at_least(:once)
.with(
'account.cache_invalidated',
kind_of(Time),
account: team.account,
cache_keys: team.account.cache_keys
)
end
end
describe '#remove_members' do
let(:team) { FactoryBot.create(:team) }
let(:users) { FactoryBot.create_list(:user, 3) }
before do
team.add_members(users.map(&:id))
allow(Rails.configuration.dispatcher).to receive(:dispatch)
end
it 'removes the members and resets cache keys' do
expect(team.reload.team_members.size).to eq(3)
team.remove_members(users.map(&:id))
expect(team.reload.team_members.size).to eq(0)
expect(Rails.configuration.dispatcher).to have_received(:dispatch).at_least(:once)
.with(
'account.cache_invalidated',
kind_of(Time),
account: team.account,
cache_keys: team.account.cache_keys
)
end
end
end
-4
View File
@@ -55,10 +55,6 @@ const tailwindConfig = {
},
overflowWrap: 'anywhere',
'br + br': {
display: 'none',
},
strong: {
color: 'rgb(var(--slate-12))',
fontWeight: '700',