|
|
|
@ -23,32 +23,23 @@
|
|
|
|
|
<template>
|
|
|
|
|
<div class="sharing-search">
|
|
|
|
|
<label for="sharing-search-input">{{ t('files_sharing', 'Search for share recipients') }}</label>
|
|
|
|
|
<NcMultiselect ref="multiselect"
|
|
|
|
|
<NcSelect ref="select"
|
|
|
|
|
id="sharing-search-input"
|
|
|
|
|
class="sharing-search__input"
|
|
|
|
|
:clear-on-select="true"
|
|
|
|
|
:disabled="!canReshare"
|
|
|
|
|
:hide-selected="true"
|
|
|
|
|
:internal-search="false"
|
|
|
|
|
:loading="loading"
|
|
|
|
|
:options="options"
|
|
|
|
|
:filterable="false"
|
|
|
|
|
:placeholder="inputPlaceholder"
|
|
|
|
|
:preselect-first="true"
|
|
|
|
|
:preserve-search="true"
|
|
|
|
|
:searchable="true"
|
|
|
|
|
:clear-search-on-blur="() => false"
|
|
|
|
|
:user-select="true"
|
|
|
|
|
open-direction="below"
|
|
|
|
|
label="displayName"
|
|
|
|
|
track-by="id"
|
|
|
|
|
@search-change="asyncFind"
|
|
|
|
|
@select="addShare">
|
|
|
|
|
<template #noOptions>
|
|
|
|
|
{{ t('files_sharing', 'No recommendations. Start typing.') }}
|
|
|
|
|
</template>
|
|
|
|
|
<template #noResult>
|
|
|
|
|
{{ noResultText }}
|
|
|
|
|
:options="options"
|
|
|
|
|
v-model="value"
|
|
|
|
|
@search="asyncFind"
|
|
|
|
|
@option:selected="addShare">
|
|
|
|
|
<template #no-options="{ search }">
|
|
|
|
|
{{ search ? noResultText : t('files_sharing', 'No recommendations. Start typing.') }}
|
|
|
|
|
</template>
|
|
|
|
|
</NcMultiselect>
|
|
|
|
|
</NcSelect>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
@ -57,7 +48,7 @@ import { generateOcsUrl } from '@nextcloud/router'
|
|
|
|
|
import { getCurrentUser } from '@nextcloud/auth'
|
|
|
|
|
import axios from '@nextcloud/axios'
|
|
|
|
|
import debounce from 'debounce'
|
|
|
|
|
import NcMultiselect from '@nextcloud/vue/dist/Components/NcMultiselect'
|
|
|
|
|
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
|
|
|
|
|
|
|
|
|
|
import Config from '../services/ConfigService'
|
|
|
|
|
import GeneratePassword from '../utils/GeneratePassword'
|
|
|
|
@ -69,7 +60,7 @@ export default {
|
|
|
|
|
name: 'SharingInput',
|
|
|
|
|
|
|
|
|
|
components: {
|
|
|
|
|
NcMultiselect,
|
|
|
|
|
NcSelect,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
mixins: [ShareTypes, ShareRequests],
|
|
|
|
@ -108,6 +99,7 @@ export default {
|
|
|
|
|
recommendations: [],
|
|
|
|
|
ShareSearch: OCA.Sharing.ShareSearch.state,
|
|
|
|
|
suggestions: [],
|
|
|
|
|
value: null,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
@ -161,7 +153,7 @@ export default {
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
|
async asyncFind(query, id) {
|
|
|
|
|
async asyncFind(query) {
|
|
|
|
|
// save current query to check if we display
|
|
|
|
|
// recommendations or search results
|
|
|
|
|
this.query = query.trim()
|
|
|
|
@ -391,21 +383,38 @@ export default {
|
|
|
|
|
// themselves from it, so let's not display the user icon
|
|
|
|
|
// case this.SHARE_TYPES.SHARE_TYPE_REMOTE:
|
|
|
|
|
// case this.SHARE_TYPES.SHARE_TYPE_USER:
|
|
|
|
|
return 'icon-user'
|
|
|
|
|
return {
|
|
|
|
|
icon: 'icon-user',
|
|
|
|
|
iconTitle: t('files_sharing', 'Guest'),
|
|
|
|
|
}
|
|
|
|
|
case this.SHARE_TYPES.SHARE_TYPE_REMOTE_GROUP:
|
|
|
|
|
case this.SHARE_TYPES.SHARE_TYPE_GROUP:
|
|
|
|
|
return 'icon-group'
|
|
|
|
|
return {
|
|
|
|
|
icon: 'icon-group',
|
|
|
|
|
iconTitle: t('files_sharing', 'Group'),
|
|
|
|
|
}
|
|
|
|
|
case this.SHARE_TYPES.SHARE_TYPE_EMAIL:
|
|
|
|
|
return 'icon-mail'
|
|
|
|
|
return {
|
|
|
|
|
icon: 'icon-mail',
|
|
|
|
|
iconTitle: t('files_sharing', 'Email'),
|
|
|
|
|
}
|
|
|
|
|
case this.SHARE_TYPES.SHARE_TYPE_CIRCLE:
|
|
|
|
|
return 'icon-circle'
|
|
|
|
|
return {
|
|
|
|
|
icon: 'icon-circle',
|
|
|
|
|
iconTitle: t('files_sharing', 'Circle'),
|
|
|
|
|
}
|
|
|
|
|
case this.SHARE_TYPES.SHARE_TYPE_ROOM:
|
|
|
|
|
return 'icon-room'
|
|
|
|
|
return {
|
|
|
|
|
icon: 'icon-room',
|
|
|
|
|
iconTitle: t('files_sharing', 'Talk conversation'),
|
|
|
|
|
}
|
|
|
|
|
case this.SHARE_TYPES.SHARE_TYPE_DECK:
|
|
|
|
|
return 'icon-deck'
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
icon: 'icon-deck',
|
|
|
|
|
iconTitle: t('files_sharing', 'Deck board'),
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return ''
|
|
|
|
|
return {}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
@ -438,7 +447,7 @@ export default {
|
|
|
|
|
displayName: result.name || result.label,
|
|
|
|
|
subtitle,
|
|
|
|
|
shareWithDisplayNameUnique: result.shareWithDisplayNameUnique || '',
|
|
|
|
|
icon: this.shareTypeToIcon(result.value.shareType),
|
|
|
|
|
...this.shareTypeToIcon(result.value.shareType),
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
@ -448,12 +457,15 @@ export default {
|
|
|
|
|
* @param {object} value the multiselect option
|
|
|
|
|
*/
|
|
|
|
|
async addShare(value) {
|
|
|
|
|
// Clear the displayed selection
|
|
|
|
|
this.value = null
|
|
|
|
|
|
|
|
|
|
if (value.lookup) {
|
|
|
|
|
await this.getSuggestions(this.query, true)
|
|
|
|
|
|
|
|
|
|
// focus the input again
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
this.$refs.multiselect.$el.querySelector('.multiselect__input').focus()
|
|
|
|
|
// open the dropdown again
|
|
|
|
|
this.$refs.select.$children[0].open = true
|
|
|
|
|
})
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
@ -501,19 +513,12 @@ export default {
|
|
|
|
|
this.$emit('add:share', share)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// reset the search string when done
|
|
|
|
|
// FIXME: https://github.com/shentao/vue-multiselect/issues/633
|
|
|
|
|
if (this.$refs.multiselect?.$refs?.VueMultiselect?.search) {
|
|
|
|
|
this.$refs.multiselect.$refs.VueMultiselect.search = ''
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await this.getRecommendations()
|
|
|
|
|
} catch (error) {
|
|
|
|
|
// focus back if any error
|
|
|
|
|
const input = this.$refs.multiselect.$el.querySelector('input')
|
|
|
|
|
if (input) {
|
|
|
|
|
input.focus()
|
|
|
|
|
}
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
// open the dropdown again on error
|
|
|
|
|
this.$refs.select.$children[0].open = true
|
|
|
|
|
})
|
|
|
|
|
this.query = value.shareWith
|
|
|
|
|
console.error('Error while adding new share', error)
|
|
|
|
|
} finally {
|
|
|
|
@ -537,19 +542,19 @@ export default {
|
|
|
|
|
&__input {
|
|
|
|
|
width: 100%;
|
|
|
|
|
margin: 10px 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// properly style the lookup entry
|
|
|
|
|
.multiselect__option {
|
|
|
|
|
span[lookup] {
|
|
|
|
|
.avatardiv {
|
|
|
|
|
background-image: var(--icon-search-white);
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
background-position: center;
|
|
|
|
|
background-color: var(--color-text-maxcontrast) !important;
|
|
|
|
|
div {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.vs__dropdown-menu {
|
|
|
|
|
// properly style the lookup entry
|
|
|
|
|
span[lookup] {
|
|
|
|
|
.avatardiv {
|
|
|
|
|
background-image: var(--icon-search-white);
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
background-position: center;
|
|
|
|
|
background-color: var(--color-text-maxcontrast) !important;
|
|
|
|
|
div {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|