Use ShareWith and filter shares on the fly

Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
John Molakvoæ (skjnldsv) 2020-05-06 12:39:52 +02:00
parent e060cfdfc7
commit e9d84d87f5
No known key found for this signature in database
GPG key ID: 60C25B8C072916CF
5 changed files with 28 additions and 32 deletions

View file

@ -216,10 +216,10 @@ class ApiController extends Controller {
try { try {
if ($keyValuePairs['access']) { if ($keyValuePairs['access']) {
$keyValuePairs['access']['users'] = array_map(function (array $user): string { $keyValuePairs['access']['users'] = array_map(function (array $user): string {
return $user['id']; return $user['shareWith'];
}, $keyValuePairs['access']['users']); }, $keyValuePairs['access']['users']);
$keyValuePairs['access']['groups'] = array_map(function (array $group): string { $keyValuePairs['access']['groups'] = array_map(function (array $group): string {
return $group['id']; return $group['shareWith'];
}, $keyValuePairs['access']['groups']); }, $keyValuePairs['access']['groups']);
} }
} catch (Exception $e) { } catch (Exception $e) {

View file

@ -234,7 +234,7 @@ class FormsService {
$user = $this->userManager->get($userId); $user = $this->userManager->get($userId);
if ($user instanceof IUser) { if ($user instanceof IUser) {
return [ return [
'id' => $userId, 'shareWith' => $userId,
'displayName' => $user->getDisplayName(), 'displayName' => $user->getDisplayName(),
'shareType' => IShare::TYPE_USER 'shareType' => IShare::TYPE_USER
]; ];
@ -252,7 +252,7 @@ class FormsService {
$group = $this->groupManager->get($groupId); $group = $this->groupManager->get($groupId);
if ($group instanceof IGroup) { if ($group instanceof IGroup) {
return [ return [
'id' => $groupId, 'shareWith' => $groupId,
'displayName' => $group->getDisplayName(), 'displayName' => $group->getDisplayName(),
'shareType' => IShare::TYPE_GROUP 'shareType' => IShare::TYPE_GROUP
]; ];

View file

@ -35,7 +35,7 @@
:searchable="true" :searchable="true"
:user-select="true" :user-select="true"
label="displayName" label="displayName"
track-by="id" track-by="shareWith"
@search-change="asyncFind" @search-change="asyncFind"
@select="addShare"> @select="addShare">
<template #noOptions> <template #noOptions>
@ -48,7 +48,7 @@
<TransitionGroup :css="false" tag="ul" class="shared-list"> <TransitionGroup :css="false" tag="ul" class="shared-list">
<!-- TODO: Iterate two times, will be cleaner, one for users, one for groups --> <!-- TODO: Iterate two times, will be cleaner, one for users, one for groups -->
<li v-for="(item, index) in sortedShares" :key="item.id + '-' + item.shareType" :data-index="index"> <li v-for="(item, index) in sortedShares" :key="item.shareWith + '-' + item.shareType" :data-index="index">
<UserDiv v-bind="item" /> <UserDiv v-bind="item" />
<div class="options"> <div class="options">
<a class="icon icon-delete svg delete-form" @click="removeShare(item)" /> <a class="icon icon-delete svg delete-form" @click="removeShare(item)" />
@ -120,13 +120,17 @@ export default {
/** /**
* Multiseelct options. Recommendations by default, * Multiseelct options. Recommendations by default,
* direct search when search query is valid. * direct search when search query is valid.
* Filter out existing shares
* @returns {Array} * @returns {Array}
*/ */
options() { options() {
const shares = [...this.userShares, ...this.groupShares]
if (this.isValidQuery) { if (this.isValidQuery) {
return this.suggestions // Filter out existing shares
return this.suggestions.filter(item => !shares.find(share => share.shareWith === item.shareWith && share.shareType === item.shareType))
} }
return this.recommendations // Filter out existing shares
return this.recommendations.filter(item => !shares.find(share => share.shareWith === item.shareWith && share.shareType === item.shareType))
}, },
noResultText() { noResultText() {
@ -144,8 +148,8 @@ export default {
methods: { methods: {
removeShare(item) { removeShare(item) {
// Filter out the removed item // Filter out the removed item
const users = this.userShares.filter(user => !(user.id === item.id && !item.isGroup)) const users = this.userShares.filter(user => !(user.shareWith === item.shareWith && item.shareType === this.SHARE_TYPES.SHARE_TYPE_USER))
const groups = this.groupShares.filter(group => !(group.id === item.id && item.isGroup)) const groups = this.groupShares.filter(group => !(group.shareWith === item.shareWith && item.shareType === this.SHARE_TYPES.SHARE_TYPE_GROUP))
this.$emit('update:shares', { users, groups }) this.$emit('update:shares', { users, groups })
}, },
@ -157,11 +161,13 @@ export default {
const users = this.userShares.slice() const users = this.userShares.slice()
const groups = this.groupShares.slice() const groups = this.groupShares.slice()
const newShare = { const newShare = {
id: share.shareWith, shareWith: share.shareWith,
displayName: share.displayName, displayName: share.displayName,
shareType: share.shareType, shareType: share.shareType,
} }
// TODO: detect if already present
if (share.shareType === this.SHARE_TYPES.SHARE_TYPE_USER) { if (share.shareType === this.SHARE_TYPES.SHARE_TYPE_USER) {
users.push(newShare) users.push(newShare)
} else if (share.shareType === this.SHARE_TYPES.SHARE_TYPE_GROUP) { } else if (share.shareType === this.SHARE_TYPES.SHARE_TYPE_GROUP) {
@ -178,7 +184,7 @@ export default {
return 0 return 0
}, },
async asyncFind(query, id) { async asyncFind(query) {
// save current query to check if we display // save current query to check if we display
// recommendations or search results // recommendations or search results
this.query = query.trim() this.query = query.trim()
@ -227,11 +233,11 @@ export default {
const rawSuggestions = Object.values(data).reduce((arr, elem) => arr.concat(elem), []) const rawSuggestions = Object.values(data).reduce((arr, elem) => arr.concat(elem), [])
// remove invalid data and format to user-select layout // remove invalid data and format to user-select layout
const exactSuggestions = this.filterOutExistingShares(rawExactSuggestions) const exactSuggestions = this.filterOutUnwantedShares(rawExactSuggestions)
.map(share => this.formatForMultiselect(share)) .map(share => this.formatForMultiselect(share))
// sort by type so we can get user&groups first... // sort by type so we can get user&groups first...
.sort((a, b) => a.shareType - b.shareType) .sort((a, b) => a.shareType - b.shareType)
const suggestions = this.filterOutExistingShares(rawSuggestions) const suggestions = this.filterOutUnwantedShares(rawSuggestions)
.map(share => this.formatForMultiselect(share)) .map(share => this.formatForMultiselect(share))
// sort by type so we can get user&groups first... // sort by type so we can get user&groups first...
.sort((a, b) => a.shareType - b.shareType) .sort((a, b) => a.shareType - b.shareType)
@ -275,7 +281,7 @@ export default {
const rawRecommendations = Object.values(exact).reduce((arr, elem) => arr.concat(elem), []) const rawRecommendations = Object.values(exact).reduce((arr, elem) => arr.concat(elem), [])
// remove invalid data and format to user-select layout // remove invalid data and format to user-select layout
this.recommendations = this.filterOutExistingShares(rawRecommendations) this.recommendations = this.filterOutUnwantedShares(rawRecommendations)
.map(share => this.formatForMultiselect(share)) .map(share => this.formatForMultiselect(share))
this.loading = false this.loading = false
@ -283,13 +289,12 @@ export default {
}, },
/** /**
* Filter out existing shares from * Filter out unwated shares
* the provided shares search results
* *
* @param {Object[]} shares the array of shares object * @param {Object[]} shares the array of shares object
* @returns {Object[]} * @returns {Object[]}
*/ */
filterOutExistingShares(shares) { filterOutUnwantedShares(shares) {
return shares.reduce((arr, share) => { return shares.reduce((arr, share) => {
// only check proper objects // only check proper objects
if (typeof share !== 'object') { if (typeof share !== 'object') {
@ -303,17 +308,6 @@ export default {
return arr return arr
} }
// Filter out existing shares
if (share.value.shareType === this.SHARE_TYPES.SHARE_TYPE_USER) {
if (this.userShares.find(user => user.id === share.value.shareWith)) {
return arr
}
} else if (share.value.shareType === this.SHARE_TYPES.SHARE_TYPE_GROUP) {
if (this.groupShares.find(group => group.id === share.value.shareWith)) {
return arr
}
}
// ALL GOOD // ALL GOOD
// let's add the suggestion // let's add the suggestion
arr.push(share) arr.push(share)
@ -337,6 +331,8 @@ export default {
isNoUser: result.value.shareType !== this.SHARE_TYPES.SHARE_TYPE_USER, isNoUser: result.value.shareType !== this.SHARE_TYPES.SHARE_TYPE_USER,
displayName: result.name || result.label, displayName: result.name || result.label,
icon: this.shareTypeToIcon(result.value.shareType), icon: this.shareTypeToIcon(result.value.shareType),
// Vue unique binding to render within Multiselect's AvatarSelectOption
key: result.uuid || result.value.shareWith + '-' + result.value.shareType + '-' + result.name || result.label,
} }
}, },

View file

@ -22,7 +22,7 @@
<template> <template>
<div class="user-row"> <div class="user-row">
<Avatar :user="id" :display-name="computedDisplayName" :is-no-user="isNoUser" /> <Avatar :user="shareWith" :display-name="computedDisplayName" :is-no-user="isNoUser" />
</div> </div>
</template> </template>
@ -37,7 +37,7 @@ export default {
mixins: [ShareTypes], mixins: [ShareTypes],
props: { props: {
id: { shareWith: {
type: String, type: String,
required: true, required: true,
}, },

View file

@ -128,7 +128,7 @@ import moment from '@nextcloud/moment'
import { subscribe, unsubscribe } from '@nextcloud/event-bus' import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { getLocale, getDayNamesShort, getMonthNamesShort } from '@nextcloud/l10n' import { getLocale, getDayNamesShort, getMonthNamesShort } from '@nextcloud/l10n'
import ShareDiv from '../components/shareDiv' import ShareDiv from '../components/ShareDiv'
import ViewsMixin from '../mixins/ViewsMixin' import ViewsMixin from '../mixins/ViewsMixin'
export default { export default {