|
|
@@ -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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |