summaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/ContactDetails/ContactDetailsAvatar.vue7
-rw-r--r--src/components/Properties/PropertyDateTime.vue2
-rw-r--r--src/components/Properties/PropertyMultipleText.vue4
-rw-r--r--src/components/Settings/SettingsImportContacts.vue194
-rw-r--r--src/components/SettingsSection.vue2
5 files changed, 185 insertions, 24 deletions
diff --git a/src/components/ContactDetails/ContactDetailsAvatar.vue b/src/components/ContactDetails/ContactDetailsAvatar.vue
index 703a3d4f..76433d41 100644
--- a/src/components/ContactDetails/ContactDetailsAvatar.vue
+++ b/src/components/ContactDetails/ContactDetailsAvatar.vue
@@ -88,8 +88,9 @@
import debounce from 'debounce'
import { ActionLink, ActionButton } from '@nextcloud/vue'
-import { getFilePickerBuilder } from 'nextcloud-dialogs'
-import { generateRemoteUrl } from 'nextcloud-router'
+import { getFilePickerBuilder } from '@nextcloud/dialogs'
+import { generateRemoteUrl } from '@nextcloud/router'
+import { getCurrentUser } from '@nextcloud/auth'
const axios = () => import('axios')
@@ -113,7 +114,7 @@ export default {
maximizeAvatar: false,
opened: false,
loading: false,
- root: generateRemoteUrl(`dav/files/${OC.getCurrentUser().uid}`),
+ root: generateRemoteUrl(`dav/files/${getCurrentUser().uid}`),
width: 0,
height: 0,
}
diff --git a/src/components/Properties/PropertyDateTime.vue b/src/components/Properties/PropertyDateTime.vue
index 03144509..cd0af107 100644
--- a/src/components/Properties/PropertyDateTime.vue
+++ b/src/components/Properties/PropertyDateTime.vue
@@ -85,7 +85,7 @@
import debounce from 'debounce'
import moment from 'moment'
import { DatetimePicker } from '@nextcloud/vue'
-import { getLocale } from 'nextcloud-l10n'
+import { getLocale } from '@nextcloud/l10n'
import { VCardTime } from 'ical.js'
import PropertyMixin from '../../mixins/PropertyMixin'
diff --git a/src/components/Properties/PropertyMultipleText.vue b/src/components/Properties/PropertyMultipleText.vue
index cd4107e9..896ff661 100644
--- a/src/components/Properties/PropertyMultipleText.vue
+++ b/src/components/Properties/PropertyMultipleText.vue
@@ -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" />
diff --git a/src/components/Settings/SettingsImportContacts.vue b/src/components/Settings/SettingsImportContacts.vue
index d7583a3a..f0b6f04c 100644
--- a/src/components/Settings/SettingsImportContacts.vue
+++ b/src/components/Settings/SettingsImportContacts.vue
@@ -23,21 +23,56 @@
<template>
<div class="import-contact">
<template v-if="!isNoAddressbookAvailable">
- <input id="contact-import"
- :disabled="isImporting"
- type="file"
- class="hidden-visually"
- @change="processFile">
- <label id="upload" for="contact-import" class="button import-contact__multiselect-label icon-upload">
- {{ isImporting ? t('contacts', 'Importing into') : t('contacts', 'Import into') }}
- </label>
- <multiselect
- v-model="selectedAddressbook"
- :options="options"
- :disabled="isSingleAddressbook || isImporting"
- :placeholder="t('contacts', 'Contacts')"
- label="displayName"
- class="import-contact__multiselect" />
+ <button class="import-contact__button-main" @click="toggleModal">
+ <span class="icon-upload" />
+ {{ t('contacts', 'Import contacts') }}
+ </button>
+ <Modal v-if="isOpened"
+ ref="modal"
+ class="import-contact__modal"
+ :title="t('contacts', 'Import contacts')"
+ @close="toggleModal">
+ <section class="import-contact__modal-addressbook">
+ <h3>{{ t('contacts', 'Import contacts') }}</h3>
+ <multiselect
+ v-if="!isSingleAddressbook"
+ id="select-addressbook"
+ v-model="selectedAddressbook"
+ :allow-empty="false"
+ :options="options"
+ :disabled="isSingleAddressbook || isImporting"
+ :placeholder="t('contacts', 'Contacts')"
+ label="displayName"
+ class="import-contact__multiselect">
+ <template slot="singleLabel" slot-scope="{ option }">
+ {{ t('contacts', `Import into the '{addressbookName}' addressbook`, { addressbookName: option.displayName }) }}
+ </template>
+ </multiselect>
+ </section>
+ <section class="import-contact__modal-pick">
+ <input id="contact-import"
+ ref="contact-import-input"
+ :disabled="loading || isImporting"
+ type="file"
+ class="hidden-visually"
+ @change="processFile">
+ <button
+ :disabled="loading"
+ class="button import-contact__button import-contact__button--local"
+ @click="clickImportInput">
+ <span class="import-contact__button-icon icon-upload" />
+ {{ t('contacts', 'Select local file') }}
+ </button>
+ <button
+ :class="{'icon-loading': loading}"
+ :disabled="loading"
+ class="button primary import-contact__button import-contact__button--files"
+ @click="openPicker">
+ <span class="import-contact__button-icon icon-folder-white" />
+ {{ t('contacts', 'Import from files') }}
+ </button>
+ </section>
+ </Modal>
</template>
<button v-else
id="upload"
@@ -49,12 +84,31 @@
</template>
<script>
+import { encodePath } from '@nextcloud/paths'
+import { getCurrentUser } from '@nextcloud/auth'
+import { generateRemoteUrl } from '@nextcloud/router'
+import { getFilePickerBuilder } from '@nextcloud/dialogs'
+import axios from 'axios'
+
+const CancelToken = axios.CancelToken
+
+const picker = getFilePickerBuilder(t('contacts', 'Choose a vcard file to import'))
+ .setMultiSelect(false)
+ .setModal(true)
+ .setType(1)
+ .allowDirectories(false)
+ .setMimeTypeFilter('text/vcard')
+ .build()
+
export default {
name: 'SettingsImportContacts',
data() {
return {
+ cancelRequest: () => {},
importDestination: false,
+ isOpened: false,
+ loading: false,
}
},
@@ -110,20 +164,126 @@ export default {
},
},
methods: {
+ /**
+ * Process input type file change
+ *
+ * @param {Event} event the input change event
+ */
processFile(event) {
+ this.loading = true
+ this.$store.dispatch('changeStage', 'parsing')
+
const file = event.target.files[0]
const reader = new FileReader()
const selectedAddressbook = this.selectedAddressbook
- this.$store.dispatch('changeStage', 'parsing')
- this.$store.dispatch('setAddressbook', selectedAddressbook.displayName)
+
const self = this
reader.onload = function(e) {
+ self.isOpened = false
self.$store.dispatch('importContactsIntoAddressbook', { vcf: reader.result, addressbook: selectedAddressbook })
+
// reset input
event.target.value = ''
+ self.resetState()
}
reader.readAsText(file)
},
+
+ toggleModal() {
+ this.isOpened = !this.isOpened
+ // cancel any ongoing request if closed
+ if (!this.isOpened) {
+ this.cancelRequest()
+ }
+ },
+
+ clickImportInput() {
+ this.$refs['contact-import-input'].click()
+ },
+
+ /**
+ * Open nextcloud file picker
+ */
+ async openPicker() {
+ try {
+ this.loading = true
+ // unlikely, but let's cancel any previous request
+ this.cancelRequest()
+
+ // prepare cancel token for axios request
+ const source = CancelToken.source()
+ this.cancelRequest = source.cancel
+
+ // pick and retrieve file
+ const path = await picker.pick()
+ const file = await axios.get(generateRemoteUrl(`dav/files/${getCurrentUser().uid}`) + encodePath(path), {
+ cancelToken: source.token,
+ })
+
+ this.$store.dispatch('changeStage', 'parsing')
+ this.$store.dispatch('setAddressbook', this.selectedAddressbook.displayName)
+
+ if (file.data) {
+ await this.$store.dispatch('importContactsIntoAddressbook', { vcf: file.data, addressbook: this.selectedAddressbook })
+ }
+ } catch (error) {
+ console.error('Something wrong happened while picking a file', error)
+ } finally {
+ this.resetState()
+ }
+ },
+
+ /**
+ * Reset default component state
+ */
+ resetState() {
+ this.cancelRequest = () => {}
+ this.importDestination = false
+ this.isOpened = false
+ this.loading = false
+ },
},
}
</script>
+
+<style lang="scss" scoped>
+.import-contact {
+ &__modal {
+ section {
+ padding: 22px;
+ // only one padding bewteen sections
+ &:not(:last-child) {
+ padding-bottom: 0;
+ }
+ }
+ &-pick {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ justify-content: space-evenly;
+ }
+ }
+ &__button {
+ display: flex;
+ align-items: center;
+ flex: 0 1 150px;
+ width: 150px;
+ // spread evenly
+ margin: 10px;
+ padding: 10px;
+ &-icon {
+ width: 32px;
+ height: 32px;
+ margin-right: 5px;
+ }
+ &-main {
+ width: 100%;
+ }
+ &--cancel:not(:focus):not(:hover) {
+ border-color: transparent;
+ background-color: transparent;
+ }
+ }
+}
+
+</style>
diff --git a/src/components/SettingsSection.vue b/src/components/SettingsSection.vue
index 7053356b..e0757716 100644
--- a/src/components/SettingsSection.vue
+++ b/src/components/SettingsSection.vue
@@ -26,11 +26,11 @@
<SettingsAddressbook v-for="addressbook in addressbooks" :key="addressbook.id" :addressbook="addressbook" />
</ul>
<SettingsNewAddressbook :addressbooks="addressbooks" />
+ <SettingsSortContacts class="settings-section" />
<SettingsImportContacts :addressbooks="addressbooks"
class="settings-section"
@clicked="onClickImport"
@fileLoaded="onLoad" />
- <SettingsSortContacts class="settings-section" />
</div>
</template>