Port files sharing selector

Signed-off-by: Christopher Ng <chrng8@gmail.com>
pull/36055/head
Christopher Ng 1 year ago
parent 75d7203f57
commit 0236c9e8cd

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -41,7 +41,7 @@ class FilesAppSharingContext implements Context, ActorAwareInterface {
* @return Locator
*/
public static function shareWithInput() {
return Locator::forThe()->css(".sharing-search__input .multiselect__input")->
return Locator::forThe()->css(".sharing-search__input input")->
descendantOf(FilesAppContext::detailsView())->
describedAs("Share with input in the details view in Files app");
}
@ -50,8 +50,7 @@ class FilesAppSharingContext implements Context, ActorAwareInterface {
* @return Locator
*/
public static function shareWithInputResults() {
return Locator::forThe()->css(".sharing-search__input .multiselect__content-wrapper")->
descendantOf(FilesAppContext::detailsView())->
return Locator::forThe()->css(".vs__dropdown-menu")->
describedAs("Share with input results list in the details view in Files app");
}
@ -59,7 +58,7 @@ class FilesAppSharingContext implements Context, ActorAwareInterface {
* @return Locator
*/
public static function shareWithInputResult($result) {
return Locator::forThe()->xpath("//li[contains(concat(' ', normalize-space(@class), ' '), ' multiselect__element ')]//span[normalize-space() = '$result']/ancestor::li")->
return Locator::forThe()->xpath("//li//span[normalize-space() = '$result']/ancestor::li")->
descendantOf(self::shareWithInputResults())->
describedAs("Share with input result from the results list in the details view in Files app");
}

Loading…
Cancel
Save