mirror of
https://github.com/lingble/chatwoot.git
synced 2025-10-29 10:12:34 +00:00
feat: Adds the ability to sort conversations (#6853)
* Add sort filter * Change UI * Change filter * Complete sort by filters * Style fixes * Fix default sort * Update app/javascript/dashboard/components/widgets/conversation/ConversationBasicFilter.vue Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> * Update app/javascript/dashboard/components/widgets/conversation/ConversationBasicFilter.vue Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> * Update app/javascript/dashboard/components/ChatList.vue Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> * Added translation * Added review fixes * Add more updates * Code cleanups * Update last_activity_at on message received event * Cleans up the design for chatlist and icons * Fix sort * Remove inline styles * Add tag along with the title --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: Pranav Raj S <pranav@chatwoot.com> Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
This commit is contained in:
@@ -14,6 +14,7 @@ class ConversationApi extends ApiClient {
|
||||
labels,
|
||||
teamId,
|
||||
conversationType,
|
||||
sortBy,
|
||||
}) {
|
||||
return axios.get(this.url, {
|
||||
params: {
|
||||
@@ -24,6 +25,7 @@ class ConversationApi extends ApiClient {
|
||||
page,
|
||||
labels,
|
||||
conversation_type: conversationType,
|
||||
sort_by: sortBy,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -95,10 +95,6 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 var(--space-normal);
|
||||
|
||||
.page-title {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content-box {
|
||||
|
||||
@@ -11,15 +11,23 @@
|
||||
class="chat-list__top"
|
||||
:class="{ filter__applied: hasAppliedFiltersOrActiveFolders }"
|
||||
>
|
||||
<h1 class="page-title text-truncate" :title="pageTitle">
|
||||
{{ pageTitle }}
|
||||
</h1>
|
||||
|
||||
<div class="filter--actions">
|
||||
<chat-filter
|
||||
<div class="flex-center chat-list__title">
|
||||
<h1
|
||||
class="page-sub-title text-truncate margin-bottom-0"
|
||||
:title="pageTitle"
|
||||
>
|
||||
{{ pageTitle }}
|
||||
</h1>
|
||||
<span
|
||||
v-if="!hasAppliedFiltersOrActiveFolders"
|
||||
@statusFilterChange="updateStatusType"
|
||||
/>
|
||||
class="conversation--status-pill"
|
||||
>
|
||||
{{
|
||||
this.$t(`CHAT_LIST.CHAT_STATUS_FILTER_ITEMS.${activeStatus}.TEXT`)
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="filter--actions">
|
||||
<div v-if="hasAppliedFilters && !hasActiveFolders">
|
||||
<woot-button
|
||||
v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.ADD.SAVE_BUTTON')"
|
||||
@@ -48,7 +56,6 @@
|
||||
@click="onClickOpenDeleteFoldersModal"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<woot-button
|
||||
v-else
|
||||
v-tooltip.right="$t('FILTER.TOOLTIP_LABEL')"
|
||||
@@ -58,6 +65,10 @@
|
||||
size="tiny"
|
||||
@click="onToggleAdvanceFiltersModal"
|
||||
/>
|
||||
<conversation-basic-filter
|
||||
v-if="!hasAppliedFiltersOrActiveFolders"
|
||||
@changeFilter="onBasicFilterChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -167,8 +178,8 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
import ChatFilter from './widgets/conversation/ChatFilter';
|
||||
import ConversationAdvancedFilter from './widgets/conversation/ConversationAdvancedFilter';
|
||||
import ConversationBasicFilter from './widgets/conversation/ConversationBasicFilter';
|
||||
import ChatTypeTabs from './widgets/ChatTypeTabs';
|
||||
import ConversationCard from './widgets/conversation/ConversationCard';
|
||||
import timeMixin from '../mixins/time';
|
||||
@@ -199,10 +210,10 @@ export default {
|
||||
AddCustomViews,
|
||||
ChatTypeTabs,
|
||||
ConversationCard,
|
||||
ChatFilter,
|
||||
ConversationAdvancedFilter,
|
||||
DeleteCustomViews,
|
||||
ConversationBulkActions,
|
||||
ConversationBasicFilter,
|
||||
},
|
||||
mixins: [
|
||||
timeMixin,
|
||||
@@ -245,6 +256,7 @@ export default {
|
||||
return {
|
||||
activeAssigneeTab: wootConstants.ASSIGNEE_TYPE.ME,
|
||||
activeStatus: wootConstants.STATUS_TYPE.OPEN,
|
||||
activeSortBy: wootConstants.SORT_BY_TYPE.LATEST,
|
||||
showAdvancedFilters: false,
|
||||
advancedFilterTypes: advancedFilterTypes.map(filter => ({
|
||||
...filter,
|
||||
@@ -364,6 +376,7 @@ export default {
|
||||
inboxId: this.conversationInbox ? this.conversationInbox : undefined,
|
||||
assigneeType: this.activeAssigneeTab,
|
||||
status: this.activeStatus,
|
||||
sortBy: this.activeSortBy,
|
||||
page: this.conversationListPagination,
|
||||
labels: this.label ? [this.label] : undefined,
|
||||
teamId: this.teamId || undefined,
|
||||
@@ -479,7 +492,8 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('setChatFilter', this.activeStatus);
|
||||
this.$store.dispatch('setChatStatusFilter', this.activeStatus);
|
||||
this.$store.dispatch('setChatSortFilter', this.activeSortBy);
|
||||
this.resetAndFetchData();
|
||||
|
||||
bus.$on('fetch_conversation_stats', () => {
|
||||
@@ -625,11 +639,13 @@ export default {
|
||||
this.selectedConversations = [];
|
||||
this.selectedInboxes = [];
|
||||
},
|
||||
updateStatusType(index) {
|
||||
if (this.activeStatus !== index) {
|
||||
this.activeStatus = index;
|
||||
this.resetAndFetchData();
|
||||
onBasicFilterChange(value, type) {
|
||||
if (type === 'status') {
|
||||
this.activeStatus = value;
|
||||
} else {
|
||||
this.activeSortBy = value;
|
||||
}
|
||||
this.resetAndFetchData();
|
||||
},
|
||||
openLastSavedItemInFolder() {
|
||||
const lastItemOfFolder = this.folders[this.folders.length - 1];
|
||||
@@ -878,11 +894,15 @@ export default {
|
||||
&.list--full-width {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.page-sub-title {
|
||||
font-size: var(--font-size-two);
|
||||
}
|
||||
}
|
||||
.filter--actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-micro);
|
||||
gap: var(--space-smaller);
|
||||
}
|
||||
|
||||
.filter__applied {
|
||||
@@ -899,4 +919,19 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.conversation--status-pill {
|
||||
background: var(--color-background);
|
||||
border-radius: var(--border-radius-small);
|
||||
color: var(--color-medium-gray);
|
||||
font-size: var(--font-size-micro);
|
||||
font-weight: var(--font-weight-medium);
|
||||
margin: var(--space-micro) var(--space-small) 0;
|
||||
padding: var(--space-smaller);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.chat-list__title {
|
||||
max-width: 85%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -38,8 +38,8 @@ export default {
|
||||
this.onTabChange();
|
||||
},
|
||||
onTabChange() {
|
||||
this.$store.dispatch('setChatFilter', this.activeStatus);
|
||||
this.$emit('statusFilterChange', this.activeStatus);
|
||||
this.$store.dispatch('setChatStatusFilter', this.activeStatus);
|
||||
this.$emit('onChangeFilter', this.activeStatus);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div class="position-relative">
|
||||
<woot-button
|
||||
v-tooltip.right="$t('CHAT_LIST.SORT_TOOLTIP_LABEL')"
|
||||
variant="smooth"
|
||||
size="tiny"
|
||||
color-scheme="secondary"
|
||||
class="selector-button"
|
||||
icon="sort-icon"
|
||||
@click="toggleDropdown"
|
||||
/>
|
||||
<div
|
||||
v-if="showActionsDropdown"
|
||||
v-on-clickaway="closeDropdown"
|
||||
class="dropdown-pane dropdown-pane--open basic-filter"
|
||||
>
|
||||
<div class="filter__item">
|
||||
<span>{{ this.$t('CHAT_LIST.CHAT_SORT.STATUS') }}</span>
|
||||
<filter-item
|
||||
type="status"
|
||||
:selected-value="chatStatus"
|
||||
:items="chatStatusItems"
|
||||
path-prefix="CHAT_LIST.CHAT_STATUS_FILTER_ITEMS"
|
||||
@onChangeFilter="onChangeFilter"
|
||||
/>
|
||||
</div>
|
||||
<div class="filter__item">
|
||||
<span>{{ this.$t('CHAT_LIST.CHAT_SORT.ORDER_BY') }}</span>
|
||||
<filter-item
|
||||
type="sort"
|
||||
:selected-value="chatSortFilter"
|
||||
:items="chatSortItems"
|
||||
path-prefix="CHAT_LIST.CHAT_SORT_FILTER_ITEMS"
|
||||
@onChangeFilter="onChangeFilter"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { mixin as clickaway } from 'vue-clickaway';
|
||||
import FilterItem from './FilterItem';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FilterItem,
|
||||
},
|
||||
mixins: [clickaway],
|
||||
data() {
|
||||
return {
|
||||
showActionsDropdown: false,
|
||||
chatStatusItems: this.$t('CHAT_LIST.CHAT_STATUS_FILTER_ITEMS'),
|
||||
chatSortItems: this.$t('CHAT_LIST.CHAT_SORT_FILTER_ITEMS'),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
chatStatusFilter: 'getChatStatusFilter',
|
||||
chatSortFilter: 'getChatSortFilter',
|
||||
}),
|
||||
chatStatus() {
|
||||
return this.chatStatusFilter || wootConstants.STATUS_TYPE.OPEN;
|
||||
},
|
||||
sortFilter() {
|
||||
return this.chatSortFilter || wootConstants.SORT_BY_TYPE.LATEST;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onTabChange(value) {
|
||||
this.$emit('changeFilter', value);
|
||||
this.closeDropdown();
|
||||
},
|
||||
toggleDropdown() {
|
||||
this.showActionsDropdown = !this.showActionsDropdown;
|
||||
},
|
||||
closeDropdown() {
|
||||
this.showActionsDropdown = false;
|
||||
},
|
||||
onChangeFilter(type, value) {
|
||||
this.$emit('changeFilter', type, value);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.basic-filter {
|
||||
margin-top: var(--space-smaller);
|
||||
padding: var(--space-normal);
|
||||
right: 0;
|
||||
width: 21rem;
|
||||
|
||||
span {
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.filter__item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
&:last-child {
|
||||
margin-top: var(--space-normal);
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: var(--font-size-mini);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: var(--space-smaller);
|
||||
}
|
||||
|
||||
.dropdown-icon {
|
||||
margin-left: var(--space-smaller);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<select v-model="activeValue" class="status--filter" @change="onTabChange()">
|
||||
<option v-for="(value, status) in items" :key="status" :value="status">
|
||||
{{ $t(`${pathPrefix}.${status}.TEXT`) }}
|
||||
</option>
|
||||
</select>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
selectedValue: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
items: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
pathPrefix: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeValue: this.selectedValue,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onTabChange() {
|
||||
if (this.type === 'status') {
|
||||
this.$store.dispatch('setChatStatusFilter', this.activeValue);
|
||||
} else {
|
||||
this.$store.dispatch('setChatSortFilter', this.activeValue);
|
||||
}
|
||||
this.$emit('onChangeFilter', this.activeValue, this.type);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.status--filter {
|
||||
background-color: var(--color-background-light);
|
||||
border: 1px solid var(--color-border);
|
||||
font-size: var(--font-size-mini);
|
||||
height: var(--space-medium);
|
||||
margin: 0 var(--space-smaller);
|
||||
padding: 0 var(--space-medium) 0 var(--space-small);
|
||||
width: 126px;
|
||||
}
|
||||
</style>
|
||||
@@ -12,6 +12,10 @@ export default {
|
||||
SNOOZED: 'snoozed',
|
||||
ALL: 'all',
|
||||
},
|
||||
SORT_BY_TYPE: {
|
||||
LATEST: 'latest',
|
||||
CREATED_AT: 'sort_on_created_at',
|
||||
},
|
||||
ARTICLE_STATUS_TYPES: {
|
||||
DRAFT: 0,
|
||||
PUBLISH: 1,
|
||||
|
||||
@@ -105,8 +105,16 @@ class ActionCableConnector extends BaseActionCableConnector {
|
||||
onLogout = () => AuthAPI.logout();
|
||||
|
||||
onMessageCreated = data => {
|
||||
const {
|
||||
conversation: { last_activity_at: lastActivityAt },
|
||||
conversation_id: conversationId,
|
||||
} = data;
|
||||
DashboardAudioNotificationHelper.onNewMessage(data);
|
||||
this.app.$store.dispatch('addMessage', data);
|
||||
this.app.$store.dispatch('updateConversationLastActivity', {
|
||||
lastActivityAt,
|
||||
conversationId,
|
||||
});
|
||||
};
|
||||
|
||||
onReload = () => window.location.reload();
|
||||
|
||||
@@ -35,6 +35,20 @@
|
||||
"TEXT": "All"
|
||||
}
|
||||
},
|
||||
"VIEW_FILTER": "View",
|
||||
"SORT_TOOLTIP_LABEL": "Sort conversations",
|
||||
"CHAT_SORT": {
|
||||
"STATUS": "Status",
|
||||
"ORDER_BY": "Order by"
|
||||
},
|
||||
"CHAT_SORT_FILTER_ITEMS": {
|
||||
"latest": {
|
||||
"TEXT": "Last activity"
|
||||
},
|
||||
"sort_on_created_at": {
|
||||
"TEXT": "Created at"
|
||||
}
|
||||
},
|
||||
"ATTACHMENTS": {
|
||||
"image": {
|
||||
"CONTENT": "Picture message"
|
||||
@@ -55,6 +69,24 @@
|
||||
"CONTENT": "has shared a url"
|
||||
}
|
||||
},
|
||||
"CHAT_SORT_BY_FILTER": {
|
||||
"TITLE": "Sort conversation",
|
||||
"DROPDOWN_TITLE": "Sort by",
|
||||
"ITEMS": {
|
||||
"LATEST": {
|
||||
"NAME": "Last activity at",
|
||||
"LABEL": "Last activity"
|
||||
},
|
||||
"CREATED_AT": {
|
||||
"NAME": "Created at",
|
||||
"LABEL": "Created at"
|
||||
},
|
||||
"LAST_USER_MESSAGE_AT": {
|
||||
"NAME": "Last user message at",
|
||||
"LABEL": "Last message"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RECEIVED_VIA_EMAIL": "Received via email",
|
||||
"VIEW_TWEET_IN_TWITTER": "View tweet in Twitter",
|
||||
"REPLY_TO_TWEET": "Reply to this tweet",
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
<div class="icon">
|
||||
<fluent-icon icon="search" class="search--icon" size="16" />
|
||||
</div>
|
||||
<p class="search--label">{{ $t('CONVERSATION.SEARCH_MESSAGES') }}</p>
|
||||
<p class="search--label text-ellipsis">
|
||||
{{ $t('CONVERSATION.SEARCH_MESSAGES') }}
|
||||
</p>
|
||||
</router-link>
|
||||
<switch-layout
|
||||
:is-on-expanded-layout="isOnExpandedLayout"
|
||||
|
||||
@@ -335,10 +335,24 @@ const actions = {
|
||||
dispatch('contacts/setContact', sender);
|
||||
},
|
||||
|
||||
setChatFilter({ commit }, data) {
|
||||
updateConversationLastActivity(
|
||||
{ commit },
|
||||
{ conversationId, lastActivityAt }
|
||||
) {
|
||||
commit(types.UPDATE_CONVERSATION_LAST_ACTIVITY, {
|
||||
lastActivityAt,
|
||||
conversationId,
|
||||
});
|
||||
},
|
||||
|
||||
setChatStatusFilter({ commit }, data) {
|
||||
commit(types.CHANGE_CHAT_STATUS_FILTER, data);
|
||||
},
|
||||
|
||||
setChatSortFilter({ commit }, data) {
|
||||
commit(types.CHANGE_CHAT_SORT_FILTER, data);
|
||||
},
|
||||
|
||||
updateAssignee({ commit }, data) {
|
||||
commit(types.UPDATE_ASSIGNEE, data);
|
||||
},
|
||||
|
||||
@@ -9,10 +9,14 @@ export const getSelectedChatConversation = ({
|
||||
|
||||
// getters
|
||||
const getters = {
|
||||
getAllConversations: ({ allConversations }) =>
|
||||
allConversations.sort(
|
||||
(a, b) => b.messages.last()?.created_at - a.messages.last()?.created_at
|
||||
),
|
||||
getAllConversations: ({ allConversations, chatSortFilter }) => {
|
||||
const comparator = {
|
||||
latest: (a, b) => b.last_activity_at - a.last_activity_at,
|
||||
sort_on_created_at: (a, b) => a.created_at - b.created_at,
|
||||
};
|
||||
|
||||
return allConversations.sort(comparator[chatSortFilter]);
|
||||
},
|
||||
getSelectedChat: ({ selectedChatId, allConversations }) => {
|
||||
const selectedChat = allConversations.find(
|
||||
conversation => conversation.id === selectedChatId
|
||||
@@ -85,6 +89,7 @@ const getters = {
|
||||
).length;
|
||||
},
|
||||
getChatStatusFilter: ({ chatStatusFilter }) => chatStatusFilter,
|
||||
getChatSortFilter: ({ chatSortFilter }) => chatSortFilter,
|
||||
getSelectedInbox: ({ currentInbox }) => currentInbox,
|
||||
getConversationById: _state => conversationId => {
|
||||
return _state.allConversations.find(
|
||||
|
||||
@@ -10,6 +10,7 @@ const state = {
|
||||
allConversations: [],
|
||||
listLoadingStatus: true,
|
||||
chatStatusFilter: wootConstants.STATUS_TYPE.OPEN,
|
||||
chatSortFilter: wootConstants.SORT_BY_TYPE.LATEST,
|
||||
currentInbox: null,
|
||||
selectedChatId: null,
|
||||
appliedFilters: [],
|
||||
@@ -77,6 +78,13 @@ export const mutations = {
|
||||
Vue.set(chat.meta, 'team', team);
|
||||
},
|
||||
|
||||
[types.UPDATE_CONVERSATION_LAST_ACTIVITY](
|
||||
_state,
|
||||
{ lastActivityAt, conversationId }
|
||||
) {
|
||||
const [chat] = _state.allConversations.filter(c => c.id === conversationId);
|
||||
Vue.set(chat, 'last_activity_at', lastActivityAt);
|
||||
},
|
||||
[types.ASSIGN_PRIORITY](_state, { priority, conversationId }) {
|
||||
const [chat] = _state.allConversations.filter(c => c.id === conversationId);
|
||||
Vue.set(chat, 'priority', priority);
|
||||
@@ -175,6 +183,10 @@ export const mutations = {
|
||||
_state.chatStatusFilter = data;
|
||||
},
|
||||
|
||||
[types.CHANGE_CHAT_SORT_FILTER](_state, data) {
|
||||
_state.chatSortFilter = data;
|
||||
},
|
||||
|
||||
// Update assignee on action cable message
|
||||
[types.UPDATE_ASSIGNEE](_state, payload) {
|
||||
const [chat] = _state.allConversations.filter(c => c.id === payload.id);
|
||||
|
||||
@@ -16,6 +16,7 @@ export default {
|
||||
SET_ALL_MESSAGES_LOADED: 'SET_ALL_MESSAGES_LOADED',
|
||||
CLEAR_ALL_MESSAGES_LOADED: 'CLEAR_ALL_MESSAGES_LOADED',
|
||||
CHANGE_CHAT_STATUS_FILTER: 'CHANGE_CHAT_STATUS_FILTER',
|
||||
CHANGE_CHAT_SORT_FILTER: 'CHANGE_CHAT_SORT_FILTER',
|
||||
UPDATE_ASSIGNEE: 'UPDATE_ASSIGNEE',
|
||||
UPDATE_CONVERSATION_CONTACT: 'UPDATE_CONVERSATION_CONTACT',
|
||||
CLEAR_CONTACT_CONVERSATIONS: 'CLEAR_CONTACT_CONVERSATIONS',
|
||||
@@ -45,6 +46,7 @@ export default {
|
||||
SET_ACTIVE_INBOX: 'SET_ACTIVE_INBOX',
|
||||
UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES:
|
||||
'UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES',
|
||||
UPDATE_CONVERSATION_LAST_ACTIVITY: 'UPDATE_CONVERSATION_LAST_ACTIVITY',
|
||||
SET_MISSING_MESSAGES: 'SET_MISSING_MESSAGES',
|
||||
|
||||
SET_CONVERSATION_CAN_REPLY: 'SET_CONVERSATION_CAN_REPLY',
|
||||
|
||||
@@ -103,4 +103,7 @@
|
||||
--color-whatsapp-brand: #25d366;
|
||||
--color-sms-twilio: #f42f46;
|
||||
--color-cloud-generic: #18b7b0;
|
||||
|
||||
// Tech-debt
|
||||
--color-medium-gray: #8492a6;
|
||||
}
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
"translate-outline": "M16.953 5.303a1 1 0 0 0-1.906-.606c-.124.389-.236.899-.324 1.344-.565.012-1.12 0-1.652-.038a1 1 0 1 0-.142 1.995c.46.032.934.048 1.416.047a25.649 25.649 0 0 0-.24 1.698c-1.263.716-2.142 1.684-2.636 2.7-.624 1.283-.7 2.857.239 3.883.675.736 1.704.758 2.499.588.322-.068.654-.176.988-.32a1 1 0 0 0 1.746-.93 13.17 13.17 0 0 0-.041-.115 8.404 8.404 0 0 0 2.735-4.06c.286.251.507.55.658.864.284.594.334 1.271.099 1.91-.234.633-.78 1.313-1.84 1.843a1 1 0 0 0 .895 1.789c1.44-.72 2.385-1.758 2.821-2.94a4.436 4.436 0 0 0-.17-3.464 4.752 4.752 0 0 0-2.104-2.165C19.998 9.22 20 9.11 20 9a1 1 0 0 0-1.974-.23 5.984 5.984 0 0 0-1.796.138c.047-.305.102-.626.166-.964a20.142 20.142 0 0 0 2.842-.473 1 1 0 0 0-.476-1.942c-.622.152-1.286.272-1.964.358.048-.208.1-.409.155-.584Zm-3.686 8.015c.166-.34.414-.697.758-1.037.02.348.053.67.098.973.083.56.207 1.048.341 1.477a3.41 3.41 0 0 1-.674.227c-.429.092-.588.019-.614.006l-.004-.001c-.162-.193-.329-.774.095-1.645Zm4.498-2.562a6.362 6.362 0 0 1-1.568 2.73 7.763 7.763 0 0 1-.095-.525 10.294 10.294 0 0 1-.088-1.904c.033-.013.067-.024.1-.036l1.651-.265Zm0 0-1.651.265c.602-.212 1.155-.29 1.651-.265ZM7.536 6.29a6.342 6.342 0 0 0-4.456.331 1 1 0 0 0 .848 1.811 4.342 4.342 0 0 1 3.049-.222c.364.107.568.248.69.37.12.123.203.27.257.454.067.225.087.446.09.69a8.195 8.195 0 0 0-.555-.117c-1.146-.199-2.733-.215-4.262.64-1.271.713-1.796 2.168-1.682 3.448.12 1.326.94 2.679 2.572 3.136 1.48.414 2.913-.045 3.877-.507l.08-.04a1 1 0 0 0 1.96-.281V10.5c0-.053.002-.12.005-.2.012-.417.034-1.16-.168-1.838a3.043 3.043 0 0 0-.755-1.29c-.394-.398-.91-.694-1.547-.881h-.003Zm-.419 5.288c.344.06.647.143.887.222v2.197a7.021 7.021 0 0 1-.905.524c-.792.38-1.682.605-2.473.384-.698-.195-1.06-.742-1.119-1.389-.062-.693.243-1.286.667-1.523.987-.553 2.06-.569 2.943-.415Z",
|
||||
"eye-show-outline": "M12 9.005a4 4 0 1 1 0 8 4 4 0 0 1 0-8Zm0 1.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5ZM12 5.5c4.613 0 8.596 3.15 9.701 7.564a.75.75 0 1 1-1.455.365 8.503 8.503 0 0 0-16.493.004.75.75 0 0 1-1.455-.363A10.003 10.003 0 0 1 12 5.5Z",
|
||||
"eye-hide-outline": "M2.22 2.22a.75.75 0 0 0-.073.976l.073.084 4.034 4.035a9.986 9.986 0 0 0-3.955 5.75.75.75 0 0 0 1.455.364 8.49 8.49 0 0 1 3.58-5.034l1.81 1.81A4 4 0 0 0 14.8 15.86l5.919 5.92a.75.75 0 0 0 1.133-.977l-.073-.084-6.113-6.114.001-.002-1.2-1.198-2.87-2.87h.002L8.719 7.658l.001-.002-1.133-1.13L3.28 2.22a.75.75 0 0 0-1.06 0Zm7.984 9.045 3.535 3.536a2.5 2.5 0 0 1-3.535-3.535ZM12 5.5c-1 0-1.97.148-2.889.425l1.237 1.236a8.503 8.503 0 0 1 9.899 6.272.75.75 0 0 0 1.455-.363A10.003 10.003 0 0 0 12 5.5Zm.195 3.51 3.801 3.8a4.003 4.003 0 0 0-3.801-3.8Z",
|
||||
"sort-icon-outline": "m17.25 4l-.1.007a.75.75 0 0 0-.65.743v12.692l-3.22-3.218l-.084-.072a.75.75 0 0 0-.976 1.134l4.504 4.5l.084.072a.75.75 0 0 0 .976-.073l4.497-4.5l.072-.084a.75.75 0 0 0-.073-.977l-.084-.072a.75.75 0 0 0-.977.073L18 17.446V4.75l-.006-.102A.75.75 0 0 0 17.251 4Zm-11.036.22L1.72 8.715l-.073.084a.75.75 0 0 0 .073.976l.084.073a.75.75 0 0 0 .976-.073l3.217-3.218v12.698l.008.102a.75.75 0 0 0 .743.648l.101-.007a.75.75 0 0 0 .649-.743L7.497 6.559l3.223 3.217l.084.072a.75.75 0 0 0 .975-1.134L7.275 4.22l-.085-.072a.75.75 0 0 0-.976.073Z",
|
||||
"wand-outline": "m13.314 7.565l-.136.126l-10.48 10.488a2.27 2.27 0 0 0 3.211 3.208L16.388 10.9a2.251 2.251 0 0 0-.001-3.182l-.157-.146a2.25 2.25 0 0 0-2.916-.007Zm-.848 2.961l1.088 1.088l-8.706 8.713a.77.77 0 1 1-1.089-1.088l8.707-8.713Zm4.386 4.48L16.75 15a.75.75 0 0 0-.743.648L16 15.75v.75h-.75a.75.75 0 0 0-.743.648l-.007.102c0 .38.282.694.648.743l.102.007H16v.75c0 .38.282.694.648.743l.102.007a.75.75 0 0 0 .743-.648l.007-.102V18h.75a.75.75 0 0 0 .743-.648L19 17.25a.75.75 0 0 0-.648-.743l-.102-.007h-.75v-.75a.75.75 0 0 0-.648-.743L16.75 15l.102.007Zm-1.553-6.254l.027.027a.751.751 0 0 1 0 1.061l-.711.713l-1.089-1.089l.73-.73a.75.75 0 0 1 1.043.018ZM6.852 5.007L6.75 5a.75.75 0 0 0-.743.648L6 5.75v.75h-.75a.75.75 0 0 0-.743.648L4.5 7.25c0 .38.282.693.648.743L5.25 8H6v.75c0 .38.282.693.648.743l.102.007a.75.75 0 0 0 .743-.648L7.5 8.75V8h.75a.75.75 0 0 0 .743-.648L9 7.25a.75.75 0 0 0-.648-.743L8.25 6.5H7.5v-.75a.75.75 0 0 0-.648-.743L6.75 5l.102.007Zm12-2L18.75 3a.75.75 0 0 0-.743.648L18 3.75v.75h-.75a.75.75 0 0 0-.743.648l-.007.102c0 .38.282.693.648.743L17.25 6H18v.75c0 .38.282.693.648.743l.102.007a.75.75 0 0 0 .743-.648l.007-.102V6h.75a.75.75 0 0 0 .743-.648L21 5.25a.75.75 0 0 0-.648-.743L20.25 4.5h-.75v-.75a.75.75 0 0 0-.648-.743L18.75 3l.102.007Z",
|
||||
"grab-handle-outline": [
|
||||
"M5 4C5 3.44772 5.44772 3 6 3H10C10.5523 3 11 3.44772 11 4V7C11 7.55228 10.5523 8 10 8H6C5.44772 8 5 7.55228 5 7V4Z",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<li class="sub-menu-container">
|
||||
<ul class="sub-menu-li-container">
|
||||
<woot-dropdown-header :title="title" />
|
||||
<woot-dropdown-header v-if="title" :title="title" />
|
||||
<slot />
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -136,7 +136,8 @@ class Message < ApplicationRecord
|
||||
conversation_id: conversation.display_id,
|
||||
conversation: {
|
||||
assignee_id: conversation.assignee_id,
|
||||
unread_count: conversation.unread_incoming_messages.count
|
||||
unread_count: conversation.unread_incoming_messages.count,
|
||||
last_activity_at: conversation.last_activity_at.to_i
|
||||
}
|
||||
)
|
||||
data.merge!(echo_id: echo_id) if echo_id.present?
|
||||
|
||||
@@ -42,4 +42,5 @@ json.timestamp conversation.last_activity_at.to_i
|
||||
json.first_reply_created_at conversation.first_reply_created_at.to_i
|
||||
json.unread_count conversation.unread_incoming_messages.count
|
||||
json.last_non_activity_message conversation.messages.non_activity_messages.first.try(:push_event_data)
|
||||
json.last_activity_at conversation.last_activity_at.to_i
|
||||
json.priority conversation.priority
|
||||
|
||||
Reference in New Issue
Block a user