diff --git a/Gemfile.lock b/Gemfile.lock
index 6b806fc3d..374555cc3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -555,7 +555,7 @@ GEM
rack (2.2.9)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
- rack-contrib (2.4.0)
+ rack-contrib (2.5.0)
rack (< 4)
rack-cors (2.0.0)
rack (>= 2.0.0)
diff --git a/app/javascript/dashboard/api/inbox/conversation.js b/app/javascript/dashboard/api/inbox/conversation.js
index 94cc81354..ebc6176e7 100644
--- a/app/javascript/dashboard/api/inbox/conversation.js
+++ b/app/javascript/dashboard/api/inbox/conversation.js
@@ -15,6 +15,7 @@ class ConversationApi extends ApiClient {
teamId,
conversationType,
sortBy,
+ updatedWithin,
}) {
return axios.get(this.url, {
params: {
@@ -26,6 +27,7 @@ class ConversationApi extends ApiClient {
labels,
conversation_type: conversationType,
sort_by: sortBy,
+ updated_within: updatedWithin,
},
});
}
diff --git a/app/javascript/dashboard/api/specs/inbox/conversation.spec.js b/app/javascript/dashboard/api/specs/inbox/conversation.spec.js
index ecc833e16..3287d7477 100644
--- a/app/javascript/dashboard/api/specs/inbox/conversation.spec.js
+++ b/app/javascript/dashboard/api/specs/inbox/conversation.spec.js
@@ -46,6 +46,7 @@ describe('#ConversationAPI', () => {
page: 1,
labels: [],
teamId: 1,
+ updatedWithin: 20,
});
expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/conversations', {
params: {
@@ -55,6 +56,7 @@ describe('#ConversationAPI', () => {
assignee_type: 'me',
page: 1,
labels: [],
+ updated_within: 20,
},
});
});
diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue
index 5b592a1f7..eb410f7d5 100644
--- a/app/javascript/dashboard/components/ChatList.vue
+++ b/app/javascript/dashboard/components/ChatList.vue
@@ -268,6 +268,7 @@ export default {
chatLists: 'getAllConversations',
mineChatsList: 'getMineChats',
allChatList: 'getAllStatusChats',
+ chatListFilters: 'getChatListFilters',
unAssignedChatsList: 'getUnAssignedChats',
chatListLoading: 'getChatListLoadingStatus',
currentUserID: 'getCurrentUserID',
@@ -293,13 +294,6 @@ export default {
hasAppliedFiltersOrActiveFolders() {
return this.hasAppliedFilters || this.hasActiveFolders;
},
- savedFoldersValue() {
- if (this.hasActiveFolders) {
- const payload = this.activeFolder.query;
- this.fetchSavedFilteredConversations(payload);
- }
- return {};
- },
showEndOfListMessage() {
return (
this.conversationList.length &&
@@ -375,7 +369,6 @@ export default {
labels: this.label ? [this.label] : undefined,
teamId: this.teamId || undefined,
conversationType: this.conversationType || undefined,
- folders: this.hasActiveFolders ? this.savedFoldersValue : undefined,
};
},
conversationListPagination() {
@@ -488,7 +481,13 @@ export default {
this.resetAndFetchData();
this.updateVirtualListProps('conversationType', this.conversationType);
},
- activeFolder() {
+ activeFolder(newVal, oldVal) {
+ if (newVal !== oldVal) {
+ this.$store.dispatch(
+ 'customViews/setActiveConversationFolder',
+ newVal || null
+ );
+ }
this.resetAndFetchData();
this.updateVirtualListProps('foldersId', this.foldersId);
},
@@ -498,8 +497,14 @@ export default {
showAssigneeInConversationCard(newVal) {
this.updateVirtualListProps('showAssignee', newVal);
},
+ conversationFilters(newVal, oldVal) {
+ if (newVal !== oldVal) {
+ this.$store.dispatch('updateChatListFilters', newVal);
+ }
+ },
},
mounted() {
+ this.$store.dispatch('setChatListFilters', this.conversationFilters);
this.setFiltersFromUISettings();
this.$store.dispatch('setChatStatusFilter', this.activeStatus);
this.$store.dispatch('setChatSortFilter', this.activeSortBy);
@@ -509,14 +514,14 @@ export default {
this.$store.dispatch('campaigns/get');
}
- bus.$on('fetch_conversation_stats', () => {
+ this.$emitter.on('fetch_conversation_stats', () => {
this.$store.dispatch('conversationStats/get', this.conversationFilters);
});
- bus.$on(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
+ this.$emitter.on(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
},
beforeDestroy() {
- bus.$off(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
+ this.$emitter.off(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
},
methods: {
updateVirtualListProps(key, value) {
@@ -695,8 +700,9 @@ export default {
this.fetchConversations();
},
fetchConversations() {
+ this.$store.dispatch('updateChatListFilters', this.conversationFilters);
this.$store
- .dispatch('fetchAllConversations', this.conversationFilters)
+ .dispatch('fetchAllConversations')
.then(this.emitConversationLoaded);
},
loadMoreConversations() {
@@ -736,7 +742,7 @@ export default {
updateAssigneeTab(selectedTab) {
if (this.activeAssigneeTab !== selectedTab) {
this.resetBulkActions();
- bus.$emit('clearSearchInput');
+ this.$emitter.emit('clearSearchInput');
this.activeAssigneeTab = selectedTab;
if (!this.currentPage) {
this.fetchConversations();
diff --git a/app/javascript/dashboard/components/Code.vue b/app/javascript/dashboard/components/Code.vue
index 269311c2d..d8f609e29 100644
--- a/app/javascript/dashboard/components/Code.vue
+++ b/app/javascript/dashboard/components/Code.vue
@@ -25,8 +25,10 @@
{
/>
+
+defineProps({
+ message: {
+ type: String,
+ default: '',
+ },
+});
+
+
+
+ {{ message }}
+
+
diff --git a/app/javascript/dashboard/components/widgets/AIAssistanceButton.vue b/app/javascript/dashboard/components/widgets/AIAssistanceButton.vue
index a64743547..34f95a330 100644
--- a/app/javascript/dashboard/components/widgets/AIAssistanceButton.vue
+++ b/app/javascript/dashboard/components/widgets/AIAssistanceButton.vue
@@ -81,7 +81,7 @@ export default {
},
mounted() {
- bus.$on(CMD_AI_ASSIST, this.onAIAssist);
+ this.$emitter.on(CMD_AI_ASSIST, this.onAIAssist);
this.initialMessage = this.draftMessage;
},
diff --git a/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue b/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue
index 61ee2c2de..52b73c405 100644
--- a/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue
+++ b/app/javascript/dashboard/components/widgets/WootWriter/Editor.vue
@@ -352,10 +352,16 @@ export default {
// Components using this
// 1. SearchPopover.vue
- bus.$on(BUS_EVENTS.INSERT_INTO_RICH_EDITOR, this.insertContentIntoEditor);
+ this.$emitter.on(
+ BUS_EVENTS.INSERT_INTO_RICH_EDITOR,
+ this.insertContentIntoEditor
+ );
},
beforeDestroy() {
- bus.$off(BUS_EVENTS.INSERT_INTO_RICH_EDITOR, this.insertContentIntoEditor);
+ this.$emitter.off(
+ BUS_EVENTS.INSERT_INTO_RICH_EDITOR,
+ this.insertContentIntoEditor
+ );
},
methods: {
reloadState(content = this.value) {
diff --git a/app/javascript/dashboard/components/widgets/conversation/Message.vue b/app/javascript/dashboard/components/widgets/conversation/Message.vue
index 20222a31e..c6822d27d 100644
--- a/app/javascript/dashboard/components/widgets/conversation/Message.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/Message.vue
@@ -473,11 +473,11 @@ export default {
},
mounted() {
this.hasMediaLoadError = false;
- bus.$on(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
+ this.$emitter.on(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
this.setupHighlightTimer();
},
beforeDestroy() {
- bus.$off(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
+ this.$emitter.off(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
clearTimeout(this.higlightTimeout);
},
methods: {
@@ -531,7 +531,7 @@ export default {
const { conversation_id: conversationId, id: replyTo } = this.data;
LocalStorage.updateJsonStore(replyStorageKey, conversationId, replyTo);
- bus.$emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.data);
+ this.$emitter.emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.data);
},
setupHighlightTimer() {
if (Number(this.$route.query.messageId) !== Number(this.data.id)) {
diff --git a/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue b/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue
index 17d875f56..df61e9de1 100644
--- a/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue
@@ -324,12 +324,12 @@ export default {
},
created() {
- bus.$on(BUS_EVENTS.SCROLL_TO_MESSAGE, this.onScrollToMessage);
+ this.$emitter.on(BUS_EVENTS.SCROLL_TO_MESSAGE, this.onScrollToMessage);
// when a new message comes in, we refetch the label suggestions
- bus.$on(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS, this.fetchSuggestions);
+ this.$emitter.on(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS, this.fetchSuggestions);
// when a message is sent we set the flag to true this hides the label suggestions,
// until the chat is changed and the flag is reset in the watch for currentChat
- bus.$on(BUS_EVENTS.MESSAGE_SENT, () => {
+ this.$emitter.on(BUS_EVENTS.MESSAGE_SENT, () => {
this.messageSentSinceOpened = true;
});
},
@@ -396,7 +396,7 @@ export default {
this.$store.dispatch('fetchAllAttachments', this.currentChat.id);
},
removeBusListeners() {
- bus.$off(BUS_EVENTS.SCROLL_TO_MESSAGE, this.onScrollToMessage);
+ this.$emitter.off(BUS_EVENTS.SCROLL_TO_MESSAGE, this.onScrollToMessage);
},
onScrollToMessage({ messageId = '' } = {}) {
this.$nextTick(() => {
@@ -514,7 +514,7 @@ export default {
} else {
this.hasUserScrolled = true;
}
- bus.$emit(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL);
+ this.$emitter.emit(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL);
this.fetchPreviousMessages(e.target.scrollTop);
},
diff --git a/app/javascript/dashboard/components/widgets/conversation/MoreActions.vue b/app/javascript/dashboard/components/widgets/conversation/MoreActions.vue
index 78435144d..4a742781d 100644
--- a/app/javascript/dashboard/components/widgets/conversation/MoreActions.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/MoreActions.vue
@@ -61,14 +61,14 @@ export default {
...mapGetters({ currentChat: 'getSelectedChat' }),
},
mounted() {
- bus.$on(CMD_MUTE_CONVERSATION, this.mute);
- bus.$on(CMD_UNMUTE_CONVERSATION, this.unmute);
- bus.$on(CMD_SEND_TRANSCRIPT, this.toggleEmailActionsModal);
+ this.$emitter.on(CMD_MUTE_CONVERSATION, this.mute);
+ this.$emitter.on(CMD_UNMUTE_CONVERSATION, this.unmute);
+ this.$emitter.on(CMD_SEND_TRANSCRIPT, this.toggleEmailActionsModal);
},
destroyed() {
- bus.$off(CMD_MUTE_CONVERSATION, this.mute);
- bus.$off(CMD_UNMUTE_CONVERSATION, this.unmute);
- bus.$off(CMD_SEND_TRANSCRIPT, this.toggleEmailActionsModal);
+ this.$emitter.off(CMD_MUTE_CONVERSATION, this.mute);
+ this.$emitter.off(CMD_UNMUTE_CONVERSATION, this.unmute);
+ this.$emitter.off(CMD_SEND_TRANSCRIPT, this.toggleEmailActionsModal);
},
methods: {
mute() {
diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue
index 42fa74ec7..d6f393bfc 100644
--- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue
@@ -596,12 +596,15 @@ export default {
);
this.fetchAndSetReplyTo();
- bus.$on(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.fetchAndSetReplyTo);
+ this.$emitter.on(
+ BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE,
+ this.fetchAndSetReplyTo
+ );
// A hacky fix to solve the drag and drop
// Is showing on top of new conversation modal drag and drop
// TODO need to find a better solution
- bus.$on(
+ this.$emitter.on(
BUS_EVENTS.NEW_CONVERSATION_MODAL,
this.onNewConversationModalActive
);
@@ -609,10 +612,13 @@ export default {
destroyed() {
document.removeEventListener('paste', this.onPaste);
document.removeEventListener('keydown', this.handleKeyEvents);
- bus.$off(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.fetchAndSetReplyTo);
+ this.$emitter.off(
+ BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE,
+ this.fetchAndSetReplyTo
+ );
},
beforeDestroy() {
- bus.$off(
+ this.$emitter.off(
BUS_EVENTS.NEW_CONVERSATION_MODAL,
this.onNewConversationModalActive
);
@@ -625,7 +631,7 @@ export default {
const lines = title.split('\n');
const nonEmptyLines = lines.filter(line => line.trim() !== '');
const filteredMarkdown = nonEmptyLines.join(' ');
- bus.$emit(
+ this.$emitter.emit(
BUS_EVENTS.INSERT_INTO_RICH_EDITOR,
`[${filteredMarkdown}](${url})`
);
@@ -867,8 +873,8 @@ export default {
'createPendingMessageAndSend',
messagePayload
);
- bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
- bus.$emit(BUS_EVENTS.MESSAGE_SENT);
+ this.$emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
+ this.$emitter.emit(BUS_EVENTS.MESSAGE_SENT);
this.removeFromDraft();
this.sendMessageAnalyticsData(messagePayload.private);
} catch (error) {
@@ -1194,7 +1200,7 @@ export default {
resetReplyToMessage() {
const replyStorageKey = LOCAL_STORAGE_KEYS.MESSAGE_REPLY_TO;
LocalStorage.deleteFromJsonStore(replyStorageKey, this.conversationId);
- bus.$emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE);
+ this.$emitter.emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE);
},
onNewConversationModalActive(isActive) {
// Issue is if the new conversation modal is open and we drag and drop the file
diff --git a/app/javascript/dashboard/components/widgets/conversation/bubble/ReplyTo.vue b/app/javascript/dashboard/components/widgets/conversation/bubble/ReplyTo.vue
index fda2a9faa..5cb063d23 100644
--- a/app/javascript/dashboard/components/widgets/conversation/bubble/ReplyTo.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/bubble/ReplyTo.vue
@@ -47,7 +47,9 @@ export default {
},
methods: {
scrollToMessage() {
- bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE, { messageId: this.message.id });
+ this.$emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE, {
+ messageId: this.message.id,
+ });
},
},
};
diff --git a/app/javascript/dashboard/components/widgets/conversation/components/SLAPopoverCard.vue b/app/javascript/dashboard/components/widgets/conversation/components/SLAPopoverCard.vue
index 479e2794f..655a42948 100644
--- a/app/javascript/dashboard/components/widgets/conversation/components/SLAPopoverCard.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/components/SLAPopoverCard.vue
@@ -39,7 +39,7 @@ const toggleShowAllNRT = () => {
{{ $t('SLA.EVENTS.TITLE') }}
diff --git a/app/javascript/dashboard/components/widgets/conversation/conversationBulkActions/Index.vue b/app/javascript/dashboard/components/widgets/conversation/conversationBulkActions/Index.vue
index 3b398b8c3..198774dad 100644
--- a/app/javascript/dashboard/components/widgets/conversation/conversationBulkActions/Index.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/conversationBulkActions/Index.vue
@@ -167,17 +167,29 @@ export default {
};
},
mounted() {
- bus.$on(CMD_BULK_ACTION_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
- bus.$on(CMD_BULK_ACTION_REOPEN_CONVERSATION, this.onCmdReopenConversation);
- bus.$on(
+ this.$emitter.on(
+ CMD_BULK_ACTION_SNOOZE_CONVERSATION,
+ this.onCmdSnoozeConversation
+ );
+ this.$emitter.on(
+ CMD_BULK_ACTION_REOPEN_CONVERSATION,
+ this.onCmdReopenConversation
+ );
+ this.$emitter.on(
CMD_BULK_ACTION_RESOLVE_CONVERSATION,
this.onCmdResolveConversation
);
},
destroyed() {
- bus.$off(CMD_BULK_ACTION_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
- bus.$off(CMD_BULK_ACTION_REOPEN_CONVERSATION, this.onCmdReopenConversation);
- bus.$off(
+ this.$emitter.off(
+ CMD_BULK_ACTION_SNOOZE_CONVERSATION,
+ this.onCmdSnoozeConversation
+ );
+ this.$emitter.off(
+ CMD_BULK_ACTION_REOPEN_CONVERSATION,
+ this.onCmdReopenConversation
+ );
+ this.$emitter.off(
CMD_BULK_ACTION_RESOLVE_CONVERSATION,
this.onCmdResolveConversation
);
diff --git a/app/javascript/dashboard/components/widgets/conversation/linear/CreateIssue.vue b/app/javascript/dashboard/components/widgets/conversation/linear/CreateIssue.vue
index 5c3575c44..a00969416 100644
--- a/app/javascript/dashboard/components/widgets/conversation/linear/CreateIssue.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/linear/CreateIssue.vue
@@ -107,6 +107,7 @@ import { useI18n } from 'dashboard/composables/useI18n';
import { useAlert } from 'dashboard/composables';
import LinearAPI from 'dashboard/api/integrations/linear';
import validations from './validations';
+import { parseLinearAPIErrorResponse } from 'dashboard/store/utils/api';
const props = defineProps({
accountId: {
@@ -140,6 +141,14 @@ const priorities = [
{ id: 4, name: 'Low' },
];
+const statusDesiredOrder = [
+ 'Backlog',
+ 'Todo',
+ 'In Progress',
+ 'Done',
+ 'Canceled',
+];
+
const isCreating = ref(false);
const inputStyles = { borderRadius: '12px', fontSize: '14px' };
@@ -177,7 +186,11 @@ const getTeams = async () => {
const response = await LinearAPI.getTeams();
teams.value = response.data;
} catch (error) {
- useAlert(t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.LOADING_TEAM_ERROR'));
+ const errorMessage = parseLinearAPIErrorResponse(
+ error,
+ t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.LOADING_TEAM_ERROR')
+ );
+ useAlert(errorMessage);
}
};
@@ -186,12 +199,16 @@ const getTeamEntities = async () => {
const response = await LinearAPI.getTeamEntities(formState.teamId);
assignees.value = response.data.users;
labels.value = response.data.labels;
- statuses.value = response.data.states;
projects.value = response.data.projects;
+ statuses.value = statusDesiredOrder
+ .map(name => response.data.states.find(status => status.name === name))
+ .filter(Boolean);
} catch (error) {
- useAlert(
+ const errorMessage = parseLinearAPIErrorResponse(
+ error,
t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.LOADING_TEAM_ENTITIES_ERROR')
);
+ useAlert(errorMessage);
}
};
@@ -226,7 +243,11 @@ const createIssue = async () => {
useAlert(t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.CREATE_SUCCESS'));
onClose();
} catch (error) {
- useAlert(t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.CREATE_ERROR'));
+ const errorMessage = parseLinearAPIErrorResponse(
+ error,
+ t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.CREATE_ERROR')
+ );
+ useAlert(errorMessage);
} finally {
isCreating.value = false;
}
diff --git a/app/javascript/dashboard/components/widgets/conversation/linear/Issue.vue b/app/javascript/dashboard/components/widgets/conversation/linear/Issue.vue
index 05cd3ab88..3304f6040 100644
--- a/app/javascript/dashboard/components/widgets/conversation/linear/Issue.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/linear/Issue.vue
@@ -56,7 +56,7 @@ const unlinkIssue = () => {