33 - SPDX-License-Identifier: AGPL-3.0-or-later
44-->
55<template >
6- <!-- eslint-disable-next-line vue/no-v-html -->
7- <div v-if =" value" class =" table-cell-usergroup" >
8- <div v-for =" item in value" :key =" item.id" class =" inline usergroup-entry" >
9- <NcUserBubble :user =" item .id " :avatar-image =" getAvatarImage (item )" :is-no-user =" ! isUser (item )" :display-name =" item .displayName ?? item .id " :show-user-status =" isUser (item ) && column .showUserStatus " :size =" column .showUserStatus ? 34 : 20 " :primary =" isCurrentUser (item )" />
6+ <div class =" cell-usergroup" >
7+ <div v-if =" !isEditing" class =" non-edit-mode" @click =" startEditing" >
8+ <div v-if =" value" class =" table-cell-usergroup" >
9+ <div v-for =" item in value" :key =" item.id" class =" inline usergroup-entry" >
10+ <NcUserBubble :user =" item .id " :avatar-image =" getAvatarImage (item )" :is-no-user =" ! isUser (item )" :display-name =" item .displayName ?? item .id " :show-user-status =" isUser (item ) && column .showUserStatus " :size =" column .showUserStatus ? 34 : 20 " :primary =" isCurrentUser (item )" />
11+ </div >
12+ </div >
13+ </div >
14+ <div v-else
15+ ref =" editingContainer"
16+ class =" edit-mode"
17+ tabindex =" 0"
18+ @keydown.enter =" saveChanges"
19+ @keydown.escape =" cancelEdit" >
20+ <NcSelect v-model =" editValue "
21+ style =" width : 100% ;"
22+ :loading =" loading || localLoading "
23+ :options =" options "
24+ :placeholder =" getPlaceholder ()"
25+ :searchable =" true "
26+ :get-option-key =" (option ) => option .key "
27+ label="displayName"
28+ :aria-label-combobox =" getPlaceholder ()"
29+ :user-select =" true "
30+ :close-on-select =" false "
31+ :multiple =" column .usergroupMultipleItems "
32+ data-cy="usergroupCellSelect"
33+ @search =" asyncFind " >
34+ <template #noResult >
35+ {{ noResultText }}
36+ </template >
37+ </NcSelect >
38+ <div v-if =" localLoading" class =" loading-indicator" >
39+ <div class =" icon-loading-small icon-loading-inline" />
40+ </div >
1041 </div >
1142 </div >
1243</template >
1344
1445<script >
1546import { getCurrentUser } from ' @nextcloud/auth'
16- import { NcUserBubble } from ' @nextcloud/vue'
47+ import { NcUserBubble , NcSelect } from ' @nextcloud/vue'
1748import { USERGROUP_TYPE } from ' ../../../constants.ts'
49+ import cellEditMixin from ' ../mixins/cellEditMixin.js'
50+ import searchUserGroup from ' ../../../mixins/searchUserGroup.js'
51+ import ShareTypes from ' ../../../mixins/shareTypesMixin.js'
52+ import { translate as t } from ' @nextcloud/l10n'
1853
1954const currentUser = getCurrentUser ()
2055
2156export default {
2257 name: ' TableCellUsergroup' ,
58+
2359 components: {
2460 NcUserBubble,
61+ NcSelect,
2562 },
63+
64+ mixins: [
65+ cellEditMixin,
66+ searchUserGroup,
67+ ShareTypes,
68+ ],
69+
2670 props: {
2771 column: {
2872 type: Object ,
@@ -37,6 +81,16 @@ export default {
3781 default : () => [],
3882 },
3983 },
84+
85+ data () {
86+ return {
87+ editValue: [],
88+ selectUsers: this .column ? .usergroupSelectUsers ?? true ,
89+ selectGroups: this .column ? .usergroupSelectGroups ?? false ,
90+ selectCircles: false ,
91+ }
92+ },
93+
4094 computed: {
4195 isCurrentUser () {
4296 return (item ) => this .isUser (item) && item .id === currentUser? .uid
@@ -45,7 +99,32 @@ export default {
4599 return (item ) => item .type === USERGROUP_TYPE .USER
46100 },
47101 },
102+
103+ watch: {
104+ isEditing (isEditing ) {
105+ if (isEditing) {
106+ this .editValue = this .value ? [... this .value ] : []
107+
108+ // Use a small delay to prevent the same click event that triggered editing
109+ // from immediately triggering the click outside handler
110+ this .$nextTick (() => {
111+ setTimeout (() => {
112+ document .addEventListener (' click' , this .handleClickOutside )
113+ }, 10 )
114+ })
115+ } else {
116+ document .removeEventListener (' click' , this .handleClickOutside )
117+ }
118+ },
119+ },
120+
121+ created () {
122+ this .selectCircles = this .isCirclesEnabled ? this .column ? .usergroupSelectTeams ?? false : false
123+ },
124+
48125 methods: {
126+ t,
127+
49128 getAvatarImage (item ) {
50129 if (item .type === USERGROUP_TYPE .GROUP ) {
51130 return ' icon-group'
@@ -55,18 +134,74 @@ export default {
55134 }
56135 return ' '
57136 },
137+
138+ formatResult (autocompleteResult ) {
139+ return {
140+ id: autocompleteResult .id ,
141+ type: this .getType (autocompleteResult .source ),
142+ key: autocompleteResult .source + ' -' + autocompleteResult .id ,
143+ displayName: autocompleteResult .label ,
144+ }
145+ },
146+
147+ filterOutUnwantedItems (list ) {
148+ return list
149+ },
150+
151+ async saveChanges () {
152+ if (this .localLoading ) {
153+ return
154+ }
155+
156+ let newValue = ! Array .isArray (this .editValue ) ? [this .editValue ] : this .editValue
157+ // If the column does not allow multiple items, limit to one item
158+ // in case we switched from multiple to single selection
159+ if (! this .column .usergroupMultipleItems ) {
160+ newValue = newValue .slice (0 , 1 )
161+ }
162+ const success = await this .updateCellValue (newValue)
163+
164+ if (! success) {
165+ this .cancelEdit ()
166+ }
167+
168+ this .localLoading = false
169+ this .isEditing = false
170+ },
171+
172+ handleClickOutside (event ) {
173+ if (this .$refs .editingContainer && ! this .$refs .editingContainer .contains (event .target )) {
174+ this .saveChanges ()
175+ }
176+ },
58177 },
59178}
60179< / script>
61180
62181< style lang= " scss" scoped>
63- .table - cell- usergroup {
64- display: flex;
65- flex- wrap: wrap;
66- padding: 10px ;
182+ .cell - usergroup {
183+ width: 100 % ;
184+
185+ .non - edit- mode {
186+ cursor: pointer;
67187 }
188+ }
189+
190+ .table - cell- usergroup {
191+ display: flex;
192+ flex- wrap: wrap;
193+ padding: 10px ;
194+ }
195+
196+ .usergroup - entry {
197+ padding- right: 10px ;
198+ }
68199
69- .usergroup - entry {
70- padding- right: 10px ;
200+ .edit - mode {
201+ padding: 10px 0 ;
202+
203+ .icon - loading- inline {
204+ margin- left: 4px ;
71205 }
206+ }
72207< / style>
0 commit comments