chore: Add new tab and copy link to conversation context menu (#12089)
# Pull Request Template ## Description This PR includes the following enhancements to the conversation card context menu: 1. **Added "Open in New Tab" and "Copy Conversation Link" options.** * "Open in New Tab" allows users to quickly open a conversation in a separate browser tab. * "Copy Conversation Link" copies the conversation URL to the clipboard for easy sharing. 2. **Enabled the context menu in Previous Conversations card** with support for these two options. Fixes https://linear.app/chatwoot/issue/CW-4722/cannot-open-previous-conversations-in-a-new-tab ## 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/37b45d23c6804db292568d093b645ac0?sid=c3105971-f938-41bd-9f52-0f00d419d1b3 ## 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 --------- Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
@@ -68,6 +68,10 @@ export default {
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
allowedContextMenuOptions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
emits: [
|
emits: [
|
||||||
'contextMenuToggle',
|
'contextMenuToggle',
|
||||||
@@ -151,11 +155,9 @@ export default {
|
|||||||
hasSlaPolicyId() {
|
hasSlaPolicyId() {
|
||||||
return this.chat?.sla_policy_id;
|
return this.chat?.sla_policy_id;
|
||||||
},
|
},
|
||||||
},
|
conversationPath() {
|
||||||
methods: {
|
|
||||||
onCardClick(e) {
|
|
||||||
const { activeInbox, chat } = this;
|
const { activeInbox, chat } = this;
|
||||||
const path = frontendURL(
|
return frontendURL(
|
||||||
conversationUrl({
|
conversationUrl({
|
||||||
accountId: this.accountId,
|
accountId: this.accountId,
|
||||||
activeInbox,
|
activeInbox,
|
||||||
@@ -166,18 +168,26 @@ export default {
|
|||||||
conversationType: this.conversationType,
|
conversationType: this.conversationType,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onCardClick(e) {
|
||||||
|
const path = this.conversationPath;
|
||||||
|
if (!path) return;
|
||||||
|
|
||||||
|
// Handle Ctrl/Cmd + Click for new tab
|
||||||
if (e.metaKey || e.ctrlKey) {
|
if (e.metaKey || e.ctrlKey) {
|
||||||
|
e.preventDefault();
|
||||||
window.open(
|
window.open(
|
||||||
window.chatwootConfig.hostURL + path,
|
`${window.chatwootConfig.hostURL}${path}`,
|
||||||
'_blank',
|
'_blank',
|
||||||
'noopener noreferrer nofollow'
|
'noopener,noreferrer'
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.isActiveChat) {
|
|
||||||
return;
|
// Skip if already active
|
||||||
}
|
if (this.isActiveChat) return;
|
||||||
|
|
||||||
router.push({ path });
|
router.push({ path });
|
||||||
},
|
},
|
||||||
@@ -359,6 +369,8 @@ export default {
|
|||||||
:priority="chat.priority"
|
:priority="chat.priority"
|
||||||
:chat-id="chat.id"
|
:chat-id="chat.id"
|
||||||
:has-unread-messages="hasUnread"
|
:has-unread-messages="hasUnread"
|
||||||
|
:conversation-url="conversationPath"
|
||||||
|
:allowed-options="allowedContextMenuOptions"
|
||||||
@update-conversation="onUpdateConversation"
|
@update-conversation="onUpdateConversation"
|
||||||
@assign-agent="onAssignAgent"
|
@assign-agent="onAssignAgent"
|
||||||
@assign-label="onAssignLabel"
|
@assign-label="onAssignLabel"
|
||||||
@@ -367,6 +379,7 @@ export default {
|
|||||||
@mark-as-read="markAsRead"
|
@mark-as-read="markAsRead"
|
||||||
@assign-priority="assignPriority"
|
@assign-priority="assignPriority"
|
||||||
@delete-conversation="deleteConversation"
|
@delete-conversation="deleteConversation"
|
||||||
|
@close="closeContextMenu"
|
||||||
/>
|
/>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import { useAdmin } from 'dashboard/composables/useAdmin';
|
||||||
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { copyTextToClipboard } from 'shared/helpers/clipboard';
|
||||||
import {
|
import {
|
||||||
getSortedAgentsByAvailability,
|
getSortedAgentsByAvailability,
|
||||||
getAgentsByUpdatedPresence,
|
getAgentsByUpdatedPresence,
|
||||||
@@ -8,7 +11,20 @@ import MenuItem from './menuItem.vue';
|
|||||||
import MenuItemWithSubmenu from './menuItemWithSubmenu.vue';
|
import MenuItemWithSubmenu from './menuItemWithSubmenu.vue';
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
import AgentLoadingPlaceholder from './agentLoadingPlaceholder.vue';
|
import AgentLoadingPlaceholder from './agentLoadingPlaceholder.vue';
|
||||||
import { useAdmin } from 'dashboard/composables/useAdmin';
|
|
||||||
|
const MENU = {
|
||||||
|
MARK_AS_READ: 'mark-as-read',
|
||||||
|
MARK_AS_UNREAD: 'mark-as-unread',
|
||||||
|
PRIORITY: 'priority',
|
||||||
|
STATUS: 'status',
|
||||||
|
SNOOZE: 'snooze',
|
||||||
|
AGENT: 'agent',
|
||||||
|
TEAM: 'team',
|
||||||
|
LABEL: 'label',
|
||||||
|
DELETE: 'delete',
|
||||||
|
OPEN_NEW_TAB: 'open-new-tab',
|
||||||
|
COPY_LINK: 'copy-link',
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -37,6 +53,14 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
conversationUrl: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
allowedOptions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
emits: [
|
emits: [
|
||||||
'updateConversation',
|
'updateConversation',
|
||||||
@@ -47,6 +71,7 @@ export default {
|
|||||||
'assignTeam',
|
'assignTeam',
|
||||||
'assignLabel',
|
'assignLabel',
|
||||||
'deleteConversation',
|
'deleteConversation',
|
||||||
|
'close',
|
||||||
],
|
],
|
||||||
setup() {
|
setup() {
|
||||||
const { isAdmin } = useAdmin();
|
const { isAdmin } = useAdmin();
|
||||||
@@ -56,6 +81,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
MENU,
|
||||||
STATUS_TYPE: wootConstants.STATUS_TYPE,
|
STATUS_TYPE: wootConstants.STATUS_TYPE,
|
||||||
readOption: {
|
readOption: {
|
||||||
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.MARK_AS_READ'),
|
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.MARK_AS_READ'),
|
||||||
@@ -63,7 +89,7 @@ export default {
|
|||||||
},
|
},
|
||||||
unreadOption: {
|
unreadOption: {
|
||||||
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.MARK_AS_UNREAD'),
|
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.MARK_AS_UNREAD'),
|
||||||
icon: 'mail',
|
icon: 'mail-unread',
|
||||||
},
|
},
|
||||||
statusMenuConfig: [
|
statusMenuConfig: [
|
||||||
{
|
{
|
||||||
@@ -88,7 +114,7 @@ export default {
|
|||||||
icon: 'snooze',
|
icon: 'snooze',
|
||||||
},
|
},
|
||||||
priorityConfig: {
|
priorityConfig: {
|
||||||
key: 'priority',
|
key: MENU.PRIORITY,
|
||||||
label: this.$t('CONVERSATION.PRIORITY.TITLE'),
|
label: this.$t('CONVERSATION.PRIORITY.TITLE'),
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
options: [
|
options: [
|
||||||
@@ -115,25 +141,35 @@ export default {
|
|||||||
].filter(item => item.key !== this.priority),
|
].filter(item => item.key !== this.priority),
|
||||||
},
|
},
|
||||||
labelMenuConfig: {
|
labelMenuConfig: {
|
||||||
key: 'label',
|
key: MENU.LABEL,
|
||||||
icon: 'tag',
|
icon: 'tag',
|
||||||
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.ASSIGN_LABEL'),
|
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.ASSIGN_LABEL'),
|
||||||
},
|
},
|
||||||
agentMenuConfig: {
|
agentMenuConfig: {
|
||||||
key: 'agent',
|
key: MENU.AGENT,
|
||||||
icon: 'person-add',
|
icon: 'person-add',
|
||||||
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.ASSIGN_AGENT'),
|
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.ASSIGN_AGENT'),
|
||||||
},
|
},
|
||||||
teamMenuConfig: {
|
teamMenuConfig: {
|
||||||
key: 'team',
|
key: MENU.TEAM,
|
||||||
icon: 'people-team-add',
|
icon: 'people-team-add',
|
||||||
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.ASSIGN_TEAM'),
|
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.ASSIGN_TEAM'),
|
||||||
},
|
},
|
||||||
deleteOption: {
|
deleteOption: {
|
||||||
key: 'delete',
|
key: MENU.DELETE,
|
||||||
icon: 'delete',
|
icon: 'delete',
|
||||||
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.DELETE'),
|
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.DELETE'),
|
||||||
},
|
},
|
||||||
|
openInNewTabOption: {
|
||||||
|
key: MENU.OPEN_NEW_TAB,
|
||||||
|
icon: 'open',
|
||||||
|
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.OPEN_IN_NEW_TAB'),
|
||||||
|
},
|
||||||
|
copyLinkOption: {
|
||||||
|
key: MENU.COPY_LINK,
|
||||||
|
icon: 'copy',
|
||||||
|
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.COPY_LINK'),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -180,6 +216,10 @@ export default {
|
|||||||
this.$store.dispatch('inboxAssignableAgents/fetch', [this.inboxId]);
|
this.$store.dispatch('inboxAssignableAgents/fetch', [this.inboxId]);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
isAllowed(keys) {
|
||||||
|
if (!this.allowedOptions.length) return true;
|
||||||
|
return keys.some(key => this.allowedOptions.includes(key));
|
||||||
|
},
|
||||||
toggleStatus(status, snoozedUntil) {
|
toggleStatus(status, snoozedUntil) {
|
||||||
this.$emit('updateConversation', status, snoozedUntil);
|
this.$emit('updateConversation', status, snoozedUntil);
|
||||||
},
|
},
|
||||||
@@ -194,6 +234,24 @@ export default {
|
|||||||
deleteConversation() {
|
deleteConversation() {
|
||||||
this.$emit('deleteConversation', this.chatId);
|
this.$emit('deleteConversation', this.chatId);
|
||||||
},
|
},
|
||||||
|
openInNewTab() {
|
||||||
|
if (!this.conversationUrl) return;
|
||||||
|
|
||||||
|
const url = `${window.chatwootConfig.hostURL}${this.conversationUrl}`;
|
||||||
|
window.open(url, '_blank', 'noopener,noreferrer');
|
||||||
|
this.$emit('close');
|
||||||
|
},
|
||||||
|
async copyConversationLink() {
|
||||||
|
if (!this.conversationUrl) return;
|
||||||
|
try {
|
||||||
|
const url = `${window.chatwootConfig.hostURL}${this.conversationUrl}`;
|
||||||
|
await copyTextToClipboard(url);
|
||||||
|
useAlert(this.$t('CONVERSATION.CARD_CONTEXT_MENU.COPY_LINK_SUCCESS'));
|
||||||
|
this.$emit('close');
|
||||||
|
} catch (error) {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
},
|
||||||
show(key) {
|
show(key) {
|
||||||
// If the conversation status is same as the action, then don't display the option
|
// If the conversation status is same as the action, then don't display the option
|
||||||
// i.e.: Don't show an option to resolve if the conversation is already resolved.
|
// i.e.: Don't show an option to resolve if the conversation is already resolved.
|
||||||
@@ -217,83 +275,114 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="p-1 rounded-md shadow-xl bg-n-alpha-3/50 backdrop-blur-[100px]">
|
<div
|
||||||
<MenuItem
|
class="p-1 rounded-md shadow-xl bg-n-alpha-3/50 backdrop-blur-[100px] outline-1 outline outline-n-weak/50"
|
||||||
v-if="!hasUnreadMessages"
|
>
|
||||||
:option="unreadOption"
|
<template v-if="isAllowed([MENU.MARK_AS_READ, MENU.MARK_AS_UNREAD])">
|
||||||
variant="icon"
|
|
||||||
@click.stop="$emit('markAsUnread')"
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
v-else
|
|
||||||
:option="readOption"
|
|
||||||
variant="icon"
|
|
||||||
@click.stop="$emit('markAsRead')"
|
|
||||||
/>
|
|
||||||
<hr class="m-1 rounded border-b border-n-weak dark:border-n-weak" />
|
|
||||||
<template v-for="option in statusMenuConfig">
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
v-if="show(option.key)"
|
v-if="!hasUnreadMessages"
|
||||||
:key="option.key"
|
:option="unreadOption"
|
||||||
:option="option"
|
|
||||||
variant="icon"
|
variant="icon"
|
||||||
@click.stop="toggleStatus(option.key, null)"
|
@click.stop="$emit('markAsUnread')"
|
||||||
/>
|
/>
|
||||||
|
<MenuItem
|
||||||
|
v-else
|
||||||
|
:option="readOption"
|
||||||
|
variant="icon"
|
||||||
|
@click.stop="$emit('markAsRead')"
|
||||||
|
/>
|
||||||
|
<hr class="m-1 rounded border-b border-n-weak dark:border-n-weak" />
|
||||||
</template>
|
</template>
|
||||||
<MenuItem
|
<template v-if="isAllowed([MENU.STATUS, MENU.SNOOZE])">
|
||||||
v-if="showSnooze"
|
<template v-for="option in statusMenuConfig">
|
||||||
:option="snoozeOption"
|
|
||||||
variant="icon"
|
|
||||||
@click.stop="snoozeConversation()"
|
|
||||||
/>
|
|
||||||
<hr class="m-1 rounded border-b border-n-weak dark:border-n-weak" />
|
|
||||||
<MenuItemWithSubmenu :option="priorityConfig">
|
|
||||||
<MenuItem
|
|
||||||
v-for="(option, i) in priorityConfig.options"
|
|
||||||
:key="i"
|
|
||||||
:option="option"
|
|
||||||
@click.stop="assignPriority(option.key)"
|
|
||||||
/>
|
|
||||||
</MenuItemWithSubmenu>
|
|
||||||
<MenuItemWithSubmenu
|
|
||||||
:option="labelMenuConfig"
|
|
||||||
:sub-menu-available="!!labels.length"
|
|
||||||
>
|
|
||||||
<MenuItem
|
|
||||||
v-for="label in labels"
|
|
||||||
:key="label.id"
|
|
||||||
:option="generateMenuLabelConfig(label, 'label')"
|
|
||||||
variant="label"
|
|
||||||
@click.stop="$emit('assignLabel', label)"
|
|
||||||
/>
|
|
||||||
</MenuItemWithSubmenu>
|
|
||||||
<MenuItemWithSubmenu
|
|
||||||
:option="agentMenuConfig"
|
|
||||||
:sub-menu-available="!!assignableAgents.length"
|
|
||||||
>
|
|
||||||
<AgentLoadingPlaceholder v-if="assignableAgentsUiFlags.isFetching" />
|
|
||||||
<template v-else>
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
v-for="agent in assignableAgents"
|
v-if="show(option.key) && isAllowed([MENU.STATUS])"
|
||||||
:key="agent.id"
|
:key="option.key"
|
||||||
:option="generateMenuLabelConfig(agent, 'agent')"
|
:option="option"
|
||||||
variant="agent"
|
variant="icon"
|
||||||
@click.stop="$emit('assignAgent', agent)"
|
@click.stop="toggleStatus(option.key, null)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</MenuItemWithSubmenu>
|
|
||||||
<MenuItemWithSubmenu
|
|
||||||
:option="teamMenuConfig"
|
|
||||||
:sub-menu-available="!!teams.length"
|
|
||||||
>
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
v-for="team in teams"
|
v-if="showSnooze && isAllowed([MENU.SNOOZE])"
|
||||||
:key="team.id"
|
:option="snoozeOption"
|
||||||
:option="generateMenuLabelConfig(team, 'team')"
|
variant="icon"
|
||||||
@click.stop="$emit('assignTeam', team)"
|
@click.stop="snoozeConversation()"
|
||||||
/>
|
/>
|
||||||
</MenuItemWithSubmenu>
|
<hr class="m-1 rounded border-b border-n-weak dark:border-n-weak" />
|
||||||
<template v-if="isAdmin">
|
</template>
|
||||||
|
<template
|
||||||
|
v-if="isAllowed([MENU.PRIORITY, MENU.LABEL, MENU.AGENT, MENU.TEAM])"
|
||||||
|
>
|
||||||
|
<MenuItemWithSubmenu
|
||||||
|
v-if="isAllowed([MENU.PRIORITY])"
|
||||||
|
:option="priorityConfig"
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
v-for="(option, i) in priorityConfig.options"
|
||||||
|
:key="i"
|
||||||
|
:option="option"
|
||||||
|
@click.stop="assignPriority(option.key)"
|
||||||
|
/>
|
||||||
|
</MenuItemWithSubmenu>
|
||||||
|
<MenuItemWithSubmenu
|
||||||
|
v-if="isAllowed([MENU.LABEL])"
|
||||||
|
:option="labelMenuConfig"
|
||||||
|
:sub-menu-available="!!labels.length"
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
v-for="label in labels"
|
||||||
|
:key="label.id"
|
||||||
|
:option="generateMenuLabelConfig(label, 'label')"
|
||||||
|
variant="label"
|
||||||
|
@click.stop="$emit('assignLabel', label)"
|
||||||
|
/>
|
||||||
|
</MenuItemWithSubmenu>
|
||||||
|
<MenuItemWithSubmenu
|
||||||
|
v-if="isAllowed([MENU.AGENT])"
|
||||||
|
:option="agentMenuConfig"
|
||||||
|
:sub-menu-available="!!assignableAgents.length"
|
||||||
|
>
|
||||||
|
<AgentLoadingPlaceholder v-if="assignableAgentsUiFlags.isFetching" />
|
||||||
|
<template v-else>
|
||||||
|
<MenuItem
|
||||||
|
v-for="agent in assignableAgents"
|
||||||
|
:key="agent.id"
|
||||||
|
:option="generateMenuLabelConfig(agent, 'agent')"
|
||||||
|
variant="agent"
|
||||||
|
@click.stop="$emit('assignAgent', agent)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</MenuItemWithSubmenu>
|
||||||
|
<MenuItemWithSubmenu
|
||||||
|
v-if="isAllowed([MENU.TEAM])"
|
||||||
|
:option="teamMenuConfig"
|
||||||
|
:sub-menu-available="!!teams.length"
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
v-for="team in teams"
|
||||||
|
:key="team.id"
|
||||||
|
:option="generateMenuLabelConfig(team, 'team')"
|
||||||
|
@click.stop="$emit('assignTeam', team)"
|
||||||
|
/>
|
||||||
|
</MenuItemWithSubmenu>
|
||||||
|
<hr class="m-1 rounded border-b border-n-weak dark:border-n-weak" />
|
||||||
|
</template>
|
||||||
|
<template v-if="isAllowed([MENU.OPEN_NEW_TAB, MENU.COPY_LINK])">
|
||||||
|
<MenuItem
|
||||||
|
v-if="isAllowed([MENU.OPEN_NEW_TAB])"
|
||||||
|
:option="openInNewTabOption"
|
||||||
|
variant="icon"
|
||||||
|
@click.stop="openInNewTab"
|
||||||
|
/>
|
||||||
|
<MenuItem
|
||||||
|
v-if="isAllowed([MENU.COPY_LINK])"
|
||||||
|
:option="copyLinkOption"
|
||||||
|
variant="icon"
|
||||||
|
@click.stop="copyConversationLink"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-if="isAdmin && isAllowed([MENU.DELETE])">
|
||||||
<hr class="m-1 rounded border-b border-n-weak dark:border-n-weak" />
|
<hr class="m-1 rounded border-b border-n-weak dark:border-n-weak" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
:option="deleteOption"
|
:option="deleteOption"
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
<script>
|
<script setup>
|
||||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
import Avatar from 'dashboard/components-next/avatar/Avatar.vue';
|
||||||
export default {
|
|
||||||
components: {
|
defineProps({
|
||||||
Thumbnail,
|
option: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
},
|
},
|
||||||
props: {
|
variant: {
|
||||||
option: {
|
type: String,
|
||||||
type: Object,
|
default: 'default',
|
||||||
default: () => {},
|
|
||||||
},
|
|
||||||
variant: {
|
|
||||||
type: String,
|
|
||||||
default: 'default',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -30,12 +26,12 @@ export default {
|
|||||||
class="label-pill flex-shrink-0"
|
class="label-pill flex-shrink-0"
|
||||||
:style="{ backgroundColor: option.color }"
|
:style="{ backgroundColor: option.color }"
|
||||||
/>
|
/>
|
||||||
<Thumbnail
|
<Avatar
|
||||||
v-if="variant === 'agent'"
|
v-if="variant === 'agent'"
|
||||||
:username="option.label"
|
:name="option.label"
|
||||||
:src="option.thumbnail"
|
:src="option.thumbnail"
|
||||||
:status="option.status"
|
:status="option.status === 'online' ? option.status : null"
|
||||||
size="20px"
|
:size="20"
|
||||||
class="flex-shrink-0"
|
class="flex-shrink-0"
|
||||||
/>
|
/>
|
||||||
<p class="menu-label truncate min-w-0 flex-1">
|
<p class="menu-label truncate min-w-0 flex-1">
|
||||||
|
|||||||
@@ -144,6 +144,9 @@
|
|||||||
"AGENTS_LOADING": "Loading agents...",
|
"AGENTS_LOADING": "Loading agents...",
|
||||||
"ASSIGN_TEAM": "Assign team",
|
"ASSIGN_TEAM": "Assign team",
|
||||||
"DELETE": "Delete conversation",
|
"DELETE": "Delete conversation",
|
||||||
|
"OPEN_IN_NEW_TAB": "Open in new tab",
|
||||||
|
"COPY_LINK": "Copy conversation link",
|
||||||
|
"COPY_LINK_SUCCESS": "Conversation link copied to clipboard",
|
||||||
"API": {
|
"API": {
|
||||||
"AGENT_ASSIGNMENT": {
|
"AGENT_ASSIGNMENT": {
|
||||||
"SUCCESFUL": "Conversation id {conversationId} assigned to \"{agentName}\"",
|
"SUCCESFUL": "Conversation id {conversationId} assigned to \"{agentName}\"",
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ export default {
|
|||||||
:chat="conversation"
|
:chat="conversation"
|
||||||
:hide-inbox-name="false"
|
:hide-inbox-name="false"
|
||||||
hide-thumbnail
|
hide-thumbnail
|
||||||
|
enable-context-menu
|
||||||
|
:allowed-context-menu-options="['open-new-tab', 'copy-link']"
|
||||||
class="compact"
|
class="compact"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user