summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--css/importScreen.scss17
-rw-r--r--package-lock.json33
-rw-r--r--package.json1
-rw-r--r--src/components/ImportScreen.vue33
-rw-r--r--src/services/parseVcf.js6
-rw-r--r--src/store/addressbooks.js43
-rw-r--r--src/store/importState.js5
7 files changed, 108 insertions, 30 deletions
diff --git a/css/importScreen.scss b/css/importScreen.scss
index c57dca90..3d815389 100644
--- a/css/importScreen.scss
+++ b/css/importScreen.scss
@@ -25,13 +25,16 @@
padding-top: 20px;
}
&__progress {
- width: 50%;
- position: absolute;
- left: 25%;
+ width: 50%;
+ min-width: 300px;
+ margin: auto;
}
&__tracker {
- padding-top: 10px;
- position: absolute;
- left: 25%;
+ display: flex;
+ justify-content: space-between;
+ width: 50%;
+ min-width: 300px;
+ margin: auto;
+ padding-top: 10px;
}
-} \ No newline at end of file
+}
diff --git a/package-lock.json b/package-lock.json
index f5c2f5d8..2efc69c4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10869,12 +10869,11 @@
"dev": true
},
"p-limit": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
- "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
- "dev": true,
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz",
+ "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==",
"requires": {
- "p-try": "^1.0.0"
+ "p-try": "^2.0.0"
}
},
"p-locate": {
@@ -10884,13 +10883,29 @@
"dev": true,
"requires": {
"p-limit": "^1.1.0"
+ },
+ "dependencies": {
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+ "dev": true
+ }
}
},
"p-try": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
- "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
- "dev": true
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
+ "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ=="
},
"pako": {
"version": "1.0.6",
diff --git a/package.json b/package.json
index ca5646c8..a0e58ba0 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
"ical.js": "^1.2.2",
"moment": "^2.22.2",
"nextcloud-vue": "^0.1.3",
+ "p-limit": "^2.0.0",
"uuid": "^3.3.2",
"v-tooltip": "^2.0.0-rc.33",
"vue": "^2.5.17",
diff --git a/src/components/ImportScreen.vue b/src/components/ImportScreen.vue
index bb903442..b58182fa 100644
--- a/src/components/ImportScreen.vue
+++ b/src/components/ImportScreen.vue
@@ -23,19 +23,46 @@
<template>
<div class="emptycontent import-screen">
<p class="icon-upload" />
- <h3 class="import-screen__header">{{ t('contacts', 'Importing into') }} {{ importState.addressbook }}</h3>
- <progress :max="importState.total" :value="importState.accepted" class="import-screen__progress" />
- <p class="import-screen__tracker">{{ Math.floor(importState.accepted/(importState.total + 1)) * 100 }} %</p>
+ <h3 class="import-screen__header">{{ t('contacts', 'Importing {total} contacts into', { total }) }} {{ addressbook }}</h3>
+ <progress :max="total" :value="progress" class="import-screen__progress" />
+ <p class="import-screen__tracker">
+ <span>{{ percentage }} %</span>
+ <span v-tooltip.auto="t('contacts', 'Open your browser console for more details')">{{ denied }} {{ t('contacts', 'failed') }}</span>
+ </p>
</div>
</template>
<script>
+import Vue from 'vue'
+import VTooltip from 'v-tooltip'
+
+Vue.use(VTooltip)
export default {
name: 'ImportScreen',
computed: {
importState() {
return this.$store.getters.getImportState
+ },
+ addressbook() {
+ return this.importState.addressbook
+ },
+ total() {
+ return this.importState.total
+ },
+ accepted() {
+ return this.importState.accepted
+ },
+ denied() {
+ return this.importState.denied
+ },
+ progress() {
+ return this.accepted + this.denied
+ },
+ percentage() {
+ return this.total <= 0
+ ? 0
+ : Math.floor(this.progress / this.total * 100)
}
}
}
diff --git a/src/services/parseVcf.js b/src/services/parseVcf.js
index 65d5f95c..11b1fc49 100644
--- a/src/services/parseVcf.js
+++ b/src/services/parseVcf.js
@@ -26,14 +26,13 @@ import Store from '../store/index'
export default function parseVcf(data = '', addressbook) {
let regexp = /BEGIN:VCARD[\s\S]*?END:VCARD/mgi
let vCards = data.match(regexp)
- let importState = Store.getters.getImportState
if (!vCards) {
console.debug('Error during the parsing of the following vcf file: ', data)
return []
}
- importState.total = vCards.length
+ Store.dispatch('setTotal', vCards.length)
// Not using map because we want to only push valid contacts
// map force to return at least undefined
@@ -41,11 +40,10 @@ export default function parseVcf(data = '', addressbook) {
try {
// console.log(vCards.indexOf(vCard))
let contact = new Contact(vCard, addressbook)
- importState.accepted++
contacts.push(contact)
} catch (e) {
// Parse error! Do not stop here...
- importState.denied++
+ Store.dispatch('incrementDenied')
console.error(e)
}
return contacts
diff --git a/src/store/addressbooks.js b/src/store/addressbooks.js
index 74a47bef..185a6465 100644
--- a/src/store/addressbooks.js
+++ b/src/store/addressbooks.js
@@ -22,9 +22,11 @@
*/
import Vue from 'vue'
+import ICAL from 'ical.js'
import parseVcf from '../services/parseVcf'
import client from '../services/cdav'
import Contact from '../models/contact'
+import pLimit from 'p-limit'
const addressbookModel = {
id: '',
@@ -327,15 +329,42 @@ const actions = {
* @param {Object} context the store mutations
* @param {Object} importDetails = { vcf, addressbook }
*/
- importContactsIntoAddressbook(context, { vcf, addressbook }) {
- let contacts = parseVcf(vcf, addressbook)
+ async importContactsIntoAddressbook(context, { vcf, addressbook }) {
+ const contacts = parseVcf(vcf, addressbook)
context.commit('changeStage', 'importing')
- contacts.forEach(contact => {
- context.commit('addContact', contact)
- context.commit('addContactToAddressbook', contact)
- context.commit('appendGroupsFromContacts', [contact])
+
+ // max simultaneous requests
+ const limit = pLimit(3)
+ const requests = []
+
+ // create the array of requests to send
+ contacts.map(async contact => {
+ // Get vcard string
+ try {
+ let vData = ICAL.stringify(contact.vCard.jCal)
+ // push contact to server and use limit
+ requests.push(limit(() => contact.addressbook.dav.createVCard(vData)
+ .then((response) => {
+ // success, update store
+ context.commit('addContact', contact)
+ context.commit('addContactToAddressbook', contact)
+ context.commit('appendGroupsFromContacts', [contact])
+ context.commit('incrementAccepted')
+ })
+ .catch((error) => {
+ // error
+ context.commit('incrementDenied')
+ console.error(error)
+ })
+ ))
+ } catch (e) {
+ context.commit('incrementDenied')
+ }
+ })
+
+ Promise.all(requests).then(() => {
+ // context.commit('changeStage', 'default')
})
- context.commit('changeStage', 'default')
},
/**
diff --git a/src/store/importState.js b/src/store/importState.js
index 024b0ac0..313c8d6d 100644
--- a/src/store/importState.js
+++ b/src/store/importState.js
@@ -77,6 +77,11 @@ const mutations = {
*/
changeStage(state, stage) {
state.importState.stage = stage
+ if (stage === 'default') {
+ state.accepted = 0
+ state.denied = 0
+ state.total = 0
+ }
}
}