Skip to content

Commit

Permalink
Add ability to clone contact
Browse files Browse the repository at this point in the history
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
  • Loading branch information
skjnldsv committed Feb 6, 2020
1 parent 89cc5e1 commit 1819d6f
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 42 deletions.
10 changes: 1 addition & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ matrix:
- php: 7.2
env: "DB=mysql CORE_BRANCH=master"
- php: 7.3
env: "DB=mysql CORE_BRANCH=master TEST_JS=TRUE PHP_COVERAGE=TRUE"
env: "DB=mysql CORE_BRANCH=master PHP_COVERAGE=TRUE"
- php: 7.2
env: "DB=pgsql CORE_BRANCH=master"
- php: 7.3
Expand Down Expand Up @@ -96,14 +96,6 @@ script:
# Run server's app code checker
- php ../../occ app:check-code contacts

# Run JS tests
- if [[ "$TEST_JS" = "TRUE" ]];
then make test;
fi

# Test JS compilation
- make build-js-production

# Test php
- make test-php
- if [[ "$PHP_COVERAGE" = "TRUE" ]];
Expand Down
2 changes: 2 additions & 0 deletions css/icons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
@include icon-black-white('up', 'contacts', 1);
@include icon-black-white('no-calendar', 'contacts', 1);
@include icon-black-white('language', 'contacts', 2);
@include icon-black-white('clone', 'contacts', 2);

.icon-up-force-white {
// using #fffffe to trick the accessibility dark theme icon invert
Expand All @@ -54,3 +55,4 @@
// using #fffffe to trick the accessibility dark theme icon invert
@include icon-color('picture', 'places', '#fffffe', 1, true);
}

1 change: 1 addition & 0 deletions img/clone.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 10 additions & 28 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 69 additions & 2 deletions src/components/ContactDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
:class="{'icon-loading-small': loadingUpdate,
[`${warning.icon}`]: warning}"
class="header-icon"
href="#" />
@click="onWarningClick" />

<!-- conflict message -->
<div v-if="conflict"
Expand All @@ -117,12 +117,22 @@
@click="updateContact" />

<!-- menu actions -->
<Actions class="header-menu" menu-align="right">
<Actions ref="actions"
class="header-menu"
menu-align="right"
:open.sync="openedMenu">
<ActionLink :href="contact.url"
:download="`${contact.displayName}.vcf`"
icon="icon-download">
{{ t('contacts', 'Download') }}
</ActionLink>
<!-- user can clone if there is at least one option available -->
<ActionButton v-if="isReadOnly && addressbooksOptions.length > 0"
ref="cloneAction"
icon="icon-clone"
@click="cloneContact">
{{ t('contacts', 'Clone contact') }}
</ActionButton>
<ActionButton icon="icon-qrcode" @click="showQRcode">
{{ t('contacts', 'Generate QR Code') }}
</ActionButton>
Expand Down Expand Up @@ -377,6 +387,7 @@ export default {
/**
* Store getters filtered and mapped to usable object
* This is the list of addressbooks that are available to write
*
* @returns {Array}
*/
Expand Down Expand Up @@ -550,6 +561,38 @@ export default {
}
},
/**
* Copy contact to the specified addressbook
*
* @param {string} addressbookId the desired addressbook ID
*/
async copyContactToAddressbook(addressbookId) {
const addressbook = this.addressbooks.find(search => search.id === addressbookId)
this.loadingUpdate = true
if (addressbook) {
try {
const contact = await this.$store.dispatch('copyContactToAddressbook', {
// we need to use the store contact, not the local contact
// using this.contact and not this.localContact
contact: this.contact,
addressbook,
})
// select the contact again
this.$router.push({
name: 'contact',
params: {
selectedGroup: this.$route.params.selectedGroup,
selectedContact: contact.key,
},
})
} catch (error) {
console.error(error)
} finally {
this.loadingUpdate = false
}
}
},
/**
* Refresh the data of a contact
*/
Expand Down Expand Up @@ -589,6 +632,30 @@ export default {
this.debounceUpdateContact()
}
},
/**
* Clone the current contact to another addressbook
*/
cloneContact() {
// only one addressbook, let's clone it there
if (this.addressbooksOptions.length === 1) {
this.copyContactToAddressbook(this.addressbooksOptions[0].id)
}
},
/**
* The user clicked the warning icon
*/
onWarningClick() {
// if the user clicked the readonly icon, let's focus the clone button
if (this.isReadOnly && this.addressbooksOptions.length > 0) {
this.openedMenu = true
this.$nextTick(() => {
// focus the clone button
this.$refs.actions.onMouseFocusAction({ target: this.$refs.cloneAction.$el })
})
}
},
},
}
</script>
4 changes: 2 additions & 2 deletions src/components/Properties/PropertyMultipleText.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@
@input="updateValue">

<!-- props actions -->
<PropertyActions class="property__actions--floating"
v-if="!isReadOnly"
<PropertyActions v-if="!isReadOnly"
class="property__actions--floating"
:actions="actions"
:property-component="this"
@delete="deleteProperty" />
Expand Down
30 changes: 29 additions & 1 deletion src/store/addressbooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ const actions = {

// Get vcard string
try {
const vData = ICAL.stringify(contact.vCard.jCal)
const vData = contact.vCard.toString()
// push contact to server and use limit
requests.push(limit(() => contact.addressbook.dav.createVCard(vData)
.then((response) => {
Expand Down Expand Up @@ -512,6 +512,34 @@ const actions = {
await context.commit('addContactToAddressbook', contact)
return contact
},

/**
* Copy a contact to the provided addressbook
*
* @param {Object} context the store mutations
* @param {Object} data destructuring object
* @param {Contact} data.contact the contact to copy
* @param {Object} data.addressbook the addressbook to move the contact to
* @returns {Contact} the new contact object
*/
async copyContactToAddressbook(context, { contact, addressbook }) {
// init new contact & strip old uid
const vData = contact.vCard.toString().replace(/^UID.+/im, '')
const newContact = new Contact(vData, addressbook)

try {
const response = await contact.dav.copy(addressbook.dav)
// setting the contact dav property
Vue.set(newContact, 'dav', response)

} catch (error) {
throw error
}
// success, update store
await context.commit('addContact', newContact)
await context.commit('addContactToAddressbook', newContact)
return newContact
},
}

export default { state, mutations, getters, actions }

0 comments on commit 1819d6f

Please sign in to comment.