Skip to content

Commit 8ddd4d9

Browse files
committed
refactor: use autocomplete for user search
Signed-off-by: grnd-alt <git@belakkaf.net>
1 parent db1a648 commit 8ddd4d9

6 files changed

Lines changed: 53 additions & 70 deletions

File tree

cypress/support/commands.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ Cypress.Commands.add('getNavigationEntry', (boardTitle) => {
9999
})
100100

101101
Cypress.Commands.add('shareBoardWithUi', (query, userId=query) => {
102-
cy.intercept({ method: 'GET', url: `**/ocs/v2.php/apps/files_sharing/api/v1/sharees?search=${query}*` }).as('fetchRecipients')
102+
cy.intercept({ method: 'GET', url: `**/ocs/v2.php/core/autocomplete/get?search=${query}*` }).as('fetchRecipients')
103103
cy.get('[aria-label="Open details"]').click()
104104
cy.get('.app-sidebar').should('be.visible')
105105

lib/Db/BoardMapper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ public function mapAcl(Acl &$acl): void {
524524
return null;
525525
}
526526
if ($acl->getType() === Acl::PERMISSION_TYPE_REMOTE) {
527-
return null;
527+
return new FederatedUser($this->cloudIdManager->resolveCloudId($acl->getParticipant()));
528528
}
529529
$this->logger->warning('Unknown permission type for mapping acl ' . $acl->getId());
530530
return null;

lib/Federation/DeckFederationProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public function notificationReceived($notificationType, $providerId, $notificati
8181
if (!isset($localBoard)) {
8282
throw new NotFoundException('Board not found for provider ID: ' . $providerId);
8383
}
84-
$localParticipant = $this->cloudIdManager->resolveCloudId($notification[0]['participant'])->getUser();
84+
$localParticipant = $this->cloudIdManager->resolveCloudId($notification[0]['participant']['uid'])->getUser();
8585
$acls = $this->aclMapper->findAll($localBoard->getId());
8686
foreach ($acls as $acl) {
8787
if ($acl->getParticipant() === $localParticipant) {

lib/Service/BoardService.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
use OCP\DB\Exception as DbException;
4242
use OCP\EventDispatcher\IEventDispatcher;
4343
use OCP\Federation\ICloudFederationFactory;
44-
use OCP\Federation\ICloudFederationNotification;
4544
use OCP\Federation\ICloudFederationProviderManager;
4645
use OCP\Federation\ICloudIdManager;
4746
use OCP\IConfig;
@@ -448,9 +447,6 @@ public function updateAcl(int $id, bool $edit, bool $share, bool $manage): Acl {
448447
if ($acl->getType() === Acl::PERMISSION_TYPE_REMOTE) {
449448
$this->configService->ensureFederationEnabled();
450449
$notification = $this->federationFactory->getCloudFederationNotification();
451-
if (!$notification instanceof ICloudFederationNotification) {
452-
throw new \InvalidArgumentException('Invalid notification type');
453-
}
454450

455451
$payload = [
456452
$acl->jsonSerialize(),

src/components/board/SharingTabSidebar.vue

Lines changed: 42 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,10 @@
44
-->
55
<template>
66
<div>
7-
<NcSelect v-if="canShare"
8-
v-model="addAcl"
9-
:input-label="t('deck', 'Share board with a user, group or team …')"
7+
<NcSelectUsers v-model="addAcl"
108
:options="formatedSharees"
11-
:user-select="true"
12-
label="displayName"
13-
:loading="isLoading || !!isSearching"
14-
:disabled="isLoading"
15-
track-by="multiselectKey"
16-
:internal-search="false"
17-
@input="clickAddAcl"
18-
@search="(search, loading) => asyncFind(search, loading)">
19-
<template #noOptions>
20-
{{ isSearching ? t('deck', 'Searching for users, groups and teams …') : t('deck', 'No participants found') }}
21-
</template>
22-
<template #noResult>
23-
{{ isSearching ? t('deck', 'Searching for users, groups and teams …') : t('deck', 'No participants found') }}
24-
</template>
25-
</NcSelect>
9+
:loading="isLoading"
10+
@search="(search) => asyncFind(search)" />
2611

2712
<ul id="shareWithList"
2813
class="shareWithList">
@@ -94,12 +79,19 @@
9479
</template>
9580

9681
<script>
97-
import { NcCollectionList, NcAvatar, NcSelect, NcActions, NcActionButton, NcActionCheckbox, NcRelatedResourcesPanel } from '@nextcloud/vue'
82+
import { NcCollectionList, NcAvatar, NcActions, NcActionButton, NcActionCheckbox, NcRelatedResourcesPanel, NcSelectUsers } from '@nextcloud/vue'
9883
import { mapGetters, mapState } from 'vuex'
9984
import { getCurrentUser } from '@nextcloud/auth'
10085
import { showError, showSuccess } from '@nextcloud/dialogs'
10186
import { loadState } from '@nextcloud/initial-state'
10287
import debounce from 'lodash/debounce.js'
88+
const SOURCE_TO_SHARE_TYPE = {
89+
users: 0,
90+
groups: 1,
91+
emails: 4,
92+
remotes: 6,
93+
teams: 7,
94+
}
10395
10496
export default {
10597
name: 'SharingTabSidebar',
@@ -108,7 +100,7 @@ export default {
108100
NcActions,
109101
NcActionButton,
110102
NcActionCheckbox,
111-
NcSelect,
103+
NcSelectUsers,
112104
NcCollectionList,
113105
NcRelatedResourcesPanel,
114106
},
@@ -141,35 +133,28 @@ export default {
141133
return (uid) => uid === getCurrentUser().uid
142134
},
143135
formatedSharees() {
144-
return this.unallocatedSharees.map(item => {
145-
const subname = item.label === item.shareWithDisplayNameUnique
146-
? ''
147-
: item.shareWithDisplayNameUnique
148-
const sharee = {
149-
user: item.value.shareWith,
150-
displayName: item.label,
151-
subname,
152-
icon: 'icon-user',
153-
multiselectKey: item.shareType + ':' + item.primaryKey,
154-
}
155-
156-
if (item.value.shareType === 1) {
157-
sharee.icon = 'icon-group'
158-
sharee.isNoUser = true
136+
const result = this.unallocatedSharees.map(item => {
137+
const res = {
138+
...item,
139+
displayName: item.displayname || item.name || item.label || item.id,
140+
user: item.id,
141+
subname: item.shareWithDisplayNameUnique || item.subline, // NcSelectUser does its own pattern matching to filter things out
159142
}
160-
if (item.value.shareType === 7) {
161-
sharee.icon = 'icon-circles'
162-
sharee.isNoUser = true
163-
}
164-
165-
sharee.value = item.value
166-
return sharee
143+
return res
167144
}).slice(0, 10)
145+
return result
168146
},
169147
unallocatedSharees() {
170148
return this.sharees.filter((sharee) => {
171149
const foundIndex = this.board.acl.findIndex((acl) => {
172-
return acl.participant.uid === sharee.value.shareWith && acl.participant.type === sharee.value.shareType
150+
console.debug()
151+
if (acl.participant.uid === sharee.id && acl.type === SOURCE_TO_SHARE_TYPE[sharee.source]) {
152+
return true
153+
}
154+
if (acl.participant.id === sharee.id && acl.type === SOURCE_TO_SHARE_TYPE[sharee.source]) {
155+
return true
156+
}
157+
return false
173158
})
174159
if (foundIndex === -1) {
175160
return true
@@ -178,6 +163,15 @@ export default {
178163
})
179164
},
180165
},
166+
watch: {
167+
addAcl: {
168+
handler() {
169+
if (this.addAcl) {
170+
this.clickAddAcl()
171+
}
172+
},
173+
},
174+
},
181175
mounted() {
182176
this.asyncFind('', () => {})
183177
},
@@ -187,15 +181,15 @@ export default {
187181
await this.$store.dispatch('loadSharees', query)
188182
this.isSearching = false
189183
}, 300),
190-
async asyncFind(query, loading) {
191-
loading(true)
184+
async asyncFind(query) {
185+
this.isLoading = true
192186
await this.debouncedFind(query)
193-
loading(false)
187+
this.isLoading = false
194188
},
195189
async clickAddAcl() {
196190
this.addAclForAPI = {
197-
type: this.addAcl.value.shareType,
198-
participant: this.addAcl.value.shareWith,
191+
type: SOURCE_TO_SHARE_TYPE[this.addAcl.source],
192+
participant: this.addAcl.id,
199193
permissionEdit: false,
200194
permissionShare: false,
201195
permissionManage: false,

src/store/main.js

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,7 @@ export default function storeFactory() {
238238
state.boards = boards
239239
},
240240
setSharees(state, shareesUsersAndGroups) {
241-
Vue.set(state, 'sharees', shareesUsersAndGroups.exact.users)
242-
state.sharees.push(...shareesUsersAndGroups.exact.groups)
243-
state.sharees.push(...shareesUsersAndGroups.exact.circles)
244-
245-
state.sharees.push(...shareesUsersAndGroups.users)
246-
state.sharees.push(...shareesUsersAndGroups.groups)
247-
state.sharees.push(...shareesUsersAndGroups.circles)
248-
state.sharees.push(...shareesUsersAndGroups.remotes)
241+
Vue.set(state, 'sharees', shareesUsersAndGroups)
249242
},
250243
setAssignableUsers(state, users) {
251244
state.assignableUsers = users
@@ -434,17 +427,17 @@ export default function storeFactory() {
434427
commit('setBoards', boards)
435428
},
436429
async loadSharees({ commit }, query) {
437-
const params = new URLSearchParams()
438430
if (typeof query === 'undefined') {
439431
return
440432
}
441-
params.append('search', query)
442-
params.append('format', 'json')
443-
params.append('perPage', 20)
444-
params.append('itemType', 'deck')
445-
params.append('lookup', false)
433+
const params = {
434+
search: query,
435+
itemType: 'deck',
436+
shareTypes: [0, 1, 4, 6, 7],
437+
limit: 20,
438+
}
446439

447-
const response = await axios.get(generateOcsUrl('apps/files_sharing/api/v1/sharees'), { params })
440+
const response = await axios.get(generateOcsUrl('/core/autocomplete/get'), { params })
448441
commit('setSharees', response.data.ocs.data)
449442
},
450443

0 commit comments

Comments
 (0)