mirror of
https://github.com/lingble/chatwoot.git
synced 2025-10-29 10:12:34 +00:00
Merge branch 'develop' into feat/openai-integration
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
|
||||
.multiselect--active {
|
||||
>.multiselect__tags {
|
||||
border-color: $color-woot;
|
||||
border-color: var(--w-500);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,16 +75,13 @@
|
||||
}
|
||||
|
||||
&.multiselect__option--selected {
|
||||
background: var(--w-400);
|
||||
color: var(--white);
|
||||
background: var(--w-75);
|
||||
|
||||
&.multiselect__option--highlight:hover {
|
||||
background: var(--w-600);
|
||||
color: var(--white);
|
||||
background: var(--w-75);
|
||||
|
||||
&::after {
|
||||
background: transparent;
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
&::after:hover {
|
||||
@@ -196,6 +193,7 @@
|
||||
display: flex;
|
||||
font-size: var(--font-size-small);
|
||||
margin: 0;
|
||||
max-height: 3.8rem;
|
||||
padding: var(--space-smaller) var(--space-micro);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import InboxDropdownItem from './InboxDropdownItem';
|
||||
|
||||
export default {
|
||||
title: 'Components/DropDowns/InboxDropdownItem',
|
||||
component: InboxDropdownItem,
|
||||
argTypes: {
|
||||
name: {
|
||||
defaultValue: 'My new inbox',
|
||||
control: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
|
||||
inboxIdentifier: {
|
||||
defaultValue: 'nithin@mail.com',
|
||||
control: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
|
||||
channelType: {
|
||||
defaultValue: 'email',
|
||||
control: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: { InboxDropdownItem },
|
||||
template: '<inbox-dropdown-item v-bind="$props" ></inbox-dropdown-item>',
|
||||
});
|
||||
|
||||
export const Banner = Template.bind({});
|
||||
Banner.args = {};
|
||||
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div class="option-item--inbox">
|
||||
<span class="badge--icon">
|
||||
<fluent-icon :icon="computedInboxIcon" size="14" />
|
||||
</span>
|
||||
<div class="option__user-data">
|
||||
<h5 class="option__title">
|
||||
{{ name }}
|
||||
</h5>
|
||||
<p class="option__body text-truncate" :title="inboxIdentifier">
|
||||
{{ inboxIdentifier || computedInboxType }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getInboxClassByType,
|
||||
getReadableInboxByType,
|
||||
} from 'dashboard/helper/inbox';
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
inboxIdentifier: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
channelType: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
computedInboxIcon() {
|
||||
if (!this.channelType) return 'chat';
|
||||
const classByType = getInboxClassByType(
|
||||
this.channelType,
|
||||
this.inboxIdentifier
|
||||
);
|
||||
return classByType;
|
||||
},
|
||||
computedInboxType() {
|
||||
if (!this.channelType) return 'chat';
|
||||
const classByType = getReadableInboxByType(
|
||||
this.channelType,
|
||||
this.inboxIdentifier
|
||||
);
|
||||
return classByType;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.option-item--inbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 3.8rem;
|
||||
min-width: 0;
|
||||
padding: 0 var(--space-smaller);
|
||||
}
|
||||
.badge--icon {
|
||||
display: inline-flex;
|
||||
border-radius: var(--border-radius-small);
|
||||
margin-right: var(--space-smaller);
|
||||
background: var(--s-25);
|
||||
padding: var(--space-micro);
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
width: var(--space-medium);
|
||||
height: var(--space-medium);
|
||||
}
|
||||
|
||||
.option__user-data {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
margin-left: var(--space-smaller);
|
||||
margin-right: var(--space-smaller);
|
||||
}
|
||||
.option__body {
|
||||
display: inline-block;
|
||||
color: var(--s-600);
|
||||
font-size: var(--font-size-small);
|
||||
line-height: 1.3;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.option__title {
|
||||
line-height: 1.1;
|
||||
font-size: var(--font-size-mini);
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,55 @@
|
||||
import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
|
||||
|
||||
export const getInboxSource = (type, phoneNumber, inbox) => {
|
||||
switch (type) {
|
||||
case INBOX_TYPES.WEB:
|
||||
return inbox.website_url || '';
|
||||
|
||||
case INBOX_TYPES.TWILIO:
|
||||
case INBOX_TYPES.WHATSAPP:
|
||||
return phoneNumber || '';
|
||||
|
||||
case INBOX_TYPES.EMAIL:
|
||||
return inbox.email || '';
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
export const getReadableInboxByType = (type, phoneNumber) => {
|
||||
switch (type) {
|
||||
case INBOX_TYPES.WEB:
|
||||
return 'livechat';
|
||||
|
||||
case INBOX_TYPES.FB:
|
||||
return 'facebook';
|
||||
|
||||
case INBOX_TYPES.TWITTER:
|
||||
return 'twitter';
|
||||
|
||||
case INBOX_TYPES.TWILIO:
|
||||
return phoneNumber?.startsWith('whatsapp') ? 'whatsapp' : 'sms';
|
||||
|
||||
case INBOX_TYPES.WHATSAPP:
|
||||
return 'whatsapp';
|
||||
|
||||
case INBOX_TYPES.API:
|
||||
return 'api';
|
||||
|
||||
case INBOX_TYPES.EMAIL:
|
||||
return 'email';
|
||||
|
||||
case INBOX_TYPES.TELEGRAM:
|
||||
return 'telegram';
|
||||
|
||||
case INBOX_TYPES.LINE:
|
||||
return 'line';
|
||||
|
||||
default:
|
||||
return 'chat';
|
||||
}
|
||||
};
|
||||
|
||||
export const getInboxClassByType = (type, phoneNumber) => {
|
||||
switch (type) {
|
||||
case INBOX_TYPES.WEB:
|
||||
|
||||
@@ -182,7 +182,8 @@
|
||||
"LABEL": "To"
|
||||
},
|
||||
"INBOX": {
|
||||
"LABEL": "Inbox",
|
||||
"LABEL": "Via Inbox",
|
||||
"PLACEHOLDER": "Choose source inbox",
|
||||
"ERROR": "Select an inbox"
|
||||
},
|
||||
"SUBJECT": {
|
||||
|
||||
@@ -8,17 +8,43 @@
|
||||
<div v-else>
|
||||
<div class="row gutter-small">
|
||||
<div class="columns">
|
||||
<label :class="{ error: $v.targetInbox.$error }">
|
||||
<label>
|
||||
{{ $t('NEW_CONVERSATION.FORM.INBOX.LABEL') }}
|
||||
<select v-model="targetInbox">
|
||||
<option
|
||||
v-for="contactableInbox in inboxes"
|
||||
:key="contactableInbox.inbox.id"
|
||||
:value="contactableInbox"
|
||||
>
|
||||
{{ contactableInbox.inbox.name }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="multiselect-wrap--small">
|
||||
<multiselect
|
||||
v-model="targetInbox"
|
||||
track-by="id"
|
||||
label="name"
|
||||
:placeholder="$t('FORMS.MULTISELECT.SELECT')"
|
||||
selected-label=""
|
||||
select-label=""
|
||||
deselect-label=""
|
||||
:max-height="160"
|
||||
:close-on-select="true"
|
||||
:options="[...inboxes]"
|
||||
>
|
||||
<template slot="singleLabel" slot-scope="{ option }">
|
||||
<inbox-dropdown-item
|
||||
v-if="option.name"
|
||||
:name="option.name"
|
||||
:inbox-identifier="computedInboxSource(option)"
|
||||
:channel-type="option.channel_type"
|
||||
/>
|
||||
<span v-else>
|
||||
{{ $t('NEW_CONVERSATION.FORM.INBOX.PLACEHOLDER') }}
|
||||
</span>
|
||||
</template>
|
||||
<template slot="option" slot-scope="{ option }">
|
||||
<inbox-dropdown-item
|
||||
:name="option.name"
|
||||
:inbox-identifier="computedInboxSource(option)"
|
||||
:channel-type="option.channel_type"
|
||||
/>
|
||||
</template>
|
||||
</multiselect>
|
||||
</div>
|
||||
<label :class="{ error: $v.targetInbox.$error }">
|
||||
<span v-if="$v.targetInbox.$error" class="message">
|
||||
{{ $t('NEW_CONVERSATION.FORM.INBOX.ERROR') }}
|
||||
</span>
|
||||
@@ -129,10 +155,12 @@ import Thumbnail from 'dashboard/components/widgets/Thumbnail';
|
||||
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor';
|
||||
import ReplyEmailHead from 'dashboard/components/widgets/conversation/ReplyEmailHead';
|
||||
import CannedResponse from 'dashboard/components/widgets/conversation/CannedResponse.vue';
|
||||
import InboxDropdownItem from 'dashboard/components/widgets/InboxDropdownItem';
|
||||
import WhatsappTemplates from './WhatsappTemplates.vue';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
|
||||
import { ExceptionWithMessage } from 'shared/helpers/CustomErrors';
|
||||
import { getInboxSource } from 'dashboard/helper/inbox';
|
||||
import { required, requiredIf } from 'vuelidate/lib/validators';
|
||||
|
||||
export default {
|
||||
@@ -142,6 +170,7 @@ export default {
|
||||
ReplyEmailHead,
|
||||
CannedResponse,
|
||||
WhatsappTemplates,
|
||||
InboxDropdownItem,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
@@ -161,9 +190,9 @@ export default {
|
||||
message: '',
|
||||
showCannedResponseMenu: false,
|
||||
cannedResponseSearchKey: '',
|
||||
selectedInbox: '',
|
||||
bccEmails: '',
|
||||
ccEmails: '',
|
||||
targetInbox: {},
|
||||
whatsappTemplateSelected: false,
|
||||
};
|
||||
},
|
||||
@@ -186,8 +215,8 @@ export default {
|
||||
}),
|
||||
emailMessagePayload() {
|
||||
const payload = {
|
||||
inboxId: this.targetInbox.inbox.id,
|
||||
sourceId: this.targetInbox.source_id,
|
||||
inboxId: this.targetInbox.id,
|
||||
sourceId: this.targetInbox.sourceId,
|
||||
contactId: this.contact.id,
|
||||
message: { content: this.message },
|
||||
mailSubject: this.subject,
|
||||
@@ -202,12 +231,17 @@ export default {
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
targetInbox: {
|
||||
selectedInbox: {
|
||||
get() {
|
||||
return this.selectedInbox || {};
|
||||
const inboxList = this.contact.contactableInboxes || [];
|
||||
return (
|
||||
inboxList.find(inbox => inbox.inbox.id === this.targetInbox.id) || {
|
||||
inbox: {},
|
||||
}
|
||||
);
|
||||
},
|
||||
set(value) {
|
||||
this.selectedInbox = value;
|
||||
this.targetInbox = value.inbox;
|
||||
},
|
||||
},
|
||||
showNoInboxAlert() {
|
||||
@@ -217,7 +251,11 @@ export default {
|
||||
return this.inboxes.length === 0 && !this.uiFlags.isFetchingInboxes;
|
||||
},
|
||||
inboxes() {
|
||||
return this.contact.contactableInboxes || [];
|
||||
const inboxList = this.contact.contactableInboxes || [];
|
||||
return inboxList.map(inbox => ({
|
||||
...inbox.inbox,
|
||||
sourceId: inbox.source_id,
|
||||
}));
|
||||
},
|
||||
isAnEmailInbox() {
|
||||
return (
|
||||
@@ -267,8 +305,8 @@ export default {
|
||||
},
|
||||
prepareWhatsAppMessagePayload({ message: content, templateParams }) {
|
||||
const payload = {
|
||||
inboxId: this.targetInbox.inbox.id,
|
||||
sourceId: this.targetInbox.source_id,
|
||||
inboxId: this.targetInbox.id,
|
||||
sourceId: this.targetInbox.sourceId,
|
||||
contactId: this.contact.id,
|
||||
message: { content, template_params: templateParams },
|
||||
assigneeId: this.currentUser.id,
|
||||
@@ -311,6 +349,18 @@ export default {
|
||||
const payload = this.prepareWhatsAppMessagePayload(messagePayload);
|
||||
await this.createConversation(payload);
|
||||
},
|
||||
inboxReadableIdentifier(inbox) {
|
||||
return `${inbox.name} (${inbox.channel_type})`;
|
||||
},
|
||||
computedInboxSource(inbox) {
|
||||
if (!inbox.channel_type) return '';
|
||||
const classByType = getInboxSource(
|
||||
inbox.channel_type,
|
||||
inbox.phone_number,
|
||||
inbox
|
||||
);
|
||||
return classByType;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -352,11 +402,23 @@ export default {
|
||||
gap: var(--space-small);
|
||||
}
|
||||
|
||||
::v-deep .mention--box {
|
||||
left: 0;
|
||||
margin: auto;
|
||||
right: 0;
|
||||
top: unset;
|
||||
height: fit-content;
|
||||
::v-deep {
|
||||
.mention--box {
|
||||
left: 0;
|
||||
margin: auto;
|
||||
right: 0;
|
||||
top: unset;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
/* TODO: Remove when have standardized a component out of multiselect */
|
||||
.multiselect .multiselect__content .multiselect__option span {
|
||||
display: inline-flex;
|
||||
width: var(--space-medium);
|
||||
color: var(--s-600);
|
||||
}
|
||||
.multiselect .multiselect__content .multiselect__option {
|
||||
padding: var(--space-micro) var(--space-smaller);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -52,6 +52,8 @@ class ActionService
|
||||
end
|
||||
|
||||
def send_email_transcript(emails)
|
||||
emails = emails[0].gsub(/\s+/, '').split(',')
|
||||
|
||||
emails.each do |email|
|
||||
ConversationReplyMailer.with(account: @conversation.account).conversation_transcript(@conversation, email)&.deliver_later
|
||||
end
|
||||
|
||||
@@ -5,6 +5,9 @@ def fetch_git_sha
|
||||
sha.strip
|
||||
elsif File.exist?('.git_sha')
|
||||
File.read('.git_sha').strip
|
||||
# This is for Heroku. Ensure heroku labs:enable runtime-dyno-metadata is turned on.
|
||||
elsif ENV.fetch('HEROKU_SLUG_COMMIT', nil).present?
|
||||
ENV.fetch('HEROKU_SLUG_COMMIT', nil)
|
||||
else
|
||||
'unknown'
|
||||
end
|
||||
|
||||
@@ -121,18 +121,6 @@ describe AutomationRuleListener do
|
||||
expect(conversation.assignee).to eq(user_1)
|
||||
end
|
||||
|
||||
it 'triggers automation rule send email transcript to the mentioned email' do
|
||||
mailer = double
|
||||
|
||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
||||
|
||||
listener.conversation_updated(event)
|
||||
|
||||
conversation.reload
|
||||
|
||||
allow(mailer).to receive(:conversation_transcript)
|
||||
end
|
||||
|
||||
it 'triggers automation rule send message to the contacts' do
|
||||
expect(conversation.messages).to be_empty
|
||||
|
||||
@@ -253,15 +241,6 @@ describe AutomationRuleListener do
|
||||
expect(conversation.assignee).to eq(user_1)
|
||||
end
|
||||
|
||||
it 'triggers automation rule send email transcript to the mentioned email' do
|
||||
mailer = double
|
||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
||||
listener.conversation_updated(event)
|
||||
conversation.reload
|
||||
|
||||
allow(mailer).to receive(:conversation_transcript)
|
||||
end
|
||||
|
||||
it 'triggers automation rule send email to the team' do
|
||||
message_delivery = instance_double(ActionMailer::MessageDelivery)
|
||||
|
||||
@@ -457,15 +436,6 @@ describe AutomationRuleListener do
|
||||
expect(conversation.assignee).to eq(user_1)
|
||||
end
|
||||
|
||||
it 'triggers automation rule send email transcript to the mentioned email' do
|
||||
mailer = double
|
||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
||||
listener.conversation_opened(event)
|
||||
conversation.reload
|
||||
|
||||
allow(mailer).to receive(:conversation_transcript)
|
||||
end
|
||||
|
||||
it 'triggers automation rule send email to the team' do
|
||||
message_delivery = instance_double(ActionMailer::MessageDelivery)
|
||||
|
||||
@@ -577,15 +547,6 @@ describe AutomationRuleListener do
|
||||
|
||||
expect(conversation.assignee).to eq(user_1)
|
||||
end
|
||||
|
||||
it 'triggers automation rule send email transcript to the mentioned email' do
|
||||
mailer = double
|
||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
||||
listener.message_created(event)
|
||||
conversation.reload
|
||||
|
||||
allow(mailer).to receive(:conversation_transcript)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -616,17 +577,6 @@ describe AutomationRuleListener do
|
||||
end
|
||||
|
||||
context 'when rule matches' do
|
||||
it 'triggers automation rule send email transcript to the mentioned email' do
|
||||
mailer = double
|
||||
allow(ConversationReplyMailer).to receive(:with).and_return(mailer)
|
||||
allow(mailer).to receive(:conversation_transcript)
|
||||
|
||||
listener.message_created(event)
|
||||
conversation.reload
|
||||
|
||||
expect(mailer).to have_received(:conversation_transcript).with(conversation, 'new_agent@example.com')
|
||||
end
|
||||
|
||||
it 'triggers automation rule send message to the contacts' do
|
||||
expect(conversation.messages.count).to eq(1)
|
||||
listener.message_created(event)
|
||||
@@ -710,18 +660,6 @@ describe AutomationRuleListener do
|
||||
end
|
||||
|
||||
context 'when rule matches' do
|
||||
it 'triggers automation rule send email transcript to the mentioned email' do
|
||||
mailer = double
|
||||
allow(ConversationReplyMailer).to receive(:with).and_return(mailer)
|
||||
allow(mailer).to receive(:conversation_transcript)
|
||||
|
||||
listener.conversation_created(event)
|
||||
|
||||
conversation.reload
|
||||
|
||||
expect(mailer).to have_received(:conversation_transcript).with(conversation, 'new_agent@example.com')
|
||||
end
|
||||
|
||||
it 'triggers automation rule send message to the contacts' do
|
||||
expect(conversation.messages.count).to eq(1)
|
||||
|
||||
@@ -781,15 +719,6 @@ describe AutomationRuleListener do
|
||||
let(:event) { Events::Base.new('message_created', Time.zone.now, { conversation: tweet, message: message }) }
|
||||
let!(:message) { create(:message, account: account, conversation: tweet, message_type: 'incoming') }
|
||||
|
||||
it 'triggers automation rule except send_message and send_attachment' do
|
||||
mailer = double
|
||||
allow(ConversationReplyMailer).to receive(:with).and_return(mailer)
|
||||
allow(mailer).to receive(:conversation_transcript)
|
||||
|
||||
listener.message_created(event)
|
||||
expect(mailer).to have_received(:conversation_transcript).with(tweet, 'new_agent@example.com')
|
||||
end
|
||||
|
||||
it 'does not triggers automation rule send message or send attachment' do
|
||||
expect(tweet.messages.count).to eq(1)
|
||||
|
||||
|
||||
@@ -87,5 +87,21 @@ RSpec.describe AutomationRules::ActionService do
|
||||
described_class.new(rule, account, conversation).perform
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform with send_email_transcript action' do
|
||||
before do
|
||||
rule.actions << { action_name: 'send_email_transcript', action_params: ['contact@example.com, agent@example.com,agent1@example.com'] }
|
||||
end
|
||||
|
||||
it 'will send email to transcript to action params emails' do
|
||||
mailer = double
|
||||
allow(ConversationReplyMailer).to receive(:with).and_return(mailer)
|
||||
allow(mailer).to receive(:conversation_transcript).with(conversation, 'contact@example.com')
|
||||
allow(mailer).to receive(:conversation_transcript).with(conversation, 'agent@example.com')
|
||||
allow(mailer).to receive(:conversation_transcript).with(conversation, 'agent1@example.com')
|
||||
|
||||
described_class.new(rule, account, conversation).perform
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -310,8 +310,6 @@
|
||||
- $ref: '#/parameters/inbox_id'
|
||||
get:
|
||||
$ref: ./application/inboxes/inbox_members/show.yml
|
||||
delete:
|
||||
$ref: ./application/inboxes/inbox_members/delete.yml
|
||||
|
||||
/api/v1/accounts/{account_id}/inbox_members:
|
||||
parameters:
|
||||
@@ -320,6 +318,8 @@
|
||||
$ref: ./application/inboxes/inbox_members/create.yml
|
||||
patch:
|
||||
$ref: ./application/inboxes/inbox_members/update.yml
|
||||
delete:
|
||||
$ref: ./application/inboxes/inbox_members/delete.yml
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3369,62 +3369,6 @@
|
||||
"description": "Access denied"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Inboxes"
|
||||
],
|
||||
"operationId": "delete-agent-in-inbox",
|
||||
"summary": "Remove an Agent from Inbox",
|
||||
"description": "Remove an Agent from Inbox",
|
||||
"security": [
|
||||
{
|
||||
"userApiKey": [
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"inbox_id",
|
||||
"user_ids"
|
||||
],
|
||||
"properties": {
|
||||
"inbox_id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the inbox"
|
||||
},
|
||||
"user_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": "IDs of users to be deleted from the inbox"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"404": {
|
||||
"description": "Inbox not found"
|
||||
},
|
||||
"403": {
|
||||
"description": "Access denied"
|
||||
},
|
||||
"422": {
|
||||
"description": "User must exist"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/accounts/{account_id}/inbox_members": {
|
||||
@@ -3558,6 +3502,62 @@
|
||||
"description": "User must exist"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Inboxes"
|
||||
],
|
||||
"operationId": "delete-agent-in-inbox",
|
||||
"summary": "Remove an Agent from Inbox",
|
||||
"description": "Remove an Agent from Inbox",
|
||||
"security": [
|
||||
{
|
||||
"userApiKey": [
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"inbox_id",
|
||||
"user_ids"
|
||||
],
|
||||
"properties": {
|
||||
"inbox_id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the inbox"
|
||||
},
|
||||
"user_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": "IDs of users to be deleted from the inbox"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"404": {
|
||||
"description": "Inbox not found"
|
||||
},
|
||||
"403": {
|
||||
"description": "Access denied"
|
||||
},
|
||||
"422": {
|
||||
"description": "User must exist"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages": {
|
||||
|
||||
Reference in New Issue
Block a user