Fix tests & add MOVE
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
parent
0f72d40d46
commit
17e8723adc
File diff suppressed because it is too large
Load Diff
39
package.json
39
package.json
|
@ -31,8 +31,8 @@
|
|||
"lint:fix": "eslint --ext .js,.vue src tests --fix",
|
||||
"stylelint": "stylelint src",
|
||||
"stylelint:fix": "stylelint src --fix",
|
||||
"test": "jest",
|
||||
"test:coverage": "jest --coverage"
|
||||
"test": "mocha-webpack --webpack-config webpack.test.js --require tests/setup.js \"tests/js/**/*.spec.js\"",
|
||||
"test:watch": "mocha-webpack -w --webpack-config webpack.test.js --require tests/setup.js \"tests/js/**/*.spec.js\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.0.0",
|
||||
|
@ -66,8 +66,8 @@
|
|||
"@babel/preset-env": "^7.1.5",
|
||||
"@vue/test-utils": "^1.0.0-beta.25",
|
||||
"babel-eslint": "^8.2.5",
|
||||
"babel-jest": "^23.6.0",
|
||||
"babel-loader": "^8.0.4",
|
||||
"chai": "^4.2.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-standard": "^11.0.0",
|
||||
|
@ -79,42 +79,21 @@
|
|||
"eslint-plugin-standard": "^3.1.0",
|
||||
"eslint-plugin-vue": "^4.5.0",
|
||||
"file-loader": "^2.0.0",
|
||||
"jest": "^23.6.0",
|
||||
"jest-serializer-vue": "^2.0.2",
|
||||
"jsdom": "^13.0.0",
|
||||
"jsdom-global": "^3.0.2",
|
||||
"mocha": "^5.2.0",
|
||||
"mocha-webpack": "^2.0.0-beta.0",
|
||||
"node-sass": "^4.10.0",
|
||||
"prettier-eslint": "^8.8.2",
|
||||
"sass-loader": "^7.1.0",
|
||||
"stylelint": "^8.4.0",
|
||||
"stylelint-config-recommended-scss": "^3.2.0",
|
||||
"stylelint-scss": "^3.4.0",
|
||||
"stylelint-webpack-plugin": "^0.10.5",
|
||||
"vue-jest": "^2.6.0",
|
||||
"vue-loader": "^15.4.2",
|
||||
"vue-template-compiler": "^2.5.17",
|
||||
"webpack": "^4.25.1",
|
||||
"webpack-cli": "^3.1.2",
|
||||
"webpack-merge": "^4.1.4"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"vue"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"^@/(.*)$": "<rootDir>/src/$1"
|
||||
},
|
||||
"transform": {
|
||||
"^.+\\.js$": "babel-jest",
|
||||
"^.+\\.vue$": "vue-jest"
|
||||
},
|
||||
"snapshotSerializers": [
|
||||
"<rootDir>/node_modules/jest-serializer-vue"
|
||||
],
|
||||
"globals": {
|
||||
"t": true,
|
||||
"n": true,
|
||||
"OC": true,
|
||||
"OCA": true
|
||||
}
|
||||
"webpack-merge": "^4.1.4",
|
||||
"webpack-node-externals": "^1.7.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,6 @@ import Vue from 'vue'
|
|||
import VTooltip from 'v-tooltip'
|
||||
import debounce from 'debounce'
|
||||
|
||||
import Contact from '../models/contact'
|
||||
import rfcProps from '../models/rfcProps.js'
|
||||
|
||||
import ContactProperty from './ContactDetails/ContactDetailsProperty'
|
||||
|
@ -145,7 +144,7 @@ export default {
|
|||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
uid: {
|
||||
contactKey: {
|
||||
type: String,
|
||||
default: undefined
|
||||
}
|
||||
|
@ -276,7 +275,7 @@ export default {
|
|||
*/
|
||||
addressbooksOptions() {
|
||||
return this.addressbooks
|
||||
.filter(addressbook => addressbook.readOnly)
|
||||
.filter(addressbook => !addressbook.readOnly)
|
||||
.map(addressbook => {
|
||||
return {
|
||||
id: addressbook.id,
|
||||
|
@ -290,22 +289,22 @@ export default {
|
|||
return this.$store.getters.getAddressbooks
|
||||
},
|
||||
contact() {
|
||||
return this.$store.getters.getContact(this.uid)
|
||||
return this.$store.getters.getContact(this.contactKey)
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
contact: function() {
|
||||
if (this.uid) {
|
||||
this.selectContact(this.uid)
|
||||
if (this.contactKey) {
|
||||
this.selectContact(this.contactKey)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
beforeMount() {
|
||||
// load the desired data if we already selected a contact
|
||||
if (this.uid) {
|
||||
this.selectContact(this.uid)
|
||||
if (this.contactKey) {
|
||||
this.selectContact(this.contactKey)
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -314,12 +313,10 @@ export default {
|
|||
* Executed on the 'updatedcontact' event
|
||||
* Send the local clone of contact to the store
|
||||
*/
|
||||
updateContact() {
|
||||
async updateContact() {
|
||||
this.loadingUpdate = true
|
||||
this.$store.dispatch('updateContact', this.contact)
|
||||
.then(() => {
|
||||
this.loadingUpdate = false
|
||||
})
|
||||
await this.$store.dispatch('updateContact', this.contact)
|
||||
this.loadingUpdate = false
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -343,12 +340,12 @@ export default {
|
|||
* Fetch updated data if necessary
|
||||
* Scroll to the selected contact if exists
|
||||
*
|
||||
* @param {string} uid the contact uid
|
||||
* @param {string} key the contact key
|
||||
*/
|
||||
selectContact(uid) {
|
||||
selectContact(key) {
|
||||
// local version of the contact
|
||||
this.loadingData = true
|
||||
let contact = this.$store.getters.getContact(uid)
|
||||
let contact = this.$store.getters.getContact(key)
|
||||
|
||||
if (contact) {
|
||||
// if contact exists AND if exists on server
|
||||
|
@ -356,11 +353,10 @@ export default {
|
|||
this.$store.dispatch('fetchFullContact', { contact })
|
||||
.then(() => {
|
||||
// create empty contact and copy inner data
|
||||
let localContact = new Contact(
|
||||
'BEGIN:VCARD\nUID:' + contact.uid + '\nEND:VCARD',
|
||||
contact.addressbook
|
||||
let localContact = Object.assign(
|
||||
Object.create(Object.getPrototypeOf(contact)),
|
||||
contact
|
||||
)
|
||||
localContact.updateContact(contact.jCal)
|
||||
this.localContact = localContact
|
||||
this.loadingData = false
|
||||
})
|
||||
|
@ -373,9 +369,9 @@ export default {
|
|||
} else {
|
||||
// create empty contact and copy inner data
|
||||
// wait for an update to really push the contact on the server!
|
||||
this.localContact = new Contact(
|
||||
'BEGIN:VCARD\nUID:' + contact.uid + '\nEND:VCARD',
|
||||
contact.addressbook
|
||||
this.localContact = Object.assign(
|
||||
Object.create(Object.getPrototypeOf(contact)),
|
||||
contact
|
||||
)
|
||||
this.loadingData = false
|
||||
}
|
||||
|
@ -404,20 +400,30 @@ export default {
|
|||
*
|
||||
* @param {string} addressbookId the desired addressbook ID
|
||||
*/
|
||||
moveContactToAddressbook(addressbookId) {
|
||||
async moveContactToAddressbook(addressbookId) {
|
||||
let addressbook = this.addressbooks.find(search => search.id === addressbookId)
|
||||
this.loadingUpdate = true
|
||||
// TODO Properly implement the MOVE request
|
||||
if (addressbook) {
|
||||
this.$store.dispatch('moveContactToAddressbook', {
|
||||
// we need to use the store contact, not the local contact
|
||||
// using this.contact and not this.localContact
|
||||
contact: this.contact,
|
||||
addressbook
|
||||
}).then(() => {
|
||||
this.updateContact()
|
||||
try {
|
||||
const contact = await this.$store.dispatch('moveContactToAddressbook', {
|
||||
// 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
|
||||
}
|
||||
})
|
||||
this.loadingUpdate = false
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
this.loadingUpdate = false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -75,7 +75,6 @@ export default {
|
|||
editingName: false,
|
||||
copied: false,
|
||||
copySuccess: true,
|
||||
readOnly: this.addressbook.readOnly,
|
||||
toggleEnabledLoading: false,
|
||||
deleteAddressbookLoading: false,
|
||||
renameLoading: false,
|
||||
|
@ -107,7 +106,7 @@ export default {
|
|||
]
|
||||
|
||||
// check if addressbook is readonly
|
||||
if (!this.readOnly) {
|
||||
if (!this.addressbook.readOnly) {
|
||||
menu.push({
|
||||
icon: this.renameLoading ? 'icon-loading-small' : 'icon-rename',
|
||||
// check if editing name
|
||||
|
|
|
@ -425,31 +425,21 @@ const actions = {
|
|||
* @param {Object} data destructuring object
|
||||
* @param {Contact} data.contact the contact to move
|
||||
* @param {Object} data.addressbook the addressbook to move the contact to
|
||||
* @returns {Contact} the new contact object
|
||||
*/
|
||||
async moveContactToAddressbook(context, { contact, addressbook }) {
|
||||
// only local move if the contact doesn't exists on the server
|
||||
if (contact.dav) {
|
||||
// TODO: implement proper move
|
||||
// await contact.dav.move(addressbook.dav)
|
||||
// .catch((error) => {
|
||||
// console.error(error)
|
||||
// OC.Notification.showTemporary(t('contacts', 'An error occurred'))
|
||||
// })
|
||||
let vData = ICAL.stringify(contact.vCard.jCal)
|
||||
let newDav
|
||||
await addressbook.dav.createVCard(vData)
|
||||
.then((response) => { newDav = response })
|
||||
.catch((error) => { throw error })
|
||||
await contact.dav.delete()
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
OC.Notification.showTemporary(t('contacts', 'An error occurred'))
|
||||
})
|
||||
await Vue.set(contact, 'dav', newDav)
|
||||
try {
|
||||
await contact.dav.move(addressbook.dav)
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
await context.commit('deleteContactFromAddressbook', contact)
|
||||
await context.commit('updateContactAddressbook', { contact, addressbook })
|
||||
await context.commit('addContactToAddressbook', contact)
|
||||
return contact
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,12 +152,27 @@ const mutations = {
|
|||
*/
|
||||
updateContactAddressbook(state, { contact, addressbook }) {
|
||||
if (state.contacts[contact.key] && contact instanceof Contact) {
|
||||
// replace contact object data
|
||||
// replace contact object data by creating a new contact
|
||||
let oldKey = contact.key
|
||||
let newContact = new Contact(contact.dav.data, addressbook)
|
||||
Vue.set(state.contacts, newContact.key, newContact)
|
||||
|
||||
// hijack reference
|
||||
var newContact = contact
|
||||
|
||||
// delete old key, cut reference
|
||||
Vue.delete(state.contacts, oldKey)
|
||||
|
||||
// replace addressbook
|
||||
Vue.set(newContact, 'addressbook', addressbook)
|
||||
|
||||
// set new key, re-assign reference
|
||||
Vue.set(state.contacts, newContact.key, newContact)
|
||||
|
||||
// Update sorted contacts list, replace at exact same position
|
||||
let index = state.sortedContacts.findIndex(search => search.key === oldKey)
|
||||
state.sortedContacts[index] = {
|
||||
key: newContact.key,
|
||||
value: newContact[state.orderKey]
|
||||
}
|
||||
} else {
|
||||
console.error('Error while replacing the addressbook of following contact', contact)
|
||||
}
|
||||
|
@ -218,7 +233,7 @@ const mutations = {
|
|||
const getters = {
|
||||
getContacts: state => state.contacts,
|
||||
getSortedContacts: state => state.sortedContacts,
|
||||
getContact: (state) => (uid) => state.contacts[uid],
|
||||
getContact: (state) => (key) => state.contacts[key],
|
||||
getOrderKey: state => state.orderKey
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<content-list :list="contactsList" :contacts="contacts" :loading="loading"
|
||||
:search-query="searchQuery" />
|
||||
<!-- main contacts details -->
|
||||
<contact-details :loading="loading" :uid="selectedContact" />
|
||||
<contact-details :loading="loading" :contact-key="selectedContact" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @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/>.
|
||||
*/
|
||||
|
||||
require('jsdom-global')()
|
||||
global.expect = require('chai').expect
|
||||
|
||||
global.OC = {
|
||||
getLocale: () => 'en'
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
const merge = require('webpack-merge')
|
||||
const common = require('./webpack.common.js')
|
||||
const nodeExternals = require('webpack-node-externals')
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
devtool: 'inline-cheap-module-source-map',
|
||||
externals: [nodeExternals()]
|
||||
})
|
Loading…
Reference in New Issue