summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJessica <jessica@Absolventas-MacBook-Pro.local>2018-09-28 15:20:18 +0200
committerJessica <jessica@Absolventas-MacBook-Pro.local>2018-09-28 15:20:18 +0200
commit531773f7ea78fda29825415725db8fcd8f9f09ec (patch)
treeb2c2bda3f626e6950ed82d8e7e68bf1a4da27e71 /src
parent39a872acbaf30f66eb8aadb5114649d0231f4d99 (diff)
parent1d47e704b1db4abe38c8f4ccdaed7474a972a2a8 (diff)
Merge remote-tracking branch 'origin/vue' into vue-avatar-management
Diffstat (limited to 'src')
-rw-r--r--src/components/ContactDetails.vue33
-rw-r--r--src/models/contact.js1
-rw-r--r--src/store/addressbooks.js5
-rw-r--r--src/store/contacts.js56
4 files changed, 81 insertions, 14 deletions
diff --git a/src/components/ContactDetails.vue b/src/components/ContactDetails.vue
index 530df74c..67f93ef1 100644
--- a/src/components/ContactDetails.vue
+++ b/src/components/ContactDetails.vue
@@ -67,7 +67,13 @@
<!-- actions -->
<div id="contact-header-actions">
- <div v-tooltip.auto="warning" :class="{'icon-loading-small': loadingUpdate, 'icon-error-white menu-icon--pulse': warning}" class="menu-icon" />
+ <div v-tooltip.bottom="warning" :class="{'icon-loading-small': loadingUpdate, 'menu-icon--pulse icon-error-white': warning}" class="menu-icon" />
+ <div v-tooltip="{
+ content: conflict,
+ show: true,
+ trigger: 'manual',
+ }" v-if="conflict" class="menu-icon menu-icon--pulse icon-history-white"
+ @click="refreshContact" />
<div class="menu-icon">
<div v-click-outside="closeMenu" class="icon-more-white" @click="toggleMenu" />
<div :class="{ 'open': openedMenu }" class="popovermenu">
@@ -165,7 +171,7 @@ export default {
/**
* Warning message
*
- * @returns {string}
+ * @returns {string|undefined}
*/
warning() {
if (!this.contact.dav) {
@@ -174,6 +180,17 @@ export default {
},
/**
+ * Conflict message
+ *
+ * @returns {string|undefined}
+ */
+ conflict() {
+ if (this.contact.conflict) {
+ return t('contacts', 'The contact you were trying to edit has changed. Please manually refresh the contact. Any further edits will be discarded.')
+ }
+ },
+
+ /**
* Contact color based on uid
*
* @returns {string}
@@ -334,7 +351,7 @@ export default {
// if contact exists AND if exists on server
if (contact && contact.dav) {
- this.$store.dispatch('fetchFullContact', contact)
+ this.$store.dispatch('fetchFullContact', { contact })
.then(() => {
// create empty contact and copy inner data
let localContact = new Contact(
@@ -389,6 +406,16 @@ export default {
this.updateContact()
})
}
+ },
+
+ /**
+ * Refresh the data of a contact
+ */
+ refreshContact() {
+ this.$store.dispatch('fetchFullContact', { contact: this.contact, etag: this.conflict })
+ .then(() => {
+ this.contact.conflict = false
+ })
}
}
}
diff --git a/src/models/contact.js b/src/models/contact.js
index 95a20ca2..8854f8ff 100644
--- a/src/models/contact.js
+++ b/src/models/contact.js
@@ -48,6 +48,7 @@ export default class Contact {
this.addressbook = addressbook
this.vCard = new ICAL.Component(this.jCal)
this.url = url
+ this.conflict = false
// if no uid set, create one
if (!this.vCard.hasProperty('uid')) {
diff --git a/src/store/addressbooks.js b/src/store/addressbooks.js
index d6ca8a1d..b7828f4b 100644
--- a/src/store/addressbooks.js
+++ b/src/store/addressbooks.js
@@ -306,7 +306,7 @@ const actions = {
// so we need to parse one by one
const contacts = response.map(item => {
let contact = new Contact(item.data, addressbook, item.url, item.etag)
- contact.dav = item
+ Vue.set(contact, 'dav', item)
return contact
})
context.commit('appendContactsToAddressbook', { addressbook, contacts })
@@ -345,6 +345,9 @@ const actions = {
// push contact to server and use limit
requests.push(limit(() => contact.addressbook.dav.createVCard(vData)
.then((response) => {
+ // setting the contact dav property
+ Vue.set(contact, 'dav', response)
+
// success, update store
context.commit('addContact', contact)
context.commit('addContactToAddressbook', contact)
diff --git a/src/store/contacts.js b/src/store/contacts.js
index aa0805f0..60e2c6bf 100644
--- a/src/store/contacts.js
+++ b/src/store/contacts.js
@@ -38,7 +38,7 @@ const mutations = {
* Store contacts into state
*
* @param {Object} state Default state
- * @param {Array} contacts Contacts
+ * @param {Array<Contact>} contacts Contacts
*/
appendContacts(state, contacts = []) {
state.contacts = contacts.reduce(function(list, contact) {
@@ -143,14 +143,15 @@ const mutations = {
},
/**
- * Update a contact
+ * Update a contact addressbook
*
* @param {Object} state the store data
+ * @param {Object} data destructuring object
* @param {Contact} contact the contact to update
+ * @param {Object} addressbook the addressbook to set
*/
updateContactAddressbook(state, { contact, addressbook }) {
if (state.contacts[contact.key] && contact instanceof Contact) {
-
// replace contact object data
state.contacts[contact.key].updateAddressbook(addressbook)
@@ -160,6 +161,24 @@ const mutations = {
},
/**
+ * Update a contact etag
+ *
+ * @param {Object} state the store data
+ * @param {Object} data destructuring object
+ * @param {Contact} contact the contact to update
+ * @param {string} etag the contact etag
+ */
+ updateContactEtag(state, { contact, etag }) {
+ if (state.contacts[contact.key] && contact instanceof Contact) {
+ // replace contact object data
+ state.contacts[contact.key].dav.etag = etag
+
+ } else {
+ console.error('Error while replacing the etag of following contact', contact)
+ }
+ },
+
+ /**
* Order the contacts list. Filters have terrible performances.
* We do not want to run the sorting function every time.
* Let's only run it on additions and create an index
@@ -254,22 +273,39 @@ const actions = {
.catch((error) => { throw error })
}
- contact.dav.data = vData
- return contact.dav.update()
- .then((response) => context.commit('updateContact', contact))
- .catch((error) => { throw error })
+ if (!contact.conflict) {
+ contact.dav.data = vData
+ return contact.dav.update()
+ .then((response) => {
+ // wrong etag, we most likely have a conflict
+ if (response.status === 412) {
+ contact.conflict = response.xhr.getResponseHeader('etag')
+ } else {
+ // all clear, let's update the store
+ context.commit('updateContact', contact)
+ }
+ })
+ .catch((error) => { throw error })
+ } else {
+ console.error('This contact is outdated, refusing to push', contact)
+ }
},
/**
* Fetch the full vCard from the dav server
*
* @param {Object} context the store mutations
- * @param {Contact} contact the contact to fetch
+ * @param {Object} data destructuring object
+ * @param {Contact} data.contact the contact to fetch
+ * @param {string} data.etag the contact etag
* @returns {Promise}
*/
- async fetchFullContact(context, contact) {
+ async fetchFullContact(context, { contact, etag = '' }) {
+ if (etag !== '') {
+ await context.commit('updateContactEtag', { contact, etag })
+ }
return contact.dav.fetchCompleteData()
- .then(() => {
+ .then((response) => {
let newContact = new Contact(contact.dav.data, contact.addressbook, contact.dav.url, contact.dav.etag)
context.commit('updateContact', newContact)
})