nextcloud-contacts/src/components/AppNavigation/Settings/SettingsAddressbook.vue

315 lines
7.9 KiB
Vue

<!--
- @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
-
- @author John Molakvoæ <skjnldsv@protonmail.com>
- @author Team Popcorn <teampopcornberlin@gmail.com>
-
- @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>
<div class="settings-addressbook-list">
<div class="icon-group settings-line__icon" />
<li :class="{'addressbook--disabled': !addressbook.enabled}" class="addressbook">
<!-- addressbook name -->
<span class="addressbook__name" :title="addressbook.displayName">
{{ addressbook.displayName }}
</span>
<!-- sharing button -->
<a v-if="!addressbook.readOnly"
v-tooltip.top="sharedWithTooltip"
:class="{'addressbook__share--shared': hasShares}"
:title="sharedWithTooltip"
href="#"
class="addressbook__share icon-shared"
@click="toggleShare" />
<!-- popovermenu -->
<Actions class="addressbook__menu" menu-align="right">
<!-- copy addressbook link -->
<ActionLink
:href="addressbook.url"
:icon="copyLinkIcon"
@click.stop.prevent="copyToClipboard(addressbookUrl)">
{{ copyButtonText }}
</ActionLink>
<!-- download addressbook -->
<ActionLink
:href="addressbook.url + '?export'"
icon="icon-download">
{{ t('contacts', 'Download') }}
</ActionLink>
<template v-if="!addressbook.readOnly">
<!-- rename addressbook -->
<ActionButton v-if="!editingName"
icon="icon-rename"
@click.stop.prevent="renameAddressbook">
{{ t('contacts', 'Rename') }}
</ActionButton>
<ActionInput v-else
ref="renameInput"
:disabled="renameLoading"
:icon="renameLoading ? 'icon-loading-small' : 'icon-rename'"
:value="addressbook.displayName"
@submit="updateAddressbookName" />
<!-- enable/disable addressbook -->
<ActionCheckbox v-if="!toggleEnabledLoading"
:checked="enabled"
@change.stop.prevent="toggleAddressbookEnabled">
{{ t('contacts', 'Enabled') }}
</ActionCheckbox>
<ActionButton v-else
icon="icon-loading-small">
{{ t('contacts', 'Enabled') }}
</ActionButton>
</template>
<!-- delete addressbook -->
<ActionButton v-if="hasMultipleAddressbooks"
:icon="deleteAddressbookLoading ? 'icon-loading-small' : 'icon-delete'"
@click="confirmDeletion">
{{ t('contacts', 'Delete') }}
</ActionButton>
</Actions>
<!-- sharing input -->
<ShareAddressBook v-if="shareOpen && !addressbook.readOnly" :addressbook="addressbook" />
</li>
</div>
</template>
<script>
import Actions from '@nextcloud/vue/dist/Components/Actions'
import ActionLink from '@nextcloud/vue/dist/Components/ActionLink'
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
import ActionInput from '@nextcloud/vue/dist/Components/ActionInput'
import ActionCheckbox from '@nextcloud/vue/dist/Components/ActionCheckbox'
import ShareAddressBook from './SettingsAddressbookShare'
import { showError } from '@nextcloud/dialogs'
import CopyToClipboardMixin from '../../../mixins/CopyToClipboardMixin'
export default {
name: 'SettingsAddressbook',
components: {
ActionButton,
ActionCheckbox,
ActionInput,
ActionLink,
Actions,
ShareAddressBook,
},
mixins: [CopyToClipboardMixin],
props: {
addressbook: {
type: Object,
default() {
return {}
},
},
},
data() {
return {
deleteAddressbookLoading: false,
editingName: false,
menuOpen: false,
renameLoading: false,
shareOpen: false,
toggleEnabledLoading: false,
}
},
computed: {
enabled() {
return this.addressbook.enabled
},
hasShares() {
return this.addressbook.shares.length > 0
},
addressbooks() {
return this.$store.getters.getAddressbooks
},
hasMultipleAddressbooks() {
return this.addressbooks.length > 1
},
// info tooltip about number of shares
sharedWithTooltip() {
return this.hasShares
? n('contacts',
'Shared with {num} entity',
'Shared with {num} entities',
this.addressbook.shares.length, {
num: this.addressbook.shares.length,
})
: '' // disable the tooltip
},
copyButtonText() {
if (this.copied) {
return this.copySuccess
? t('contacts', 'Copied')
: t('contacts', 'Cannot copy')
}
return t('contacts', 'Copy link')
},
addressbookUrl() {
return window.location.origin + this.addressbook.url
},
},
watch: {
menuOpen() {
if (this.menuOpen === false) {
this.editingName = false
}
},
},
mounted() {
// required if popup needs to stay opened after menu click
this.popupItem = this.$el
},
methods: {
closeMenu() {
this.menuOpen = false
},
toggleMenu() {
this.menuOpen = !this.menuOpen
},
toggleShare() {
this.shareOpen = !this.shareOpen
},
async toggleAddressbookEnabled() {
// change to loading status
this.toggleEnabledLoading = true
try {
await this.$store.dispatch('toggleAddressbookEnabled', this.addressbook)
} catch (err) {
// error handling
console.error(err)
showError(t('contacts', 'Toggling of address book was not successful'))
} finally {
// stop loading status regardless of outcome
this.toggleEnabledLoading = false
}
},
confirmDeletion() {
OC.dialogs.confirm(
t('contacts', 'This will delete the address book and every contacts within it'),
t('contacts', 'Delete {addressbook}?', { addressbook: this.addressbook.displayName }),
this.deleteAddressbook,
true
)
},
async deleteAddressbook(confirm) {
if (confirm) {
// change to loading status
this.deleteAddressbookLoading = true
try {
await this.$store.dispatch('deleteAddressbook', this.addressbook)
} catch (err) {
// error handling
console.error(err)
showError(t('contacts', 'Deletion of address book was not successful.'))
} finally {
// stop loading status regardless of outcome
this.deleteAddressbookLoading = false
}
}
},
renameAddressbook() {
this.editingName = true
},
async updateAddressbookName(e) {
const addressbook = this.addressbook
// New name for addressbook - inputed value from form
const newName = this.$refs.renameInput.$el.querySelector('input[type="text"]').value
// change to loading status
this.renameLoading = true
try {
await this.$store.dispatch('renameAddressbook', { addressbook, newName })
} catch (err) {
// error handling
console.error(err)
showError(t('contacts', 'Renaming of address book was not successful.'))
} finally {
this.editingName = false
// stop loading status regardless of outcome
this.renameLoading = false
// close popover menu
this.menuOpen = false
}
},
},
}
</script>
<style lang="scss" scoped>
.addressbook {
display: flex;
flex-wrap: wrap;
align-items: center;
white-space: nowrap;
text-overflow: ellipsis;
> .addressbook__name {
+ a,
+ div {
// put actions at the end
margin-left: auto;
}
}
&__name {
display: block;
flex: 0 1 auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: calc(100% - 2 * 44px);
}
&__share,
&__menu .icon-more {
width: 44px;
height: 44px;
opacity: .5;
&:hover,
&:focus,
&:active {
opacity: .7;
}
}
&__share {
&--shared {
opacity: .7;
}
}
&--disabled &__name {
opacity: .5;
}
}
</style>