mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 19:17:48 +00:00 
			
		
		
		
	fix: Right click Snooze is not working (#9498)
This commit is contained in:
		| @@ -7,79 +7,17 @@ | ||||
|     ]" | ||||
|   > | ||||
|     <slot /> | ||||
|     <div | ||||
|       class="flex items-center justify-between px-4 py-0" | ||||
|       :class="{ | ||||
|         'pb-3 border-b border-slate-75 dark:border-slate-700': | ||||
|           hasAppliedFiltersOrActiveFolders, | ||||
|       }" | ||||
|     > | ||||
|       <div class="flex max-w-[85%] justify-center items-center"> | ||||
|         <h1 | ||||
|           class="text-xl font-medium break-words truncate text-black-900 dark:text-slate-100" | ||||
|           :title="pageTitle" | ||||
|         > | ||||
|           {{ pageTitle }} | ||||
|         </h1> | ||||
|         <span | ||||
|           v-if="!hasAppliedFiltersOrActiveFolders" | ||||
|           class="p-1 my-0.5 mx-1 rounded-md capitalize bg-slate-50 dark:bg-slate-800 text-xxs text-slate-600 dark:text-slate-300" | ||||
|         > | ||||
|           {{ $t(`CHAT_LIST.CHAT_STATUS_FILTER_ITEMS.${activeStatus}.TEXT`) }} | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex items-center gap-1"> | ||||
|         <div v-if="hasAppliedFilters && !hasActiveFolders"> | ||||
|           <woot-button | ||||
|             v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.ADD.SAVE_BUTTON')" | ||||
|             size="tiny" | ||||
|             variant="smooth" | ||||
|             color-scheme="secondary" | ||||
|             icon="save" | ||||
|             @click="onClickOpenAddFoldersModal" | ||||
|     <chat-list-header | ||||
|       :page-title="pageTitle" | ||||
|       :has-applied-filters="hasAppliedFilters" | ||||
|       :has-active-folders="hasActiveFolders" | ||||
|       :active-status="activeStatus" | ||||
|       @add-folders="onClickOpenAddFoldersModal" | ||||
|       @delete-folders="onClickOpenDeleteFoldersModal" | ||||
|       @filters-modal="onToggleAdvanceFiltersModal" | ||||
|       @reset-filters="resetAndFetchData" | ||||
|       @basic-filter-change="onBasicFilterChange" | ||||
|     /> | ||||
|           <woot-button | ||||
|             v-tooltip.top-end="$t('FILTER.CLEAR_BUTTON_LABEL')" | ||||
|             size="tiny" | ||||
|             variant="smooth" | ||||
|             color-scheme="alert" | ||||
|             icon="dismiss-circle" | ||||
|             @click="resetAndFetchData" | ||||
|           /> | ||||
|         </div> | ||||
|         <div v-if="hasActiveFolders"> | ||||
|           <woot-button | ||||
|             v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.EDIT.EDIT_BUTTON')" | ||||
|             size="tiny" | ||||
|             variant="smooth" | ||||
|             color-scheme="secondary" | ||||
|             icon="edit" | ||||
|             @click="onToggleAdvanceFiltersModal" | ||||
|           /> | ||||
|           <woot-button | ||||
|             v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.DELETE.DELETE_BUTTON')" | ||||
|             size="tiny" | ||||
|             variant="smooth" | ||||
|             color-scheme="alert" | ||||
|             icon="delete" | ||||
|             @click="onClickOpenDeleteFoldersModal" | ||||
|           /> | ||||
|         </div> | ||||
|         <woot-button | ||||
|           v-else | ||||
|           v-tooltip.right="$t('FILTER.TOOLTIP_LABEL')" | ||||
|           variant="smooth" | ||||
|           color-scheme="secondary" | ||||
|           icon="filter" | ||||
|           size="tiny" | ||||
|           @click="onToggleAdvanceFiltersModal" | ||||
|         /> | ||||
|         <conversation-basic-filter | ||||
|           v-if="!hasAppliedFiltersOrActiveFolders" | ||||
|           @changeFilter="onBasicFilterChange" | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
|     <add-custom-views | ||||
|       v-if="showAddFoldersModal" | ||||
| @@ -173,6 +111,15 @@ | ||||
|         @updateFolder="onUpdateSavedFilter" | ||||
|       /> | ||||
|     </woot-modal> | ||||
|     <woot-modal | ||||
|       :show.sync="showCustomSnoozeModal" | ||||
|       :on-close="hideCustomSnoozeModal" | ||||
|     > | ||||
|       <custom-snooze-modal | ||||
|         @close="hideCustomSnoozeModal" | ||||
|         @choose-time="chooseSnoozeTime" | ||||
|       /> | ||||
|     </woot-modal> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| @@ -180,8 +127,8 @@ | ||||
| import { mapGetters } from 'vuex'; | ||||
| import VirtualList from 'vue-virtual-scroll-list'; | ||||
|  | ||||
| import ChatListHeader from './ChatListHeader.vue'; | ||||
| import ConversationAdvancedFilter from './widgets/conversation/ConversationAdvancedFilter.vue'; | ||||
| import ConversationBasicFilter from './widgets/conversation/ConversationBasicFilter.vue'; | ||||
| import ChatTypeTabs from './widgets/ChatTypeTabs.vue'; | ||||
| import ConversationItem from './ConversationItem.vue'; | ||||
| import timeMixin from '../mixins/time'; | ||||
| @@ -205,10 +152,15 @@ import { | ||||
|   isOnUnattendedView, | ||||
| } from '../store/modules/conversations/helpers/actionHelpers'; | ||||
| import { CONVERSATION_EVENTS } from '../helper/AnalyticsHelper/events'; | ||||
| import { CMD_SNOOZE_CONVERSATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents'; | ||||
| import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers'; | ||||
| import { getUnixTime } from 'date-fns'; | ||||
| import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue'; | ||||
| import IntersectionObserver from './IntersectionObserver.vue'; | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     ChatListHeader, | ||||
|     AddCustomViews, | ||||
|     ChatTypeTabs, | ||||
|     // eslint-disable-next-line vue/no-unused-components | ||||
| @@ -216,9 +168,9 @@ export default { | ||||
|     ConversationAdvancedFilter, | ||||
|     DeleteCustomViews, | ||||
|     ConversationBulkActions, | ||||
|     ConversationBasicFilter, | ||||
|     IntersectionObserver, | ||||
|     VirtualList, | ||||
|     CustomSnoozeModal, | ||||
|   }, | ||||
|   mixins: [ | ||||
|     timeMixin, | ||||
| @@ -295,6 +247,7 @@ export default { | ||||
|         root: this.$refs.conversationList, | ||||
|         rootMargin: '100px 0px 100px 0px', | ||||
|       }, | ||||
|       showCustomSnoozeModal: false, | ||||
|  | ||||
|       itemComponent: ConversationItem, | ||||
|       // virtualListExtraProps is to pass the props to the conversationItem component. | ||||
| @@ -329,12 +282,13 @@ export default { | ||||
|       campaigns: 'campaigns/getAllCampaigns', | ||||
|       labels: 'labels/getLabels', | ||||
|       selectedConversations: 'bulkActions/getSelectedConversationIds', | ||||
|       contextMenuChatId: 'getContextMenuChatId', | ||||
|     }), | ||||
|     hasAppliedFilters() { | ||||
|       return this.appliedFilters.length !== 0; | ||||
|     }, | ||||
|     hasActiveFolders() { | ||||
|       return this.activeFolder && this.foldersId !== 0; | ||||
|       return Boolean(this.activeFolder && this.foldersId !== 0); | ||||
|     }, | ||||
|     hasAppliedFiltersOrActiveFolders() { | ||||
|       return this.hasAppliedFilters || this.hasActiveFolders; | ||||
| @@ -558,6 +512,11 @@ export default { | ||||
|     bus.$on('fetch_conversation_stats', () => { | ||||
|       this.$store.dispatch('conversationStats/get', this.conversationFilters); | ||||
|     }); | ||||
|  | ||||
|     bus.$on(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation); | ||||
|   }, | ||||
|   beforeDestroy() { | ||||
|     bus.$off(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation); | ||||
|   }, | ||||
|   methods: { | ||||
|     updateVirtualListProps(key, value) { | ||||
| @@ -1034,6 +993,43 @@ export default { | ||||
|     onContextMenuToggle(state) { | ||||
|       this.isContextMenuOpen = state; | ||||
|     }, | ||||
|     onCmdSnoozeConversation(snoozeType) { | ||||
|       if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) { | ||||
|         this.showCustomSnoozeModal = true; | ||||
|       } else { | ||||
|         this.toggleStatus( | ||||
|           wootConstants.STATUS_TYPE.SNOOZED, | ||||
|           findSnoozeTime(snoozeType) || null | ||||
|         ); | ||||
|       } | ||||
|     }, | ||||
|     chooseSnoozeTime(customSnoozeTime) { | ||||
|       this.showCustomSnoozeModal = false; | ||||
|       if (customSnoozeTime) { | ||||
|         this.toggleStatus( | ||||
|           wootConstants.STATUS_TYPE.SNOOZED, | ||||
|           getUnixTime(customSnoozeTime) | ||||
|         ); | ||||
|       } | ||||
|     }, | ||||
|     toggleStatus(status, snoozedUntil) { | ||||
|       this.$store | ||||
|         .dispatch('toggleStatus', { | ||||
|           conversationId: this.currentChat?.id || this.contextMenuChatId, | ||||
|           status, | ||||
|           snoozedUntil, | ||||
|         }) | ||||
|         .then(() => { | ||||
|           this.$store.dispatch('setContextMenuChatId', null); | ||||
|           this.showAlert(this.$t('CONVERSATION.CHANGE_STATUS')); | ||||
|         }); | ||||
|     }, | ||||
|     hideCustomSnoozeModal() { | ||||
|       // if we select custom snooze and then the custom snooze modal is open | ||||
|       // Then if the custom snooze modal is closed and set the context menu chat id to null | ||||
|       this.$store.dispatch('setContextMenuChatId', null); | ||||
|       this.showCustomSnoozeModal = false; | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
|   | ||||
							
								
								
									
										115
									
								
								app/javascript/dashboard/components/ChatListHeader.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								app/javascript/dashboard/components/ChatListHeader.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| <script setup> | ||||
| import { computed } from 'vue'; | ||||
| import ConversationBasicFilter from './widgets/conversation/ConversationBasicFilter.vue'; | ||||
|  | ||||
| const props = defineProps({ | ||||
|   pageTitle: { | ||||
|     type: String, | ||||
|     required: true, | ||||
|   }, | ||||
|   hasAppliedFilters: { | ||||
|     type: Boolean, | ||||
|     required: true, | ||||
|   }, | ||||
|   hasActiveFolders: { | ||||
|     type: Boolean, | ||||
|     required: true, | ||||
|   }, | ||||
|   activeStatus: { | ||||
|     type: String, | ||||
|     required: true, | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| const emits = defineEmits([ | ||||
|   'add-folders', | ||||
|   'delete-folders', | ||||
|   'reset-filters', | ||||
|   'basic-filter-change', | ||||
|   'filters-modal', | ||||
| ]); | ||||
|  | ||||
| const onBasicFilterChange = (value, type) => { | ||||
|   emits('basic-filter-change', value, type); | ||||
| }; | ||||
|  | ||||
| const hasAppliedFiltersOrActiveFolders = computed(() => { | ||||
|   return props.hasAppliedFilters || props.hasActiveFolders; | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div | ||||
|     class="flex items-center justify-between px-4 py-0" | ||||
|     :class="{ | ||||
|       'pb-3 border-b border-slate-75 dark:border-slate-700': | ||||
|         hasAppliedFiltersOrActiveFolders, | ||||
|     }" | ||||
|   > | ||||
|     <div class="flex max-w-[85%] justify-center items-center"> | ||||
|       <h1 | ||||
|         class="text-xl font-medium break-words truncate text-black-900 dark:text-slate-100" | ||||
|         :title="pageTitle" | ||||
|       > | ||||
|         {{ pageTitle }} | ||||
|       </h1> | ||||
|       <span | ||||
|         v-if="!hasAppliedFiltersOrActiveFolders" | ||||
|         class="p-1 my-0.5 mx-1 rounded-md capitalize bg-slate-50 dark:bg-slate-800 text-xxs text-slate-600 dark:text-slate-300" | ||||
|       > | ||||
|         {{ $t(`CHAT_LIST.CHAT_STATUS_FILTER_ITEMS.${activeStatus}.TEXT`) }} | ||||
|       </span> | ||||
|     </div> | ||||
|     <div class="flex items-center gap-1"> | ||||
|       <div v-if="hasAppliedFilters && !hasActiveFolders"> | ||||
|         <woot-button | ||||
|           v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.ADD.SAVE_BUTTON')" | ||||
|           size="tiny" | ||||
|           variant="smooth" | ||||
|           color-scheme="secondary" | ||||
|           icon="save" | ||||
|           @click="emits('add-folders')" | ||||
|         /> | ||||
|         <woot-button | ||||
|           v-tooltip.top-end="$t('FILTER.CLEAR_BUTTON_LABEL')" | ||||
|           size="tiny" | ||||
|           variant="smooth" | ||||
|           color-scheme="alert" | ||||
|           icon="dismiss-circle" | ||||
|           @click="emits('reset-filters')" | ||||
|         /> | ||||
|       </div> | ||||
|       <div v-if="hasActiveFolders"> | ||||
|         <woot-button | ||||
|           v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.EDIT.EDIT_BUTTON')" | ||||
|           size="tiny" | ||||
|           variant="smooth" | ||||
|           color-scheme="secondary" | ||||
|           icon="edit" | ||||
|           @click="emits('filters-modal')" | ||||
|         /> | ||||
|         <woot-button | ||||
|           v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.DELETE.DELETE_BUTTON')" | ||||
|           size="tiny" | ||||
|           variant="smooth" | ||||
|           color-scheme="alert" | ||||
|           icon="delete" | ||||
|           @click="emits('delete-folders')" | ||||
|         /> | ||||
|       </div> | ||||
|       <woot-button | ||||
|         v-else | ||||
|         v-tooltip.right="$t('FILTER.TOOLTIP_LABEL')" | ||||
|         variant="smooth" | ||||
|         color-scheme="secondary" | ||||
|         icon="filter" | ||||
|         size="tiny" | ||||
|         @click="emits('filters-modal')" | ||||
|       /> | ||||
|       <conversation-basic-filter | ||||
|         v-if="!hasAppliedFiltersOrActiveFolders" | ||||
|         @changeFilter="onBasicFilterChange" | ||||
|       /> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| @@ -73,25 +73,13 @@ | ||||
|         </woot-dropdown-item> | ||||
|       </woot-dropdown-menu> | ||||
|     </div> | ||||
|     <woot-modal | ||||
|       :show.sync="showCustomSnoozeModal" | ||||
|       :on-close="hideCustomSnoozeModal" | ||||
|     > | ||||
|       <custom-snooze-modal | ||||
|         @close="hideCustomSnoozeModal" | ||||
|         @choose-time="chooseSnoozeTime" | ||||
|       /> | ||||
|     </woot-modal> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { getUnixTime } from 'date-fns'; | ||||
| import { mapGetters } from 'vuex'; | ||||
| import alertMixin from 'shared/mixins/alertMixin'; | ||||
| import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue'; | ||||
| import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; | ||||
| import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers'; | ||||
| import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue'; | ||||
| import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue'; | ||||
|  | ||||
| @@ -99,14 +87,12 @@ import wootConstants from 'dashboard/constants/globals'; | ||||
| import { | ||||
|   CMD_REOPEN_CONVERSATION, | ||||
|   CMD_RESOLVE_CONVERSATION, | ||||
|   CMD_SNOOZE_CONVERSATION, | ||||
| } from '../../routes/dashboard/commands/commandBarBusEvents'; | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     WootDropdownItem, | ||||
|     WootDropdownMenu, | ||||
|     CustomSnoozeModal, | ||||
|   }, | ||||
|   mixins: [alertMixin, keyboardEventListenerMixins], | ||||
|   props: { conversationId: { type: [String, Number], required: true } }, | ||||
| @@ -115,7 +101,6 @@ export default { | ||||
|       isLoading: false, | ||||
|       showActionsDropdown: false, | ||||
|       STATUS_TYPE: wootConstants.STATUS_TYPE, | ||||
|       showCustomSnoozeModal: false, | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
| @@ -143,12 +128,10 @@ export default { | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     bus.$on(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation); | ||||
|     bus.$on(CMD_REOPEN_CONVERSATION, this.onCmdOpenConversation); | ||||
|     bus.$on(CMD_RESOLVE_CONVERSATION, this.onCmdResolveConversation); | ||||
|   }, | ||||
|   destroyed() { | ||||
|     bus.$off(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation); | ||||
|     bus.$off(CMD_REOPEN_CONVERSATION, this.onCmdOpenConversation); | ||||
|     bus.$off(CMD_RESOLVE_CONVERSATION, this.onCmdResolveConversation); | ||||
|   }, | ||||
| @@ -201,28 +184,6 @@ export default { | ||||
|         // error | ||||
|       } | ||||
|     }, | ||||
|     onCmdSnoozeConversation(snoozeType) { | ||||
|       if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) { | ||||
|         this.showCustomSnoozeModal = true; | ||||
|       } else { | ||||
|         this.toggleStatus( | ||||
|           this.STATUS_TYPE.SNOOZED, | ||||
|           findSnoozeTime(snoozeType) || null | ||||
|         ); | ||||
|       } | ||||
|     }, | ||||
|     chooseSnoozeTime(customSnoozeTime) { | ||||
|       this.showCustomSnoozeModal = false; | ||||
|       if (customSnoozeTime) { | ||||
|         this.toggleStatus( | ||||
|           this.STATUS_TYPE.SNOOZED, | ||||
|           getUnixTime(customSnoozeTime) | ||||
|         ); | ||||
|       } | ||||
|     }, | ||||
|     hideCustomSnoozeModal() { | ||||
|       this.showCustomSnoozeModal = false; | ||||
|     }, | ||||
|     onCmdOpenConversation() { | ||||
|       this.toggleStatus(this.STATUS_TYPE.OPEN); | ||||
|     }, | ||||
|   | ||||
| @@ -103,6 +103,7 @@ | ||||
|         :status="chat.status" | ||||
|         :inbox-id="inbox.id" | ||||
|         :priority="chat.priority" | ||||
|         :chat-id="chat.id" | ||||
|         :has-unread-messages="hasUnread" | ||||
|         @update-conversation="onUpdateConversation" | ||||
|         @assign-agent="onAssignAgent" | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
|       /> | ||||
|     </template> | ||||
|     <menu-item | ||||
|       v-if="show(snoozeOption.key)" | ||||
|       v-if="showSnooze" | ||||
|       :option="snoozeOption" | ||||
|       variant="icon" | ||||
|       @click="snoozeConversation()" | ||||
| @@ -86,6 +86,10 @@ export default { | ||||
|   }, | ||||
|   mixins: [agentMixin], | ||||
|   props: { | ||||
|     chatId: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|     status: { | ||||
|       type: String, | ||||
|       default: '', | ||||
| @@ -205,6 +209,10 @@ export default { | ||||
|         ...this.filteredAgentOnAvailability, | ||||
|       ]; | ||||
|     }, | ||||
|     showSnooze() { | ||||
|       // Don't show snooze if the conversation is already snoozed/resolved/pending | ||||
|       return this.status === wootConstants.STATUS_TYPE.OPEN; | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.$store.dispatch('inboxAssignableAgents/fetch', [this.inboxId]); | ||||
| @@ -213,7 +221,8 @@ export default { | ||||
|     toggleStatus(status, snoozedUntil) { | ||||
|       this.$emit('update-conversation', status, snoozedUntil); | ||||
|     }, | ||||
|     snoozeConversation() { | ||||
|     async snoozeConversation() { | ||||
|       await this.$store.dispatch('setContextMenuChatId', this.chatId); | ||||
|       const ninja = document.querySelector('ninja-keys'); | ||||
|       ninja.open({ parent: 'snooze_conversation' }); | ||||
|     }, | ||||
|   | ||||
| @@ -52,8 +52,22 @@ export const validateLoggedInRoutes = (to, user, roleWiseRoutes) => { | ||||
|   return null; | ||||
| }; | ||||
|  | ||||
| export const isAConversationRoute = routeName => | ||||
|   [ | ||||
| export const isAConversationRoute = ( | ||||
|   routeName, | ||||
|   includeBase = false, | ||||
|   includeExtended = true | ||||
| ) => { | ||||
|   const baseRoutes = [ | ||||
|     'home', | ||||
|     'conversation_mentions', | ||||
|     'conversation_unattended', | ||||
|     'inbox_dashboard', | ||||
|     'label_conversations', | ||||
|     'team_conversations', | ||||
|     'folder_conversations', | ||||
|     'conversation_participating', | ||||
|   ]; | ||||
|   const extendedRoutes = [ | ||||
|     'inbox_conversation', | ||||
|     'conversation_through_mentions', | ||||
|     'conversation_through_unattended', | ||||
| @@ -62,7 +76,15 @@ export const isAConversationRoute = routeName => | ||||
|     'conversations_through_team', | ||||
|     'conversations_through_folders', | ||||
|     'conversation_through_participating', | ||||
|   ].includes(routeName); | ||||
|   ]; | ||||
|  | ||||
|   const routes = [ | ||||
|     ...(includeBase ? baseRoutes : []), | ||||
|     ...(includeExtended ? extendedRoutes : []), | ||||
|   ]; | ||||
|  | ||||
|   return routes.includes(routeName); | ||||
| }; | ||||
|  | ||||
| export const getConversationDashboardRoute = routeName => { | ||||
|   switch (routeName) { | ||||
|   | ||||
| @@ -106,6 +106,51 @@ describe('isAConversationRoute', () => { | ||||
|     expect(isAConversationRoute('conversations_through_team')).toBe(true); | ||||
|     expect(isAConversationRoute('dashboard')).toBe(false); | ||||
|   }); | ||||
|  | ||||
|   it('returns true if base conversation route name is provided and includeBase is true', () => { | ||||
|     expect(isAConversationRoute('home', true)).toBe(true); | ||||
|     expect(isAConversationRoute('conversation_mentions', true)).toBe(true); | ||||
|     expect(isAConversationRoute('conversation_unattended', true)).toBe(true); | ||||
|     expect(isAConversationRoute('inbox_dashboard', true)).toBe(true); | ||||
|     expect(isAConversationRoute('label_conversations', true)).toBe(true); | ||||
|     expect(isAConversationRoute('team_conversations', true)).toBe(true); | ||||
|     expect(isAConversationRoute('folder_conversations', true)).toBe(true); | ||||
|     expect(isAConversationRoute('conversation_participating', true)).toBe(true); | ||||
|   }); | ||||
|  | ||||
|   it('returns false if base conversation route name is provided and includeBase is false', () => { | ||||
|     expect(isAConversationRoute('home', false)).toBe(false); | ||||
|     expect(isAConversationRoute('conversation_mentions', false)).toBe(false); | ||||
|     expect(isAConversationRoute('conversation_unattended', false)).toBe(false); | ||||
|     expect(isAConversationRoute('inbox_dashboard', false)).toBe(false); | ||||
|     expect(isAConversationRoute('label_conversations', false)).toBe(false); | ||||
|     expect(isAConversationRoute('team_conversations', false)).toBe(false); | ||||
|     expect(isAConversationRoute('folder_conversations', false)).toBe(false); | ||||
|     expect(isAConversationRoute('conversation_participating', false)).toBe( | ||||
|       false | ||||
|     ); | ||||
|   }); | ||||
|  | ||||
|   it('returns true if base conversation route name is provided and includeBase and includeExtended is true', () => { | ||||
|     expect(isAConversationRoute('home', true, true)).toBe(true); | ||||
|     expect(isAConversationRoute('conversation_mentions', true, true)).toBe( | ||||
|       true | ||||
|     ); | ||||
|     expect(isAConversationRoute('conversation_unattended', true, true)).toBe( | ||||
|       true | ||||
|     ); | ||||
|     expect(isAConversationRoute('inbox_dashboard', true, true)).toBe(true); | ||||
|     expect(isAConversationRoute('label_conversations', true, true)).toBe(true); | ||||
|     expect(isAConversationRoute('team_conversations', true, true)).toBe(true); | ||||
|     expect(isAConversationRoute('folder_conversations', true, true)).toBe(true); | ||||
|     expect(isAConversationRoute('conversation_participating', true, true)).toBe( | ||||
|       true | ||||
|     ); | ||||
|   }); | ||||
|  | ||||
|   it('returns false if base conversation route name is not provided', () => { | ||||
|     expect(isAConversationRoute('')).toBe(false); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| describe('getConversationDashboardRoute', () => { | ||||
|   | ||||
| @@ -154,7 +154,7 @@ | ||||
|       "UNTIL_TOMORROW": "Until tomorrow", | ||||
|       "UNTIL_NEXT_MONTH": "Until next month", | ||||
|       "AN_HOUR_FROM_NOW": "Until an hour from now", | ||||
|       "CUSTOM": "Custom...", | ||||
|       "UNTIL_CUSTOM_TIME": "Custom...", | ||||
|       "CHANGE_APPEARANCE": "Change Appearance", | ||||
|       "LIGHT_MODE": "Light", | ||||
|       "DARK_MODE": "Dark", | ||||
|   | ||||
| @@ -12,6 +12,8 @@ import { | ||||
|   ICON_RESOLVE_CONVERSATION, | ||||
| } from './CommandBarIcons'; | ||||
|  | ||||
| import { createSnoozeHandlers } from './commandBarActions'; | ||||
|  | ||||
| const SNOOZE_OPTIONS = wootConstants.SNOOZE_OPTIONS; | ||||
|  | ||||
| export const SNOOZE_CONVERSATION_BULK_ACTIONS = [ | ||||
| @@ -22,79 +24,11 @@ export const SNOOZE_CONVERSATION_BULK_ACTIONS = [ | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     children: Object.values(SNOOZE_OPTIONS), | ||||
|   }, | ||||
|  | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_NEXT_REPLY, | ||||
|     title: 'COMMAND_BAR.COMMANDS.UNTIL_NEXT_REPLY', | ||||
|     parent: 'bulk_action_snooze_conversation', | ||||
|     section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit( | ||||
|   ...createSnoozeHandlers( | ||||
|     CMD_BULK_ACTION_SNOOZE_CONVERSATION, | ||||
|         SNOOZE_OPTIONS.UNTIL_NEXT_REPLY | ||||
|     'bulk_action_snooze_conversation', | ||||
|     'COMMAND_BAR.SECTIONS.BULK_ACTIONS' | ||||
|   ), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.AN_HOUR_FROM_NOW, | ||||
|     title: 'COMMAND_BAR.COMMANDS.AN_HOUR_FROM_NOW', | ||||
|     parent: 'bulk_action_snooze_conversation', | ||||
|     section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit( | ||||
|         CMD_BULK_ACTION_SNOOZE_CONVERSATION, | ||||
|         SNOOZE_OPTIONS.AN_HOUR_FROM_NOW | ||||
|       ), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_TOMORROW, | ||||
|     title: 'COMMAND_BAR.COMMANDS.UNTIL_TOMORROW', | ||||
|     section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS', | ||||
|     parent: 'bulk_action_snooze_conversation', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit( | ||||
|         CMD_BULK_ACTION_SNOOZE_CONVERSATION, | ||||
|         SNOOZE_OPTIONS.UNTIL_TOMORROW | ||||
|       ), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_NEXT_WEEK, | ||||
|     title: 'COMMAND_BAR.COMMANDS.UNTIL_NEXT_WEEK', | ||||
|     section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS', | ||||
|     parent: 'bulk_action_snooze_conversation', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit( | ||||
|         CMD_BULK_ACTION_SNOOZE_CONVERSATION, | ||||
|         SNOOZE_OPTIONS.UNTIL_NEXT_WEEK | ||||
|       ), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_NEXT_MONTH, | ||||
|     title: 'COMMAND_BAR.COMMANDS.UNTIL_NEXT_MONTH', | ||||
|     section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS', | ||||
|     parent: 'bulk_action_snooze_conversation', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit( | ||||
|         CMD_BULK_ACTION_SNOOZE_CONVERSATION, | ||||
|         SNOOZE_OPTIONS.UNTIL_NEXT_MONTH | ||||
|       ), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME, | ||||
|     title: 'COMMAND_BAR.COMMANDS.CUSTOM', | ||||
|     section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS', | ||||
|     parent: 'bulk_action_snooze_conversation', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit( | ||||
|         CMD_BULK_ACTION_SNOOZE_CONVERSATION, | ||||
|         SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME | ||||
|       ), | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| export const RESOLVED_CONVERSATION_BULK_ACTIONS = [ | ||||
|   | ||||
| @@ -30,6 +30,17 @@ export const OPEN_CONVERSATION_ACTIONS = [ | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| export const createSnoozeHandlers = (busEventName, parentId, section) => { | ||||
|   return Object.values(SNOOZE_OPTIONS).map(option => ({ | ||||
|     id: option, | ||||
|     title: `COMMAND_BAR.COMMANDS.${option.toUpperCase()}`, | ||||
|     parent: parentId, | ||||
|     section: section, | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => bus.$emit(busEventName, option), | ||||
|   })); | ||||
| }; | ||||
|  | ||||
| export const SNOOZE_CONVERSATION_ACTIONS = [ | ||||
|   { | ||||
|     id: 'snooze_conversation', | ||||
| @@ -37,61 +48,11 @@ export const SNOOZE_CONVERSATION_ACTIONS = [ | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     children: Object.values(SNOOZE_OPTIONS), | ||||
|   }, | ||||
|  | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_NEXT_REPLY, | ||||
|     title: 'COMMAND_BAR.COMMANDS.UNTIL_NEXT_REPLY', | ||||
|     parent: 'snooze_conversation', | ||||
|     section: 'COMMAND_BAR.SECTIONS.SNOOZE_CONVERSATION', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit(CMD_SNOOZE_CONVERSATION, SNOOZE_OPTIONS.UNTIL_NEXT_REPLY), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.AN_HOUR_FROM_NOW, | ||||
|     title: 'COMMAND_BAR.COMMANDS.AN_HOUR_FROM_NOW', | ||||
|     parent: 'snooze_conversation', | ||||
|     section: 'COMMAND_BAR.SECTIONS.SNOOZE_CONVERSATION', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit(CMD_SNOOZE_CONVERSATION, SNOOZE_OPTIONS.AN_HOUR_FROM_NOW), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_TOMORROW, | ||||
|     title: 'COMMAND_BAR.COMMANDS.UNTIL_TOMORROW', | ||||
|     section: 'COMMAND_BAR.SECTIONS.SNOOZE_CONVERSATION', | ||||
|     parent: 'snooze_conversation', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit(CMD_SNOOZE_CONVERSATION, SNOOZE_OPTIONS.UNTIL_TOMORROW), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_NEXT_WEEK, | ||||
|     title: 'COMMAND_BAR.COMMANDS.UNTIL_NEXT_WEEK', | ||||
|     section: 'COMMAND_BAR.SECTIONS.SNOOZE_CONVERSATION', | ||||
|     parent: 'snooze_conversation', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit(CMD_SNOOZE_CONVERSATION, SNOOZE_OPTIONS.UNTIL_NEXT_WEEK), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_NEXT_MONTH, | ||||
|     title: 'COMMAND_BAR.COMMANDS.UNTIL_NEXT_MONTH', | ||||
|     section: 'COMMAND_BAR.SECTIONS.SNOOZE_CONVERSATION', | ||||
|     parent: 'snooze_conversation', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit(CMD_SNOOZE_CONVERSATION, SNOOZE_OPTIONS.UNTIL_NEXT_MONTH), | ||||
|   }, | ||||
|   { | ||||
|     id: SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME, | ||||
|     title: 'COMMAND_BAR.COMMANDS.CUSTOM', | ||||
|     section: 'COMMAND_BAR.SECTIONS.SNOOZE_CONVERSATION', | ||||
|     parent: 'snooze_conversation', | ||||
|     icon: ICON_SNOOZE_CONVERSATION, | ||||
|     handler: () => | ||||
|       bus.$emit(CMD_SNOOZE_CONVERSATION, SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME), | ||||
|   }, | ||||
|   ...createSnoozeHandlers( | ||||
|     CMD_SNOOZE_CONVERSATION, | ||||
|     'snooze_conversation', | ||||
|     'COMMAND_BAR.SECTIONS.SNOOZE_CONVERSATION' | ||||
|   ), | ||||
| ]; | ||||
|  | ||||
| export const RESOLVED_CONVERSATION_ACTIONS = [ | ||||
|   | ||||
| @@ -6,11 +6,13 @@ | ||||
|     hideBreadcrumbs | ||||
|     :placeholder="placeholder" | ||||
|     @selected="onSelected" | ||||
|     @closed="onClosed" | ||||
|   /> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import 'ninja-keys'; | ||||
| import '@chatwoot/ninja-keys'; | ||||
| import wootConstants from 'dashboard/constants/globals'; | ||||
| import conversationHotKeysMixin from './conversationHotKeys'; | ||||
| import bulkActionsHotKeysMixin from './bulkActionsHotKeys'; | ||||
| import inboxHotKeysMixin from './inboxHotKeys'; | ||||
| @@ -34,6 +36,14 @@ export default { | ||||
|     appearanceHotKeys, | ||||
|     goToCommandHotKeys, | ||||
|   ], | ||||
|   data() { | ||||
|     return { | ||||
|       // Added selectedSnoozeType to track the selected snooze type | ||||
|       // So if the selected snooze type is "custom snooze" then we set selectedSnoozeType with the CMD action id | ||||
|       // So that we can track the selected snooze type and when we close the command bar | ||||
|       selectedSnoozeType: null, | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
|     placeholder() { | ||||
|       return this.$t('COMMAND_BAR.SEARCH_PLACEHOLDER'); | ||||
| @@ -67,14 +77,35 @@ export default { | ||||
|       this.$refs.ninjakeys.data = this.hotKeys; | ||||
|     }, | ||||
|     onSelected(item) { | ||||
|       const { detail: { action: { title = null, section = null } = {} } = {} } = | ||||
|         item; | ||||
|       const { | ||||
|         detail: { | ||||
|           action: { title = null, section = null, id = null } = {}, | ||||
|         } = {}, | ||||
|       } = item; | ||||
|       // Added this condition to prevent setting the selectedSnoozeType to null | ||||
|       // When we select the "custom snooze" (CMD bar will close and the custom snooze modal will open) | ||||
|       if (id === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) { | ||||
|         this.selectedSnoozeType = | ||||
|           wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME; | ||||
|       } else { | ||||
|         this.selectedSnoozeType = null; | ||||
|       } | ||||
|       this.$track(GENERAL_EVENTS.COMMAND_BAR, { | ||||
|         section, | ||||
|         action: title, | ||||
|       }); | ||||
|       this.setCommandbarData(); | ||||
|     }, | ||||
|     onClosed() { | ||||
|       // If the selectedSnoozeType is not "SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME (custom snooze)" then we set the context menu chat id to null | ||||
|       // Else we do nothing and its handled in the ChatList.vue hideCustomSnoozeModal() method | ||||
|       if ( | ||||
|         this.selectedSnoozeType !== | ||||
|         wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME | ||||
|       ) { | ||||
|         this.$store.dispatch('setContextMenuChatId', null); | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
|   | ||||
| @@ -55,11 +55,15 @@ export default { | ||||
|     replyMode() { | ||||
|       this.setCommandbarData(); | ||||
|     }, | ||||
|     contextMenuChatId() { | ||||
|       this.setCommandbarData(); | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters({ | ||||
|       currentChat: 'getSelectedChat', | ||||
|       replyMode: 'draftMessages/getReplyEditorMode', | ||||
|       contextMenuChatId: 'getContextMenuChatId', | ||||
|     }), | ||||
|     draftMessage() { | ||||
|       return this.$store.getters['draftMessages/get'](this.draftKey); | ||||
| @@ -93,6 +97,7 @@ export default { | ||||
|       } | ||||
|       return this.prepareActions(actions); | ||||
|     }, | ||||
|  | ||||
|     priorityOptions() { | ||||
|       return [ | ||||
|         { | ||||
| @@ -327,11 +332,21 @@ export default { | ||||
|       ]; | ||||
|     }, | ||||
|  | ||||
|     conversationHotKeys() { | ||||
|       if ( | ||||
|     isConversationOrInboxRoute() { | ||||
|       return ( | ||||
|         isAConversationRoute(this.$route.name) || | ||||
|         isAInboxViewRoute(this.$route.name) | ||||
|       ) { | ||||
|       ); | ||||
|     }, | ||||
|  | ||||
|     shouldShowSnoozeOption() { | ||||
|       return ( | ||||
|         isAConversationRoute(this.$route.name, true, false) && | ||||
|         this.contextMenuChatId | ||||
|       ); | ||||
|     }, | ||||
|  | ||||
|     getDefaultConversationHotKeys() { | ||||
|       const defaultConversationHotKeys = [ | ||||
|         ...this.statusActions, | ||||
|         ...this.conversationAdditionalActions, | ||||
| @@ -344,8 +359,15 @@ export default { | ||||
|         return [...defaultConversationHotKeys, ...this.AIAssistActions]; | ||||
|       } | ||||
|       return defaultConversationHotKeys; | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     conversationHotKeys() { | ||||
|       if (this.shouldShowSnoozeOption) { | ||||
|         return this.prepareActions(SNOOZE_CONVERSATION_ACTIONS); | ||||
|       } | ||||
|       if (this.isConversationOrInboxRoute) { | ||||
|         return this.getDefaultConversationHotKeys; | ||||
|       } | ||||
|       return []; | ||||
|     }, | ||||
|   }, | ||||
|   | ||||
| @@ -466,6 +466,10 @@ const actions = { | ||||
|     commit(types.ASSIGN_PRIORITY, { priority, conversationId }); | ||||
|   }, | ||||
|  | ||||
|   setContextMenuChatId({ commit }, chatId) { | ||||
|     commit(types.SET_CONTEXT_MENU_CHAT_ID, chatId); | ||||
|   }, | ||||
|  | ||||
|   ...messageReadActions, | ||||
|   ...messageTranslateActions, | ||||
| }; | ||||
|   | ||||
| @@ -100,6 +100,10 @@ const getters = { | ||||
|   getConversationLastSeen: _state => { | ||||
|     return _state.conversationLastSeen; | ||||
|   }, | ||||
|  | ||||
|   getContextMenuChatId: _state => { | ||||
|     return _state.contextMenuChatId; | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| export default getters; | ||||
|   | ||||
| @@ -15,6 +15,7 @@ const state = { | ||||
|   currentInbox: null, | ||||
|   selectedChatId: null, | ||||
|   appliedFilters: [], | ||||
|   contextMenuChatId: null, | ||||
|   conversationParticipants: [], | ||||
|   conversationLastSeen: null, | ||||
|   syncConversationsMessages: {}, | ||||
| @@ -281,6 +282,10 @@ export const mutations = { | ||||
|   ) { | ||||
|     _state.syncConversationsMessages[conversationId] = messageId; | ||||
|   }, | ||||
|  | ||||
|   [types.SET_CONTEXT_MENU_CHAT_ID](_state, chatId) { | ||||
|     _state.contextMenuChatId = chatId; | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| export default { | ||||
|   | ||||
| @@ -652,4 +652,11 @@ describe('#addMentions', () => { | ||||
|       ]); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('#setContextMenuChatId', () => { | ||||
|     it('sets the context menu chat id', () => { | ||||
|       actions.setContextMenuChatId({ commit }, 1); | ||||
|       expect(commit.mock.calls).toEqual([[types.SET_CONTEXT_MENU_CHAT_ID, 1]]); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -272,4 +272,11 @@ describe('#getters', () => { | ||||
|       ]); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('#getContextMenuChatId', () => { | ||||
|     it('returns the context menu chat id', () => { | ||||
|       const state = { contextMenuChatId: 1 }; | ||||
|       expect(getters.getContextMenuChatId(state)).toEqual(1); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -403,4 +403,12 @@ describe('#mutations', () => { | ||||
|       expect(state.allConversations[0].attachments).toHaveLength(1); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('#SET_CONTEXT_MENU_CHAT_ID', () => { | ||||
|     it('sets the context menu chat id', () => { | ||||
|       const state = { contextMenuChatId: 1 }; | ||||
|       mutations[types.SET_CONTEXT_MENU_CHAT_ID](state, 2); | ||||
|       expect(state.contextMenuChatId).toEqual(2); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -58,6 +58,8 @@ export default { | ||||
|  | ||||
|   SET_CONVERSATION_CAN_REPLY: 'SET_CONVERSATION_CAN_REPLY', | ||||
|  | ||||
|   SET_CONTEXT_MENU_CHAT_ID: 'SET_CONTEXT_MENU_CHAT_ID', | ||||
|  | ||||
|   // Inboxes | ||||
|   SET_INBOXES_UI_FLAG: 'SET_INBOXES_UI_FLAG', | ||||
|   SET_INBOXES: 'SET_INBOXES', | ||||
|   | ||||
| @@ -67,7 +67,7 @@ | ||||
|     "markdown-it": "^13.0.2", | ||||
|     "markdown-it-link-attributes": "^4.0.1", | ||||
|     "md5": "^2.3.0", | ||||
|     "ninja-keys": "^1.2.2", | ||||
|     "@chatwoot/ninja-keys": "1.2.3", | ||||
|     "opus-recorder": "^8.0.5", | ||||
|     "postcss": "^8.4.31", | ||||
|     "postcss-loader": "^4.2.0", | ||||
|   | ||||
							
								
								
									
										18
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								yarn.lock
									
									
									
									
									
								
							| @@ -3156,6 +3156,15 @@ | ||||
|     "@braid/vue-formulate-i18n" "^1.16.0" | ||||
|     is-plain-object "^3.0.1" | ||||
|  | ||||
| "@chatwoot/ninja-keys@1.2.3": | ||||
|   version "1.2.3" | ||||
|   resolved "https://registry.yarnpkg.com/@chatwoot/ninja-keys/-/ninja-keys-1.2.3.tgz#3c3f2b505f091ef4707fd1da39bb2ec6d12e7824" | ||||
|   integrity sha512-xM8d9P5ikDMZm2WbaCTk/TW5HFauylrU3cJ75fq5je6ixKwyhl/0kZbVN/vbbZN4+AUX/OaSIn6IJbtCgIF67g== | ||||
|   dependencies: | ||||
|     "@material/mwc-icon" "0.25.3" | ||||
|     hotkeys-js "3.8.7" | ||||
|     lit "2.2.6" | ||||
|  | ||||
| "@chatwoot/prosemirror-schema@1.0.5": | ||||
|   version "1.0.5" | ||||
|   resolved "https://registry.yarnpkg.com/@chatwoot/prosemirror-schema/-/prosemirror-schema-1.0.5.tgz#d6053692beae59d466ac0b04128fa157f59eb176" | ||||
| @@ -15083,15 +15092,6 @@ nice-try@^1.0.4: | ||||
|   resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" | ||||
|   integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== | ||||
|  | ||||
| ninja-keys@^1.2.2: | ||||
|   version "1.2.2" | ||||
|   resolved "https://registry.yarnpkg.com/ninja-keys/-/ninja-keys-1.2.2.tgz#c1e1ec1a98aee3a977ee77157ac4aa865348be88" | ||||
|   integrity sha512-ylo8jzKowi3XBHkgHRjBJaKQkl32WRLr7kRiA0ajiku11vHRDJ2xANtTScR5C7XlDwKEOYvUPesCKacUeeLAYw== | ||||
|   dependencies: | ||||
|     "@material/mwc-icon" "0.25.3" | ||||
|     hotkeys-js "3.8.7" | ||||
|     lit "2.2.6" | ||||
|  | ||||
| no-case@^3.0.4: | ||||
|   version "3.0.4" | ||||
|   resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sivin Varghese
					Sivin Varghese