From 6eddc39f718412f0dfdec9f24856411641c9bb79 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Fri, 8 Apr 2022 13:52:44 +0200 Subject: Unify composer logic and use modal/outbox everywhere * Convert replies to modals/outbox * Convert forward to modals/outbox * Convert draft resumes to modals/outbox Signed-off-by: Christoph Wurst --- src/components/Composer.vue | 6 +- src/components/Envelope.vue | 28 ++-- src/components/Mailbox.vue | 10 +- src/components/MailboxThread.vue | 12 +- src/components/MenuEnvelope.vue | 75 ++++------ src/components/NewMessageDetail.vue | 285 ------------------------------------ src/components/NewMessageModal.vue | 12 +- src/components/ThreadEnvelope.vue | 42 ++---- src/store/actions.js | 73 ++++++++- src/views/Home.vue | 14 +- 10 files changed, 141 insertions(+), 416 deletions(-) delete mode 100644 src/components/NewMessageDetail.vue (limited to 'src') diff --git a/src/components/Composer.vue b/src/components/Composer.vue index e4d7fd93a..1472b84d9 100644 --- a/src/components/Composer.vue +++ b/src/components/Composer.vue @@ -349,6 +349,10 @@ export default { type: Object, default: () => html(''), }, + draftId: { + type: Number, + default: undefined, + }, draft: { type: Function, required: true, @@ -389,7 +393,7 @@ export default { bodyVal, attachments: [], noReply: this.to.some((to) => to.email.startsWith('noreply@') || to.email.startsWith('no-reply@')), - draftsPromise: Promise.resolve(), + draftsPromise: Promise.resolve(this.draftId), attachmentsPromise: Promise.resolve(), canSaveDraft: true, savingDraft: undefined, diff --git a/src/components/Envelope.vue b/src/components/Envelope.vue index 95fdff205..bd661da57 100644 --- a/src/components/Envelope.vue +++ b/src/components/Envelope.vue @@ -12,7 +12,8 @@ :to="link" :data-envelope-id="data.databaseId" :title="addresses" - :details="formatted()"> + :details="formatted()" + @click="onClick"> - - + @@ -76,7 +75,6 @@ import Vue from 'vue' import infiniteScroll from '../directives/infinite-scroll' import logger from '../logger' import Mailbox from './Mailbox' -import NewMessageDetail from './NewMessageDetail' import NoMessageSelected from './NoMessageSelected' import Thread from './Thread' import { UNIFIED_ACCOUNT_ID, UNIFIED_INBOX_ID } from '../store/constants' @@ -96,7 +94,6 @@ export default { AppContent, AppContentList, Mailbox, - NewMessageDetail, NoMessageSelected, Popover, SectionTitle, @@ -154,13 +151,6 @@ export default { } return this.searchQuery }, - newMessage() { - return ( - this.$route.params.threadId === 'new' - || this.$route.params.threadId === 'reply' - || this.$route.params.threadId === 'replyAll' - ) - }, isThreadShown() { return !!this.$route.params.threadId }, diff --git a/src/components/MenuEnvelope.vue b/src/components/MenuEnvelope.vue index 74a3cc7fc..c2ce9d76c 100644 --- a/src/components/MenuEnvelope.vue +++ b/src/components/MenuEnvelope.vue @@ -32,23 +32,23 @@ }} - + @click="onReply"> {{ t('mail', 'Reply') }} - - + + @click="onReply"> {{ t('mail', 'Reply to sender only') }} - - + + @click="onForward"> {{ t('mail', 'Forward') }} - + @@ -151,7 +151,6 @@ import axios from '@nextcloud/axios' import Actions from '@nextcloud/vue/dist/Components/Actions' import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' import ActionLink from '@nextcloud/vue/dist/Components/ActionLink' -import ActionRouter from '@nextcloud/vue/dist/Components/ActionRouter' import { Base64 } from 'js-base64' import ChevronLeft from 'vue-material-design-icons/ChevronLeft' import { buildRecipients as buildReplyRecipients } from '../ReplyBuilder' @@ -172,7 +171,6 @@ export default { Actions, ActionButton, ActionLink, - ActionRouter, ChevronLeft, EventModal, Modal, @@ -243,45 +241,6 @@ export default { }) return recipients.to.concat(recipients.cc).length > 1 }, - replyOneLink() { - return { - name: 'message', - params: { - mailboxId: this.$route.params.mailboxId, - threadId: 'reply', - filter: this.$route.params.filter ? this.$route.params.filter : undefined, - }, - query: { - messageId: this.envelope.databaseId, - }, - } - }, - replyAllLink() { - return { - name: 'message', - params: { - mailboxId: this.$route.params.mailboxId, - threadId: 'replyAll', - filter: this.$route.params.filter ? this.$route.params.filter : undefined, - }, - query: { - messageId: this.envelope.databaseId, - }, - } - }, - forwardLink() { - return { - name: 'message', - params: { - mailboxId: this.$route.params.mailboxId, - threadId: 'new', - filter: this.$route.params.filter ? this.$route.params.filter : undefined, - }, - query: { - messageId: this.envelope.databaseId, - }, - } - }, threadingFile() { return `data:text/plain;base64,${Base64.encode(JSON.stringify({ subject: this.envelope.subject, @@ -304,6 +263,14 @@ export default { }, }, methods: { + onForward() { + this.$store.dispatch('showMessageComposer', { + reply: { + mode: 'forward', + data: this.envelope, + }, + }) + }, onToggleFlagged() { this.$store.dispatch('toggleEnvelopeFlagged', this.envelope) }, @@ -380,6 +347,14 @@ export default { onOpenTagModal() { this.showTagModal = true }, + onReply() { + this.$store.dispatch('showMessageComposer', { + reply: { + mode: this.hasMultipleRecipients ? 'replyAll' : 'reply', + data: this.envelope, + }, + }) + }, onCloseTagModal() { this.showTagModal = false }, diff --git a/src/components/NewMessageDetail.vue b/src/components/NewMessageDetail.vue deleted file mode 100644 index b23e5d5ae..000000000 --- a/src/components/NewMessageDetail.vue +++ /dev/null @@ -1,285 +0,0 @@ - - - diff --git a/src/components/NewMessageModal.vue b/src/components/NewMessageModal.vue index 5b2280db2..7e0dc9a91 100644 --- a/src/components/NewMessageModal.vue +++ b/src/components/NewMessageModal.vue @@ -10,6 +10,8 @@ :bcc="composerData.bcc" :subject="composerData.subject" :body="composerData.body" + :reply-to="composerData.replyTo" + :draft-id="composerData.draftId" :draft="saveDraft" :send="sendMessage" :forwarded-messages="forwardedMessages" /> @@ -32,7 +34,6 @@ export default { data() { return { original: undefined, - originalBody: undefined, } }, computed: { @@ -40,6 +41,15 @@ export default { if (this.composerMessage.type === 'outbox') { return t('mail', 'Outbox draft') } + if (this.composerData.draftId !== undefined) { + return t('mail', 'Draft') + } + if (this.composerData.replyTo) { + return t('mail', 'Reply') + } + if (this.composerData.forwardFrom) { + return t('mail', 'Forward') + } return t('mail', 'New message') }, composerMessage() { diff --git a/src/components/ThreadEnvelope.vue b/src/components/ThreadEnvelope.vue index a1a7e6fda..0bd787b6b 100644 --- a/src/components/ThreadEnvelope.vue +++ b/src/components/ThreadEnvelope.vue @@ -70,16 +70,16 @@
- + class="button" + @click="onReply"> {{ t('mail', 'Reply') }} - + 1 }, - replyOneLink() { - return { - name: 'message', - params: { - mailboxId: this.$route.params.mailboxId, - threadId: 'reply', - filter: this.$route.params.filter ? this.$route.params.filter : undefined, - }, - query: { - messageId: this.envelope.databaseId, - }, - } - }, - replyAllLink() { - return { - name: 'message', - params: { - mailboxId: this.$route.params.mailboxId, - threadId: 'replyAll', - filter: this.$route.params.filter ? this.$route.params.filter : undefined, - }, - query: { - messageId: this.envelope.databaseId, - }, - } - }, route() { return { name: 'message', @@ -278,6 +252,14 @@ export default { const top = this.$el.getBoundingClientRect().top - globalHeader - threadHeader window.scrollTo({ top }) }, + onReply() { + this.$store.dispatch('showMessageComposer', { + reply: { + mode: this.hasMultipleRecipients ? 'replyAll' : 'reply', + data: this.envelope, + }, + }) + }, onToggleImportant() { this.$store.dispatch('toggleEnvelopeImportant', this.envelope) }, diff --git a/src/store/actions.js b/src/store/actions.js index 8c5180d1f..69e4960b0 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -87,6 +87,11 @@ import Axios from '@nextcloud/axios' import { generateUrl } from '@nextcloud/router' import { showWarning } from '@nextcloud/dialogs' import { translate as t } from '@nextcloud/l10n' +import { + buildForwardSubject, + buildRecipients as buildReplyRecipients, + buildReplySubject, +} from '../ReplyBuilder' const sliceToPage = slice(0, PAGE_SIZE) @@ -258,8 +263,72 @@ export default { updated, }) }, - async showMessageComposer({ commit, dispatch }, { type = 'imap', data = {}, forwardedMessages = [], templateMessageId }) { - if (templateMessageId) { + async showMessageComposer({ commit, dispatch, getters }, { type = 'imap', data = {}, reply, forwardedMessages = [], templateMessageId }) { + if (reply) { + const original = await dispatch('fetchMessage', reply.data.databaseId) + + // Fetch and transform the body into a rich text object + if (original.hasHtmlBody) { + const resp = await Axios.get( + generateUrl('/apps/mail/api/messages/{id}/html?plain=true', { + id: original.databaseId, + }) + ) + + data.body = html(resp.data) + } else { + data.body = plain(original.body) + } + + if (reply.mode === 'reply') { + logger.debug('Show simple reply composer', { reply }) + commit('showMessageComposer', { + data: { + accountId: reply.data.accountId, + to: reply.data.from, + cc: [], + subject: buildReplySubject(reply.data.subject), + body: data.body, + originalBody: data.body, + replyTo: reply.data, + }, + }) + return + } else if (reply.mode === 'replyAll') { + logger.debug('Show reply all reply composer', { reply }) + const account = getters.getAccount(reply.data.accountId) + const recipients = buildReplyRecipients(reply.data, { + email: account.emailAddress, + label: account.name, + }) + commit('showMessageComposer', { + data: { + accountId: reply.data.accountId, + to: recipients.to, + cc: recipients.cc, + subject: buildReplySubject(reply.data.subject), + body: data.body, + originalBody: data.body, + replyTo: reply.data, + }, + }) + return + } else if (reply.mode === 'forward') { + logger.debug('Show forward composer', { reply }) + commit('showMessageComposer', { + data: { + accountId: reply.data.accountId, + to: [], + cc: [], + subject: buildForwardSubject(reply.data.subject), + body: data.body, + originalBody: data.body, + forwardFrom: reply.data, + }, + }) + return + } + } else if (templateMessageId) { const message = await dispatch('fetchMessage', templateMessageId) // Merge the original into any existing data data = { diff --git a/src/views/Home.vue b/src/views/Home.vue index 4ac7375f9..33bd93940 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -1,7 +1,5 @@