Skip to content
Snippets Groups Projects
NavigationMailbox.vue 8.89 KiB
Newer Older
  • Learn to ignore specific revisions
  • <!--
      - @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
      -
      - @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
      -
      - @license GNU AGPL version 3 or any later version
      -
      - This program is free software: you can redistribute it and/or modify
      - it under the terms of the GNU Affero General Public License as
      - published by the Free Software Foundation, either version 3 of the
      - License, or (at your option) any later version.
      -
      - This program is distributed in the hope that it will be useful,
      - but WITHOUT ANY WARRANTY; without even the implied warranty of
      - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      - GNU Affero General Public License for more details.
      -
      - You should have received a copy of the GNU Affero General Public License
      - along with this program.  If not, see <http://www.gnu.org/licenses/>.
      -->
    
    <template>
    
    	<AppNavigationItem
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		:id="genId(mailbox)"
    		:key="genId(mailbox)"
    
    		:allow-collapse="true"
    
    GretaD's avatar
    GretaD committed
    		:menu-open.sync="menuOpen"
    
    		:force-menu="true"
    
    		:icon="icon"
    		:title="title"
    		:to="to"
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		:open.sync="showSubMailboxes"
    
    		@update:menuOpen="onMenuToggle">
    
    		<!-- actions -->
    		<template slot="actions">
    
    			<template>
    
    GretaD's avatar
    GretaD committed
    				<ActionText
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					v-if="!account.isUnified && mailbox.specialRole !== 'flagged'"
    
    GretaD's avatar
    GretaD committed
    					icon="icon-info"
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					:title="mailbox.name">
    
    					{{ statsText }}
    				</ActionText>
    
    
    GretaD's avatar
    GretaD committed
    					v-if="mailbox.specialRole !== 'flagged' && !account.isUnified"
    
    GretaD's avatar
    GretaD committed
    					icon="icon-mail"
    
    					:title="t('mail', 'Mark all as read')"
    					:disabled="loadingMarkAsRead"
    
    					@click="markAsRead">
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					{{ t('mail', 'Mark all messages of this mailbox as read') }}
    
    GretaD's avatar
    GretaD committed
    				<ActionButton
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					v-if="!editing && top && !account.isUnified && mailbox.specialRole !== 'flagged'"
    
    GretaD's avatar
    GretaD committed
    					icon="icon-folder"
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					@click="openCreateMailbox">
    
    					{{ t('mail', 'Add subfolder') }}
    
    GretaD's avatar
    GretaD committed
    				</ActionButton>
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				<ActionInput v-if="editing" icon="icon-folder" @submit.prevent.stop="createMailbox" />
    
    GretaD's avatar
    GretaD committed
    				<ActionText v-if="showSaving" icon="icon-loading-small">
    					{{ t('mail', 'Saving') }}
    				</ActionText>
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					v-if="debug && !account.isUnified && mailbox.specialRole !== 'flagged'"
    
    					icon="icon-settings"
    					:title="t('mail', 'Clear cache')"
    					:disabled="clearingCache"
    
    					@click="clearCache">
    
    					{{ t('mail', 'Clear locally cached data, in case there are issues with synchronization.') }}
    				</ActionButton>
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				<ActionButton v-if="!account.isUnified && !mailbox.specialRole" icon="icon-delete" @click="deleteMailbox">
    
    GretaD's avatar
    GretaD committed
    					{{ t('mail', 'Delete folder') }}
    				</ActionButton>
    
    			</template>
    		</template>
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		<AppNavigationCounter v-if="mailbox.unread" slot="counter">
    			{{ mailbox.unread }}
    
    		</AppNavigationCounter>
    
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		<!-- submailboxes -->
    		<NavigationMailbox
    			v-for="subMailbox in subMailboxes"
    			:key="genId(subMailbox)"
    
    			:account="account"
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    			:mailbox="subMailbox"
    
    	</AppNavigationItem>
    
    import AppNavigationItem from '@nextcloud/vue/dist/Components/AppNavigationItem'
    import AppNavigationCounter from '@nextcloud/vue/dist/Components/AppNavigationCounter'
    import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
    import ActionInput from '@nextcloud/vue/dist/Components/ActionInput'
    
    import ActionText from '@nextcloud/vue/dist/Components/ActionText'
    
    import { clearCache } from '../service/MessageService'
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    import { getMailboxStatus } from '../service/MailboxService'
    
    import logger from '../logger'
    
    import { translatePlural as n } from '@nextcloud/l10n'
    import { translate as translateMailboxName } from '../i18n/MailboxTranslator'
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    	name: 'NavigationMailbox',
    
    	components: {
    		AppNavigationItem,
    
    		AppNavigationCounter,
    
    		ActionButton,
    		ActionInput,
    
    	},
    	props: {
    		account: {
    			type: Object,
    			required: true,
    		},
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		mailbox: {
    
    		top: {
    			type: Boolean,
    			default: true,
    		},
    
    		filter: {
    			type: String,
    			default: '',
    			required: false,
    		},
    
    			debug: window?.OC?.debug || false,
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    			mailboxStats: undefined,
    
    			loadingMarkAsRead: false,
    
    GretaD's avatar
    GretaD committed
    			showSaving: false,
    			editing: false,
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    			showSubMailboxes: false,
    
    GretaD's avatar
    GretaD committed
    			menuOpen: false,
    
    				this.account.showSubscribedOnly === false
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				|| (this.mailbox.attributes && this.mailbox.attributes.includes('\\subscribed'))
    
    			if (this.filter === 'starred') {
    				// Little hack to trick the translation logic into a different path
    				return translateMailboxName({
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					...this.mailbox,
    
    					specialUse: ['flagged'],
    				})
    			}
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    			return translateMailboxName(this.mailbox)
    
    			if (this.filter === 'starred') {
    				return 'icon-flagged'
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    			} else if (this.mailbox.isPriorityInbox) {
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    			return this.mailbox.specialRole ? 'icon-' + this.mailbox.specialRole : 'icon-folder'
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				name: 'mailbox',
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					mailboxId: this.mailbox.databaseId,
    
    					filter: this.filter ? this.filter : undefined,
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		subMailboxes() {
    			return this.$store.getters.getSubMailboxes(this.mailbox.databaseId)
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    			if (this.mailboxStats && 'total' in this.mailboxStats && 'unread' in this.mailboxStats) {
    				if (this.mailboxStats.unread === 0) {
    					return n('mail', '{total} message', '{total} messages', this.mailboxStats.total, {
    						total: this.mailboxStats.total,
    
    GretaD's avatar
    GretaD committed
    					return n(
    						'mail',
    						'{unread} unread of {total}',
    						'{unread} unread of {total}',
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    						this.mailboxStats.unread,
    
    GretaD's avatar
    GretaD committed
    						{
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    							total: this.mailboxStats.total,
    							unread: this.mailboxStats.unread,
    
    GretaD's avatar
    GretaD committed
    						}
    					)
    
    			return t('mail', 'Loading …')
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		 * Generate unique key id for a specific mailbox
    		 * @param {Object} mailbox the mailbox to gen id for
    
    		 * @returns {string}
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		genId(mailbox) {
    			return 'mailbox-' + mailbox.databaseId
    
    		/**
    		 * On menu toggle, fetch stats
    		 * @param {boolean} open menu opened state
    		 */
    		onMenuToggle(open) {
    			if (open) {
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				this.fetchMailboxStats()
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		 * Fetch mailbox unread/read stats
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		async fetchMailboxStats() {
    			this.mailboxStats = null
    			if (this.account.isUnified || this.mailbox.specialRole === 'flagged') {
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				const stats = await getMailboxStatus(this.mailbox.databaseId)
    				logger.debug(`loaded mailbox stats for ${this.mailbox.databaseId}`, { stats })
    				this.mailboxStats = stats
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				this.mailboxStats = { error: true }
    				logger.error(`could not load mailbox stats for ${this.mailbox.databaseId}`, error)
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		async createMailbox(e) {
    
    GretaD's avatar
    GretaD committed
    			this.editing = true
    
    			const name = e.target.elements[1].value
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    			const withPrefix = atob(this.mailbox.databaseId) + this.mailbox.delimiter + name
    			logger.info(`creating mailbox ${withPrefix} as submailbox of ${this.mailbox.databaseId}`)
    
    GretaD's avatar
    GretaD committed
    			try {
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				await this.$store.dispatch('createMailbox', {
    
    					account: this.account,
    					name: withPrefix,
    				})
    
    GretaD's avatar
    GretaD committed
    			} catch (error) {
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				logger.error(`could not create mailbox ${withPrefix}`, { error })
    
    GretaD's avatar
    GretaD committed
    				throw error
    			} finally {
    				this.editing = false
    				this.showSaving = false
    			}
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    			logger.info(`mailbox ${withPrefix} created`)
    			this.showSubMailboxes = true
    
    GretaD's avatar
    GretaD committed
    		},
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		openCreateMailbox() {
    
    GretaD's avatar
    GretaD committed
    			this.editing = true
    			this.showSaving = false
    
    			this.loadingMarkAsRead = true
    
    			this.$store
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				.dispatch('markMailboxRead', {
    
    					accountId: this.account.id,
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					mailboxId: this.mailbox.databaseId,
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				.then(() => logger.info(`mailbox ${this.mailbox.databaseId} marked as read`))
    				.catch((error) => logger.error(`could not mark mailbox ${this.mailbox.databaseId} as read`, { error }))
    
    				.then(() => (this.loadingMarkAsRead = false))
    
    		async clearCache() {
    			try {
    				this.clearingCache = true
    				logger.debug('clearing message cache', {
    					accountId: this.account.id,
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					mailboxId: this.mailbox.databaseId,
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				await clearCache(this.account.id, this.mailbox.databaseId)
    
    
    				// TODO: there might be a nicer way to handle this
    				window.location.reload(false)
    			} finally {
    				this.clearCache = false
    			}
    		},
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    		deleteMailbox() {
    			const id = this.mailbox.databaseId
    			logger.info('delete mailbox', { mailbox: this.mailbox })
    
    GretaD's avatar
    GretaD committed
    			OC.dialogs.confirmDestructive(
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    				t('mail', 'The folder and all messages in it will be deleted.'),
    
    GretaD's avatar
    GretaD committed
    				t('mail', 'Delete folder'),
    				{
    					type: OC.dialogs.YES_NO_BUTTONS,
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    					confirm: t('mail', 'Delete folder {name}', { name: this.mailbox.displayName }),
    
    GretaD's avatar
    GretaD committed
    					confirmClasses: 'error',
    					cancel: t('mail', 'Cancel'),
    				},
    				(result) => {
    					if (result) {
    						return this.$store
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    							.dispatch('deleteMailbox', { mailbox: this.mailbox })
    
    GretaD's avatar
    GretaD committed
    							.then(() => {
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    								logger.info(`mailbox ${id} deleted`)
    
    GretaD's avatar
    GretaD committed
    							})
    
    Christoph Wurst's avatar
    Christoph Wurst committed
    							.catch((error) => logger.error('could not delete mailbox', { error }))