nextcloud-contacts/src/components/EntityPicker/ContactsPicker.vue

188 lines
4.3 KiB
Vue

<template>
<!-- Bulk contacts edit modal -->
<Modal v-if="isProcessing || isProcessDone"
:clear-view-delay="-1"
:can-close="isProcessDone"
@close="closeProcess">
<AddToGroupView v-bind="processStatus" @close="closeProcess" />
</Modal>
<!-- contacts picker -->
<EntityPicker v-else-if="showPicker"
:confirm-label="t('contacts', 'Add to {group}', { group: pickerforGroup.name})"
:data-types="pickerTypes"
:data-set="pickerData"
@close="onContactPickerClose"
@submit="onContactPickerPick" />
</template>
<script>
import { subscribe } from '@nextcloud/event-bus'
import pLimit from 'p-limit'
import Modal from '@nextcloud/vue/dist/Components/Modal'
import AddToGroupView from '../../views/Processing/AddToGroupView'
import appendContactToGroup from '../../services/appendContactToGroup'
import EntityPicker from './EntityPicker'
export default {
name: 'ContactsPicker',
components: {
AddToGroupView,
EntityPicker,
Modal,
},
data() {
return {
// Entity picker
showPicker: false,
pickerforGroup: null,
pickerData: [],
pickerTypes: [{
id: 'contact',
label: t('contacts', 'Contacts'),
}],
// Bulk processing
isProcessing: false,
isProcessDone: false,
processStatus: {
failed: 0,
progress: 0,
success: 0,
total: 0,
name: '',
},
}
},
computed: {
contacts() {
return this.$store.getters.getContacts
},
groups() {
return this.$store.getters.getGroups
},
sortedContacts() {
return this.$store.getters.getSortedContacts
},
},
mounted() {
// Watch for a add-to-group event
subscribe('contacts:group:append', this.addContactsToGroup)
},
methods: {
// Bulk contacts group management handlers
addContactsToGroup(group) {
console.debug('Contacts picker opened for group', group)
// Get the full group if we provided the group name only
if (typeof group === 'string') {
group = this.groups.find(a => a.name === group)
if (!group) {
console.error('Cannot add contact to an undefined group', group)
return
}
}
// Init data set
this.pickerData = this.sortedContacts
.map(({ key }) => {
const contact = this.contacts[key]
return {
id: contact.key,
label: contact.displayName,
type: 'contact',
readOnly: contact.addressbook.readOnly,
groups: contact.groups,
}
})
// No read only contacts
.filter(contact => !contact.readOnly)
// No contacts already present in group
.filter(contact => contact.groups.indexOf(group.name) === -1)
this.showPicker = true
this.pickerforGroup = group
},
onContactPickerClose() {
this.pickerData = []
this.showPicker = false
},
onContactPickerPick(selection) {
console.debug('Adding', selection, 'to group', this.pickerforGroup)
const groupName = this.pickerforGroup.name
this.isProcessing = true
this.showPicker = false
this.processStatus.total = selection.length
this.processStatus.name = this.pickerforGroup.name
this.processStatus.progress = 0
this.processStatus.failed = 0
// max simultaneous requests
const limit = pLimit(3)
const requests = []
// create the array of requests to send
selection.map(async entity => {
try {
// Get contact
const contact = this.contacts[entity.id]
// push contact to server and use limit
requests.push(limit(() => appendContactToGroup(contact, groupName)
.then((response) => {
this.$store.dispatch('addContactToGroup', { contact, groupName })
this.processStatus.progress++
this.processStatus.success++
})
.catch((error) => {
this.processStatus.progress++
this.processStatus.error++
console.error(error)
})
))
} catch (e) {
console.error(e)
}
})
Promise.all(requests).then(() => {
this.isProcessDone = true
this.showPicker = false
// Auto close after 3 seconds if no errors
if (this.processStatus.failed === 0) {
setTimeout(this.closeProcess, 3000)
}
})
},
closeProcess() {
this.pickerforGroup = null
this.isProcessing = false
this.isProcessDone = false
// Reset
this.processStatus.failed = 0
this.processStatus.progress = 0
this.processStatus.success = 0
this.processStatus.total = 0
},
},
}
</script>
<style lang="scss" scoped>
</style>