Skip to content

Commit 09078ce

Browse files
committed
feat: Inline editing - usergroup
Signed-off-by: Enjeck C. <patrathewhiz@gmail.com>
1 parent 288b4f9 commit 09078ce

2 files changed

Lines changed: 146 additions & 12 deletions

File tree

src/shared/components/ncTable/partials/TableCellUsergroup.vue

Lines changed: 146 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,70 @@
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>
1546
import { getCurrentUser } from '@nextcloud/auth'
16-
import { NcUserBubble } from '@nextcloud/vue'
47+
import { NcUserBubble, NcSelect } from '@nextcloud/vue'
1748
import { 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
1954
const currentUser = getCurrentUser()
2055
2156
export 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>

src/shared/components/ncTable/partials/TableRow.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ export default {
112112
nonInlineEditableColumnTypes() {
113113
return [
114114
ColumnTypes.TextRich,
115-
ColumnTypes.Usergroup,
116115
ColumnTypes.SelectionMulti,
117116
ColumnTypes.TextLink,
118117
ColumnTypes.NumberStars,

0 commit comments

Comments
 (0)