diff options
author | Jessica <jessica@Absolventas-MacBook-Pro.local> | 2018-09-28 15:20:18 +0200 |
---|---|---|
committer | Jessica <jessica@Absolventas-MacBook-Pro.local> | 2018-09-28 15:20:18 +0200 |
commit | 531773f7ea78fda29825415725db8fcd8f9f09ec (patch) | |
tree | b2c2bda3f626e6950ed82d8e7e68bf1a4da27e71 /src | |
parent | 39a872acbaf30f66eb8aadb5114649d0231f4d99 (diff) | |
parent | 1d47e704b1db4abe38c8f4ccdaed7474a972a2a8 (diff) |
Merge remote-tracking branch 'origin/vue' into vue-avatar-management
Diffstat (limited to 'src')
-rw-r--r-- | src/components/ContactDetails.vue | 33 | ||||
-rw-r--r-- | src/models/contact.js | 1 | ||||
-rw-r--r-- | src/store/addressbooks.js | 5 | ||||
-rw-r--r-- | src/store/contacts.js | 56 |
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) }) |