@ -24,31 +24,30 @@
-- >
< template >
< Fragment >
< tr class = "user-list__row"
: data - test = "user.id" >
< td class = "row__cell row__cell--avatar" >
< NcLoadingIcon v -if = " isLoadingUser "
: name = "t('settings', 'Loading user …')"
: size = "32" / >
< NcAvatar v -else
: key = "user.id"
< NcAvatar v -else -if = " visible "
disable - menu
: show - user - status = "false"
: user = "user.id" / >
< / td >
< td class = "row__cell row__cell--displayname"
: data - test = "user.id" >
< template v-if ="idState.editing && user.backendCapabilities.setDisplayName" >
< td class = "row__cell row__cell--displayname" >
< template v-if ="editing && user.backendCapabilities.setDisplayName" >
< NcTextField ref = "displayNameField"
data - test = "displayNameField"
class = "user-row-text-field"
: trailing - button - label = "t('settings', 'Submit')"
: class = "{ 'icon-loading-small': idState. loading.displayName }"
: class = "{ 'icon-loading-small': loading.displayName }"
: show - trailing - button = "true"
: disabled = " idState. loading.displayName || isLoadingField"
: disabled = " loading.displayName || isLoadingField"
: label = "t('settings', 'Change display name')"
trailing - button - icon = "arrowRight"
: value . sync = " idState. editedDisplayName"
: value . sync = " editedDisplayName"
autocapitalize = "off"
autocomplete = "off"
autocorrect = "off"
@ -66,17 +65,17 @@
< td class = "row__cell"
: class = "{ 'row__cell--obfuscated': hasObfuscated }" >
< template v-if =" idState. editing && settings.canChangePassword && user.backendCapabilities.setPassword">
< template v-if =" editing && settings.canChangePassword && user.backendCapabilities.setPassword">
< NcTextField class = "user-row-text-field"
: class = "{'icon-loading-small': idState.loading.password}"
: trailing - button - label = "t('settings', 'Submit')"
: class = "{'icon-loading-small': loading.password}"
: show - trailing - button = "true"
: disabled = " idState. loading.password || isLoadingField"
: disabled = " loading.password || isLoadingField"
: minlength = "minPasswordLength"
maxlength = "469"
: label = "t('settings', 'Set new password')"
trailing - button - icon = "arrowRight"
: value . sync = " idState. editedPassword"
: value . sync = " editedPassword"
autocapitalize = "off"
autocomplete = "new-password"
autocorrect = "off"
@ -91,15 +90,15 @@
< / td >
< td class = "row__cell" >
< template v-if =" idState. editing">
< template v-if =" editing">
< NcTextField class = "user-row-text-field"
: class = "{'icon-loading-small': idState. loading.mailAddress}"
: class = "{'icon-loading-small': loading.mailAddress}"
: show - trailing - button = "true"
: trailing - button - label = "t('settings', 'Submit')"
: disabled = "idState.loading.mailAddress || isLoadingField"
: label = "t('settings', 'Set new email address')"
: disabled = "loading.mailAddress || isLoadingField"
trailing - button - icon = "arrowRight"
: value . sync = " idState. editedMail"
: value . sync = " editedMail"
autocapitalize = "off"
autocomplete = "new-password"
autocorrect = "off"
@ -114,7 +113,7 @@
< / td >
< td class = "row__cell row__cell--large row__cell--multiline" >
< template v-if =" idState. editing">
< template v-if =" editing">
< label class = "hidden-visually"
: for = "'groups' + uniqueId" >
{ { t ( 'settings' , 'Add user to group' ) } }
@ -122,13 +121,12 @@
< NcSelect : input -id = " ' groups ' + uniqueId "
: close - on - select = "false"
: disabled = "isLoadingField"
: loading = " idState. loading.groups"
: loading = " loading.groups"
: multiple = "true"
: options = "availableGroups"
: placeholder = "t('settings', 'Add user to group')"
: taggable = "settings.isAdmin"
: value = "userGroups"
class = "select-vue"
label = "name"
: no - wrap = "true"
: create - option = "(value) => ({ name: value, isCreating: true })"
@ -144,7 +142,7 @@
< td v -if = " subAdminsGroups.length > 0 && settings . isAdmin "
class = "row__cell row__cell--large row__cell--multiline" >
< template v-if =" idState. editing && settings.isAdmin && subAdminsGroups.length > 0">
< template v-if =" editing && settings.isAdmin && subAdminsGroups.length > 0">
< label class = "hidden-visually"
: for = "'subadmins' + uniqueId" >
{ { t ( 'settings' , 'Set user as admin for' ) } }
@ -152,14 +150,13 @@
< NcSelect : id = "'subadmins' + uniqueId"
: close - on - select = "false"
: disabled = "isLoadingField"
: loading = " idState. loading.subadmins"
: loading = " loading.subadmins"
label = "name"
: multiple = "true"
: no - wrap = "true"
: options = "subAdminsGroups"
: placeholder = "t('settings', 'Set user as admin for')"
: value = "userSubAdminsGroups"
class = "select-vue"
@ option : deselected = "removeUserSubAdmin"
@ option : selected = "options => addUserSubAdmin(options.at(-1))" / >
< / template >
@ -170,7 +167,7 @@
< / td >
< td class = "row__cell" >
< template v-if =" idState. editing">
< template v-if =" editing">
< label class = "hidden-visually"
: for = "'quota' + uniqueId" >
{ { t ( 'settings' , 'Select user quota' ) } }
@ -179,10 +176,9 @@
: close - on - select = "true"
: create - option = "validateQuota"
: disabled = "isLoadingField"
: loading = " idState. loading.quota"
: loading = " loading.quota"
: clearable = "false"
: input - id = "'quota' + uniqueId"
class = "select-vue"
: options = "quotaOptions"
: placeholder = "t('settings', 'Select user quota')"
: taggable = "true"
@ -202,7 +198,7 @@
< td v -if = " showConfig.showLanguages "
class = "row__cell row__cell--large"
data - test = "language" >
< template v-if =" idState. editing">
< template v-if =" editing">
< label class = "hidden-visually"
: for = "'language' + uniqueId" >
{ { t ( 'settings' , 'Set the language' ) } }
@ -210,13 +206,12 @@
< NcSelect : id = "'language' + uniqueId"
: allow - empty = "false"
: disabled = "isLoadingField"
: loading = " idState. loading.languages"
: loading = " loading.languages"
: clearable = "false"
: options = "availableLanguages"
: placeholder = "t('settings', 'No language set')"
: value = "userLanguage"
label = "name"
class = "select-vue"
@ input = "setUserLanguage" / >
< / template >
< span v -else -if = " ! isObfuscated " >
@ -243,21 +238,21 @@
< span v-if ="!isObfuscated" > {{ userLastLogin }} < / span >
< / td >
< td class = "row__cell row__cell--large ">
< template v-if =" idState. editing">
< td class = "row__cell row__cell--large row__cell--fill ">
< template v-if =" editing">
< label class = "hidden-visually"
: for = "'manager' + uniqueId" >
{ { managerLabel } }
< / label >
< NcSelect v -model = " idState.currentManager "
< NcSelect v -model = " currentManager "
class = "select--fill"
: input - id = "'manager' + uniqueId"
: close - on - select = "true"
: disabled = "isLoadingField"
: loading = " idState. loadingPossibleManagers || idState. loading.manager"
: loading = " loadingPossibleManagers || loading.manager"
label = "displayname"
: options = " idState. possibleManagers"
: options = " possibleManagers"
: placeholder = "managerLabel"
class = "select-vue"
@ open = "searchInitialUserManager"
@ search = "searchUserManager"
@ option : selected = "updateUserManager"
@ -269,18 +264,16 @@
< / td >
< td class = "row__cell row__cell--actions" >
< UserRowActions v -if = " ! isObfuscated & & canEdit & & ! idState. loading.all"
< UserRowActions v -if = " visible & & ! isObfuscated & & canEdit & & ! loading.all"
: actions = "userActions"
: disabled = "isLoadingField"
: edit = " idState. editing"
: edit = " editing"
@ update : edit = "toggleEdit" / >
< / td >
< / Fragmen t>
< / tr >
< / template >
< script >
import { Fragment } from 'vue-frag'
import { IdState } from 'vue-virtual-scroller'
import { getCurrentUser } from '@nextcloud/auth'
import { showSuccess , showError } from '@nextcloud/dialogs'
@ -299,7 +292,6 @@ export default {
name : 'UserRow' ,
components : {
Fragment ,
NcAvatar ,
NcLoadingIcon ,
NcProgressBar ,
@ -309,14 +301,6 @@ export default {
} ,
mixins : [
/ * *
* Use scoped ` idState ` instead of ` data ` which is reused between rows
*
* See https : / / g i t h u b . c o m / A k r y u m / v u e - v i r t u a l - s c r o l l e r / t r e e / v 1 / p a c k a g e s / v u e - v i r t u a l - s c r o l l e r # w h y - i s - t h i s - u s e f u l
* /
IdState ( {
idProp : vm => vm . user . id ,
} ) ,
UserRowMixin ,
] ,
@ -325,6 +309,10 @@ export default {
type : Object ,
required : true ,
} ,
visible : {
type : Boolean ,
required : true ,
} ,
users : {
type : Array ,
required : true ,
@ -359,7 +347,7 @@ export default {
} ,
} ,
idState ( ) {
data ( ) {
return {
selectedQuota : false ,
rand : Math . random ( ) . toString ( 36 ) . substring ( 2 ) ,
@ -402,15 +390,15 @@ export default {
} ,
isLoadingUser ( ) {
return this . idState. loading. delete || this . idState. loading. disable || this . idState . loading . wipe
return this . loading. delete || this . loading. disable || this . loading . wipe
} ,
isLoadingField ( ) {
return this . idState. loading. delete || this . idState. loading. disable || this . idState . loading . all
return this . loading. delete || this . loading. disable || this . loading . all
} ,
uniqueId ( ) {
return this . user . id + this . idState. rand
return this . user . id + this . rand
} ,
userGroupsLabels ( ) {
@ -487,8 +475,8 @@ export default {
/ / m a p p i n g s a v e d v a l u e s t o o b j e c t s
editedUserQuota : {
get ( ) {
if ( this . idState. selectedQuota !== false ) {
return this . idState. selectedQuota
if ( this . selectedQuota !== false ) {
return this . selectedQuota
}
if ( this . settings . defaultQuota !== unlimitedQuota . id && OC . Util . computerFileSize ( this . settings . defaultQuota ) >= 0 ) {
/ / i f v a l u e i s v a l i d , l e t ' s m a p t h e q u o t a O p t i o n s o r r e t u r n c u s t o m q u o t a
@ -497,7 +485,7 @@ export default {
return unlimitedQuota / / u n l i m i t e d
} ,
set ( quota ) {
this . idState. selectedQuota = quota
this . selectedQuota = quota
} ,
} ,
@ -510,10 +498,6 @@ export default {
if ( this . user . manager ) {
await this . initManager ( this . user . manager )
}
/ / R e s e t l o a d i n g s t a t e b e f o r e m o u n t i n g t h e c o m p o n e n t .
/ / T h i s i s u s e f u l w h e n w e d i s a b l e a u s e r a s t h e l o a d i n g s t a t e c a n n o t b e p r o p e r l y r e s e t u p o n p r o m i s e r e s o l u t i o n .
Object . keys ( this . idState . loading ) . forEach ( key => ( this . idState . loading [ key ] = false ) )
} ,
methods : {
@ -530,13 +514,13 @@ export default {
} ,
( result ) => {
if ( result ) {
this . idState. loading. wipe = true
this . idState. loading. all = true
this . loading. wipe = true
this . loading. all = true
this . $store . dispatch ( 'wipeUserDevices' , userid )
. then ( ( ) => showSuccess ( t ( 'settings' , 'Wiped {userid}\'s devices' , { userid } ) ) , { timeout : 2000 } )
. finally ( ( ) => {
this . idState. loading. wipe = false
this . idState. loading. all = false
this . loading. wipe = false
this . loading. all = false
} )
}
} ,
@ -550,42 +534,42 @@ export default {
async initManager ( userId ) {
await this . $store . dispatch ( 'getUser' , userId ) . then ( response => {
this . idState. currentManager = response ? . data . ocs . data
this . currentManager = response ? . data . ocs . data
} )
} ,
async searchInitialUserManager ( ) {
this . idState. loadingPossibleManagers = true
this . loadingPossibleManagers = true
await this . searchUserManager ( )
this . idState. loadingPossibleManagers = false
this . loadingPossibleManagers = false
} ,
async searchUserManager ( query ) {
await this . $store . dispatch ( 'searchUsers' , { offset : 0 , limit : 10 , search : query } ) . then ( response => {
const users = response ? . data ? this . filterManagers ( Object . values ( response ? . data . ocs . data . users ) ) : [ ]
if ( users . length > 0 ) {
this . idState. possibleManagers = users
this . possibleManagers = users
}
} )
} ,
async updateUserManager ( manager ) {
if ( manager === null ) {
this . idState. currentManager = ''
this . currentManager = ''
}
this . idState. loading. manager = true
this . loading. manager = true
try {
await this . $store . dispatch ( 'setUserData' , {
userid : this . user . id ,
key : 'manager' ,
value : this . idState. currentManager ? this . idState . currentManager . id : '' ,
value : this . currentManager ? this . currentManager . id : '' ,
} )
} catch ( error ) {
/ / T R A N S L A T O R S T h i s s t r i n g d e s c r i b e s a m a n a g e r i n t h e c o n t e x t o f a n o r g a n i z a t i o n
showError ( t ( 'setting' , 'Failed to update user manager' ) )
console . error ( error )
} finally {
this . idState. loading. manager = false
this . loading. manager = false
}
} ,
@ -602,12 +586,12 @@ export default {
} ,
( result ) => {
if ( result ) {
this . idState. loading. delete = true
this . idState. loading. all = true
this . loading. delete = true
this . loading. all = true
return this . $store . dispatch ( 'deleteUser' , userid )
. then ( ( ) => {
this . idState. loading. delete = false
this . idState. loading. all = false
this . loading. delete = false
this . loading. all = false
} )
}
} ,
@ -616,8 +600,8 @@ export default {
} ,
enableDisableUser ( ) {
this . idState. loading. delete = true
this . idState. loading. all = true
this . loading. delete = true
this . loading. all = true
const userid = this . user . id
const enabled = ! this . user . enabled
return this . $store . dispatch ( 'enableDisableUser' , {
@ -625,8 +609,8 @@ export default {
enabled ,
} )
. then ( ( ) => {
this . idState. loading. delete = false
this . idState. loading. all = false
this . loading. delete = false
this . loading. all = false
} )
} ,
@ -636,14 +620,14 @@ export default {
* @ param { string } displayName The display name
* /
updateDisplayName ( ) {
this . idState. loading. displayName = true
this . loading. displayName = true
this . $store . dispatch ( 'setUserData' , {
userid : this . user . id ,
key : 'displayname' ,
value : this . idState. editedDisplayName,
value : this . editedDisplayName,
} ) . then ( ( ) => {
this . idState. loading. displayName = false
if ( this . idState. editedDisplayName === this . user . displayname ) {
this . loading. displayName = false
if ( this . editedDisplayName === this . user . displayname ) {
showSuccess ( t ( 'setting' , 'Display name was successfully changed' ) )
}
} )
@ -655,18 +639,18 @@ export default {
* @ param { string } password The email address
* /
updatePassword ( ) {
this . idState. loading. password = true
if ( this . idState. editedPassword. length === 0 ) {
this . loading. password = true
if ( this . editedPassword. length === 0 ) {
showError ( t ( 'setting' , "Password can't be empty" ) )
this . idState. loading. password = false
this . loading. password = false
} else {
this . $store . dispatch ( 'setUserData' , {
userid : this . user . id ,
key : 'password' ,
value : this . idState. editedPassword,
value : this . editedPassword,
} ) . then ( ( ) => {
this . idState. loading. password = false
this . idState. editedPassword = ''
this . loading. password = false
this . editedPassword = ''
showSuccess ( t ( 'setting' , 'Password was successfully changed' ) )
} )
}
@ -678,19 +662,19 @@ export default {
* @ param { string } mailAddress The email address
* /
updateEmail ( ) {
this . idState. loading. mailAddress = true
if ( this . idState. editedMail === '' ) {
this . loading. mailAddress = true
if ( this . editedMail === '' ) {
showError ( t ( 'setting' , "Email can't be empty" ) )
this . idState. loading. mailAddress = false
this . idState. editedMail = this . user . email
this . loading. mailAddress = false
this . editedMail = this . user . email
} else {
this . $store . dispatch ( 'setUserData' , {
userid : this . user . id ,
key : 'email' ,
value : this . idState. editedMail,
value : this . editedMail,
} ) . then ( ( ) => {
this . idState. loading. mailAddress = false
if ( this . idState. editedMail === this . user . email ) {
this . loading. mailAddress = false
if ( this . editedMail === this . user . email ) {
showSuccess ( t ( 'setting' , 'Email was successfully changed' ) )
}
} )
@ -703,7 +687,7 @@ export default {
* @ param { string } gid Group id
* /
async createGroup ( { name : gid } ) {
this . idState. loading = { groups : true , subadmins : true }
this . loading = { groups : true , subadmins : true }
try {
await this . $store . dispatch ( 'addGroup' , gid )
const userid = this . user . id
@ -711,7 +695,7 @@ export default {
} catch ( error ) {
console . error ( error )
} finally {
this . idState. loading = { groups : false , subadmins : false }
this . loading = { groups : false , subadmins : false }
}
return this . $store . getters . getGroups [ this . groups . length ]
} ,
@ -727,7 +711,7 @@ export default {
/ / I g n o r e
return
}
this . idState. loading. groups = true
this . loading. groups = true
const userid = this . user . id
const gid = group . id
if ( group . canAdd === false ) {
@ -738,7 +722,7 @@ export default {
} catch ( error ) {
console . error ( error )
} finally {
this . idState. loading. groups = false
this . loading. groups = false
}
} ,
@ -751,7 +735,7 @@ export default {
if ( group . canRemove === false ) {
return false
}
this . idState. loading. groups = true
this . loading. groups = true
const userid = this . user . id
const gid = group . id
try {
@ -759,13 +743,13 @@ export default {
userid ,
gid ,
} )
this . idState. loading. groups = false
this . loading. groups = false
/ / r e m o v e u s e r f r o m c u r r e n t l i s t i f c u r r e n t l i s t i s t h e r e m o v e d g r o u p
if ( this . $route . params . selectedGroup === gid ) {
this . $store . commit ( 'deleteUser' , userid )
}
} catch {
this . idState. loading. groups = false
this . loading. groups = false
}
} ,
@ -775,7 +759,7 @@ export default {
* @ param { object } group Group object
* /
async addUserSubAdmin ( group ) {
this . idState. loading. subadmins = true
this . loading. subadmins = true
const userid = this . user . id
const gid = group . id
try {
@ -783,7 +767,7 @@ export default {
userid ,
gid ,
} )
this . idState. loading. subadmins = false
this . loading. subadmins = false
} catch ( error ) {
console . error ( error )
}
@ -795,7 +779,7 @@ export default {
* @ param { object } group Group object
* /
async removeUserSubAdmin ( group ) {
this . idState. loading. subadmins = true
this . loading. subadmins = true
const userid = this . user . id
const gid = group . id
@ -807,7 +791,7 @@ export default {
} catch ( error ) {
console . error ( error )
} finally {
this . idState. loading. subadmins = false
this . loading. subadmins = false
}
} ,
@ -822,7 +806,7 @@ export default {
if ( quota === 'none' ) {
quota = unlimitedQuota
}
this . idState. loading. quota = true
this . loading. quota = true
/ / e n s u r e w e o n l y s e n d t h e p r e s e t i d
quota = quota . id ? quota . id : quota
@ -835,7 +819,7 @@ export default {
} catch ( error ) {
console . error ( error )
} finally {
this . idState. loading. quota = false
this . loading. quota = false
}
return quota
} ,
@ -868,7 +852,7 @@ export default {
* @ return { object }
* /
async setUserLanguage ( lang ) {
this . idState. loading. languages = true
this . loading. languages = true
/ / e n s u r e w e o n l y s e n d t h e p r e s e t i d
try {
await this . $store . dispatch ( 'setUserData' , {
@ -876,7 +860,7 @@ export default {
key : 'language' ,
value : lang . code ,
} )
this . idState. loading. languages = false
this . loading. languages = false
} catch ( error ) {
console . error ( error )
}
@ -887,24 +871,24 @@ export default {
* Dispatch new welcome mail request
* /
sendWelcomeMail ( ) {
this . idState. loading. all = true
this . loading. all = true
this . $store . dispatch ( 'sendWelcomeMail' , this . user . id )
. then ( ( ) => showSuccess ( t ( 'setting' , 'Welcome mail sent!' ) , { timeout : 2000 } ) )
. finally ( ( ) => {
this . idState. loading. all = false
this . loading. all = false
} )
} ,
async toggleEdit ( ) {
this . idState. editing = ! this . idState . editing
if ( this . idState. editing) {
this . editing = ! this . editing
if ( this . editing) {
await this . $nextTick ( )
this . $refs . displayNameField ? . $refs ? . inputField ? . $refs ? . input ? . focus ( )
}
if ( this . idState. editedDisplayName !== this . user . displayname ) {
this . idState. editedDisplayName = this . user . displayname
} else if ( this . idState. editedMail !== this . user . email ) {
this . idState. editedMail = this . user . email ? ? ''
if ( this . editedDisplayName !== this . user . displayname ) {
this . editedDisplayName = this . user . displayname
} else if ( this . editedMail !== this . user . email ) {
this . editedMail = this . user . email ? ? ''
}
} ,
} ,
@ -914,6 +898,24 @@ export default {
< style lang = "scss" scoped >
@ import './shared/styles.scss' ;
. user - list _ _row {
@ include row ;
border - bottom : 1 px solid var ( -- color - border ) ;
& : hover {
background - color : var ( -- color - background - hover ) ;
. row _ _cell : not ( . row _ _cell -- actions ) {
background - color : var ( -- color - background - hover ) ;
}
}
/ / L i m i t w i d t h o f s e l e c t i n f i l l c e l l
. select -- fill {
max - width : calc ( var ( -- cell - width - large ) - ( 2 * var ( -- cell - padding ) ) ) ;
}
}
. row {
@ include cell ;