Skip to content
Snippets Groups Projects
Unverified Commit c864bc83 authored by Greta Doci's avatar Greta Doci Committed by John Molakvoæ (skjnldsv)
Browse files

Move users management to multi line


Signed-off-by: default avatarGreta Doci <gretadoci@gmail.com>
parent c6e51924
No related branches found
No related tags found
No related merge requests found
Showing
with 331 additions and 359 deletions
...@@ -524,7 +524,6 @@ td, th { ...@@ -524,7 +524,6 @@ td, th {
visibility: hidden; visibility: hidden;
} }
&.password, &.password,
&.displayName,
&.mailAddress { &.mailAddress {
min-width: 5em; min-width: 5em;
max-width: 12em; max-width: 12em;
...@@ -705,6 +704,7 @@ span.version { ...@@ -705,6 +704,7 @@ span.version {
#searchresults { #searchresults {
display: none; display: none;
} }
} }
#apps-list.store { #apps-list.store {
.section { .section {
...@@ -1351,8 +1351,8 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { ...@@ -1351,8 +1351,8 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
/* USERS LIST -------------------------------------------------------------- */ /* USERS LIST -------------------------------------------------------------- */
#body-settings { #body-settings {
$grid-row-height: 46px; $grid-row-height: 60px;
$grid-col-min-width: 120px; $grid-col-min-width: 150px;
#app-content.user-list-grid { #app-content.user-list-grid {
display: grid; display: grid;
grid-auto-columns: 1fr; grid-auto-columns: 1fr;
...@@ -1376,7 +1376,6 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { ...@@ -1376,7 +1376,6 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
/* grid col width */ /* grid col width */
.name, .name,
.displayName,
.password, .password,
.mailAddress, .mailAddress,
.languages, .languages,
...@@ -1384,12 +1383,17 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { ...@@ -1384,12 +1383,17 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
.userBackend, .userBackend,
.lastLogin { .lastLogin {
min-width: $grid-col-min-width; min-width: $grid-col-min-width;
display: flex;
color: var(--color-text-dark);
vertical-align: baseline;
} }
.groups, .groups,
.subadmins, .subadmins,
.quota { .quota {
.multiselect { .multiselect {
min-width: $grid-col-min-width; min-width: $grid-col-min-width;
color: var(--color-text-dark);
vertical-align: baseline;
} }
} }
.obfuscated { .obfuscated {
...@@ -1399,6 +1403,10 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { ...@@ -1399,6 +1403,10 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
.userActions { .userActions {
min-width: 44px; min-width: 44px;
} }
.subtitle {
color: var(--color-text-maxcontrast);
vertical-align: baseline;
}
/* various */ /* various */
&#grid-header, &#grid-header,
...@@ -1427,16 +1435,23 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { ...@@ -1427,16 +1435,23 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
&#grid-header { &#grid-header {
color: var(--color-text-maxcontrast); color: var(--color-text-maxcontrast);
z-index: 60; /* above new-user */ z-index: 60; /* above new-user */
border-bottom-width: thin;
#headerDisplayName, #headerDisplayName,
#headerPassword, #headerPassword,
#headerAddress, #headerAddress,
#headerGroups, #headerGroups,
#headerSubAdmins, #headerSubAdmins,
#theHeaderUserBackend,
#theHeaderLastLogin,
#headerQuota, #headerQuota,
#theHeaderStorageLocation,
#headerLanguages { #headerLanguages {
/* Line up header text with column content for when there’s inputs */ /* Line up header text with column content for when there’s inputs */
padding-left: 7px; padding-left: 7px;
text-transform: none;
color: var(--color-text-maxcontrast);
vertical-align: baseline;
} }
} }
&:hover { &:hover {
...@@ -1451,8 +1466,7 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { ...@@ -1451,8 +1466,7 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
> form { > form {
grid-row: 1; grid-row: 1;
display: inline-flex; display: inline-flex;
align-items: center; color: var(--color-text-lighter);
color: var(--color-text);
position: relative; position: relative;
> input:not(:focus):not(:active) { > input:not(:focus):not(:active) {
border-color: transparent; border-color: transparent;
...@@ -1478,7 +1492,7 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { ...@@ -1478,7 +1492,7 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
} }
} }
&.name, &.name,
&.storageLocation { &.userBackend {
/* better multi-line visual */ /* better multi-line visual */
line-height: 1.3em; line-height: 1.3em;
max-height: 100%; max-height: 100%;
...@@ -1492,16 +1506,14 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { ...@@ -1492,16 +1506,14 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
&.quota { &.quota {
.multiselect--active + progress { height: 44px;
display: none; display: flex;
} align-items: center;
justify-content: center;
progress { progress {
position: absolute; width: 100%;
width: calc(100% - 4px); /* minus left and right */ margin: 0 10px;
left: 2px;
bottom: 2px;
height: 3px; height: 3px;
z-index: 5; /* above multiselect */
} }
} }
.icon-confirm { .icon-confirm {
...@@ -1520,16 +1532,22 @@ doesnotexist:-o-prefocus, .strengthify-wrapper { ...@@ -1520,16 +1532,22 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
} }
} }
&.userActions { &.userActions {
.action-item {
position: absolute;
}
#newsubmit { #newsubmit {
width: 100%; width: 100%;
} }
.toggleUserActions { .toggleUserActions {
position: relative; position: relative;
display: block;
align-items: center;
.icon-more { .icon-more {
width: 44px; width: 44px;
height: 44px; height: 44px;
opacity: .5; opacity: .5;
cursor: pointer; cursor: pointer;
margin-left: 40px;
&:hover { &:hover {
opacity: .7; opacity: .7;
} }
......
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
...@@ -29,7 +29,9 @@ ...@@ -29,7 +29,9 @@
<button v-if="showUpdateAll" <button v-if="showUpdateAll"
id="app-list-update-all" id="app-list-update-all"
class="primary" class="primary"
@click="updateAll">{{t('settings', 'Update all')}}</button> @click="updateAll">
{{ t('settings', 'Update all') }}
</button>
</div> </div>
<transition-group name="app-list" tag="div" class="apps-list-container"> <transition-group name="app-list" tag="div" class="apps-list-container">
<AppItem v-for="app in apps" <AppItem v-for="app in apps"
......
...@@ -22,13 +22,16 @@ ...@@ -22,13 +22,16 @@
<template> <template>
<div id="app-content" class="user-list-grid" @scroll.passive="onScroll"> <div id="app-content" class="user-list-grid" @scroll.passive="onScroll">
<div id="grid-header" class="row" :class="{'sticky': scrolled && !showConfig.showNewUserForm}"> <div id="grid-header"
:class="{'sticky': scrolled && !showConfig.showNewUserForm}"
class="row">
<div id="headerAvatar" class="avatar" /> <div id="headerAvatar" class="avatar" />
<div id="headerName" class="name"> <div id="headerName" class="name">
{{ t('settings', 'Username') }} {{ t('settings', 'Username') }}
</div>
<div id="headerDisplayName" class="displayName"> <div class="subtitle">
{{ t('settings', 'Display name') }} {{ t('settings', 'Display name') }}
</div>
</div> </div>
<div id="headerPassword" class="password"> <div id="headerPassword" class="password">
{{ t('settings', 'Password') }} {{ t('settings', 'Password') }}
...@@ -52,99 +55,103 @@ ...@@ -52,99 +55,103 @@
class="languages"> class="languages">
{{ t('settings', 'Language') }} {{ t('settings', 'Language') }}
</div> </div>
<div v-if="showConfig.showStoragePath"
class="headerStorageLocation storageLocation"> <div v-if="showConfig.showUserBackend || showConfig.showStoragePath"
{{ t('settings', 'Storage location') }}
</div>
<div v-if="showConfig.showUserBackend"
class="headerUserBackend userBackend"> class="headerUserBackend userBackend">
{{ t('settings', 'User backend') }} <div v-if="showConfig.showUserBackend" class="userBackend">
{{ t('settings', 'User backend') }}
</div>
<div v-if="showConfig.showStoragePath"
class="subtitle storageLocation">
{{ t('settings', 'Storage location') }}
</div>
</div> </div>
<div v-if="showConfig.showLastLogin" <div v-if="showConfig.showLastLogin"
class="headerLastLogin lastLogin"> class="headerLastLogin lastLogin">
{{ t('settings', 'Last login') }} {{ t('settings', 'Last login') }}
</div> </div>
<div class="userActions" /> <div class="userActions" />
</div> </div>
<form v-show="showConfig.showNewUserForm" <form v-show="showConfig.showNewUserForm"
id="new-user" id="new-user"
class="row"
:disabled="loading.all"
:class="{'sticky': scrolled && showConfig.showNewUserForm}" :class="{'sticky': scrolled && showConfig.showNewUserForm}"
:disabled="loading.all"
class="row"
@submit.prevent="createUser"> @submit.prevent="createUser">
<div :class="loading.all?'icon-loading-small':'icon-add'" /> <div :class="loading.all?'icon-loading-small':'icon-add'" />
<div class="name"> <div class="name">
<input id="newusername" <input id="newusername"
ref="newusername" ref="newusername"
v-model="newUser.id" v-model="newUser.id"
type="text" :disabled="settings.newUserGenerateUserID"
required
:placeholder="settings.newUserGenerateUserID :placeholder="settings.newUserGenerateUserID
? t('settings', 'Will be autogenerated') ? t('settings', 'Will be autogenerated')
: t('settings', 'Username')" : t('settings', 'Username')"
name="username"
autocomplete="off"
autocapitalize="none" autocapitalize="none"
autocomplete="off"
autocorrect="off" autocorrect="off"
name="username"
pattern="[a-zA-Z0-9 _\.@\-']+" pattern="[a-zA-Z0-9 _\.@\-']+"
:disabled="settings.newUserGenerateUserID"> required
type="text">
</div> </div>
<div class="displayName"> <div class="displayName">
<input id="newdisplayname" <input id="newdisplayname"
v-model="newUser.displayName" v-model="newUser.displayName"
type="text"
:placeholder="t('settings', 'Display name')" :placeholder="t('settings', 'Display name')"
name="displayname"
autocomplete="off"
autocapitalize="none" autocapitalize="none"
autocorrect="off"> autocomplete="off"
autocorrect="off"
name="displayname"
type="text">
</div> </div>
<div class="password"> <div class="password">
<input id="newuserpassword" <input id="newuserpassword"
ref="newuserpassword" ref="newuserpassword"
v-model="newUser.password" v-model="newUser.password"
type="password" :minlength="minPasswordLength"
:required="newUser.mailAddress===''"
:placeholder="t('settings', 'Password')" :placeholder="t('settings', 'Password')"
name="password" :required="newUser.mailAddress===''"
autocomplete="new-password"
autocapitalize="none" autocapitalize="none"
autocomplete="new-password"
autocorrect="off" autocorrect="off"
:minlength="minPasswordLength"> name="password"
type="password">
</div> </div>
<div class="mailAddress"> <div class="mailAddress">
<input id="newemail" <input id="newemail"
v-model="newUser.mailAddress" v-model="newUser.mailAddress"
type="email"
:required="newUser.password==='' || settings.newUserRequireEmail"
:placeholder="t('settings', 'Email')" :placeholder="t('settings', 'Email')"
name="email" :required="newUser.password==='' || settings.newUserRequireEmail"
autocomplete="off"
autocapitalize="none" autocapitalize="none"
autocorrect="off"> autocomplete="off"
autocorrect="off"
name="email"
type="email">
</div> </div>
<div class="groups"> <div class="groups">
<!-- hidden input trick for vanilla html5 form validation --> <!-- hidden input trick for vanilla html5 form validation -->
<input v-if="!settings.isAdmin" <input v-if="!settings.isAdmin"
id="newgroups" id="newgroups"
type="text" :class="{'icon-loading-small': loading.groups}"
:required="!settings.isAdmin"
:value="newUser.groups" :value="newUser.groups"
tabindex="-1" tabindex="-1"
:required="!settings.isAdmin" type="text">
:class="{'icon-loading-small': loading.groups}">
<Multiselect v-model="newUser.groups" <Multiselect v-model="newUser.groups"
:options="canAddGroups" :close-on-select="false"
:disabled="loading.groups||loading.all" :disabled="loading.groups||loading.all"
tag-placeholder="create" :multiple="true"
:options="canAddGroups"
:placeholder="t('settings', 'Add user in group')" :placeholder="t('settings', 'Add user in group')"
:tag-width="60"
:taggable="true"
class="multiselect-vue"
label="name" label="name"
tag-placeholder="create"
track-by="id" track-by="id"
class="multiselect-vue"
:multiple="true"
:taggable="true"
:close-on-select="false"
:tag-width="60"
@tag="createGroup"> @tag="createGroup">
<!-- If user is not admin, he is a subadmin. <!-- If user is not admin, he is a subadmin.
Subadmins can't create users outside their groups Subadmins can't create users outside their groups
...@@ -152,63 +159,64 @@ ...@@ -152,63 +159,64 @@
<span slot="noResult">{{ t('settings', 'No results') }}</span> <span slot="noResult">{{ t('settings', 'No results') }}</span>
</Multiselect> </Multiselect>
</div> </div>
<div v-if="subAdminsGroups.length>0 && settings.isAdmin" class="subadmins"> <div v-if="subAdminsGroups.length>0 && settings.isAdmin"
class="subadmins">
<Multiselect v-model="newUser.subAdminsGroups" <Multiselect v-model="newUser.subAdminsGroups"
:close-on-select="false"
:multiple="true"
:options="subAdminsGroups" :options="subAdminsGroups"
:placeholder="t('settings', 'Set user as admin for')" :placeholder="t('settings', 'Set user as admin for')"
label="name" :tag-width="60"
track-by="id"
class="multiselect-vue" class="multiselect-vue"
:multiple="true" label="name"
:close-on-select="false" track-by="id">
:tag-width="60">
<span slot="noResult">{{ t('settings', 'No results') }}</span> <span slot="noResult">{{ t('settings', 'No results') }}</span>
</Multiselect> </Multiselect>
</div> </div>
<div class="quota"> <div class="quota">
<Multiselect v-model="newUser.quota" <Multiselect v-model="newUser.quota"
:allow-empty="false"
:options="quotaOptions" :options="quotaOptions"
:placeholder="t('settings', 'Select user quota')" :placeholder="t('settings', 'Select user quota')"
:taggable="true"
class="multiselect-vue"
label="label" label="label"
track-by="id" track-by="id"
class="multiselect-vue"
:allow-empty="false"
:taggable="true"
@tag="validateQuota" /> @tag="validateQuota" />
</div> </div>
<div v-if="showConfig.showLanguages" class="languages"> <div v-if="showConfig.showLanguages" class="languages">
<Multiselect v-model="newUser.language" <Multiselect v-model="newUser.language"
:allow-empty="false"
:options="languages" :options="languages"
:placeholder="t('settings', 'Default language')" :placeholder="t('settings', 'Default language')"
label="name"
track-by="code"
class="multiselect-vue" class="multiselect-vue"
:allow-empty="false" group-label="label"
group-values="languages" group-values="languages"
group-label="label" /> label="name"
track-by="code" />
</div> </div>
<div v-if="showConfig.showStoragePath" class="storageLocation" /> <div v-if="showConfig.showStoragePath" class="storageLocation" />
<div v-if="showConfig.showUserBackend" class="userBackend" /> <div v-if="showConfig.showUserBackend" class="userBackend" />
<div v-if="showConfig.showLastLogin" class="lastLogin" /> <div v-if="showConfig.showLastLogin" class="lastLogin" />
<div class="userActions"> <div class="userActions">
<input id="newsubmit" <input id="newsubmit"
type="submit" :title="t('settings', 'Add a new user')"
class="button primary icon-checkmark-white has-tooltip" class="button primary icon-checkmark-white has-tooltip"
value="" type="submit"
:title="t('settings', 'Add a new user')"> value="">
</div> </div>
</form> </form>
<user-row v-for="(user, key) in filteredUsers" <user-row v-for="(user, key) in filteredUsers"
:key="key" :key="key"
:user="user" :external-actions="externalActions"
:groups="groups"
:languages="languages"
:quota-options="quotaOptions"
:settings="settings" :settings="settings"
:show-config="showConfig" :show-config="showConfig"
:groups="groups"
:sub-admins-groups="subAdminsGroups" :sub-admins-groups="subAdminsGroups"
:quota-options="quotaOptions" :user="user" />
:languages="languages"
:external-actions="externalActions" />
<InfiniteLoading ref="infiniteLoading" @infinite="infiniteHandler"> <InfiniteLoading ref="infiniteLoading" @infinite="infiniteHandler">
<div slot="spinner"> <div slot="spinner">
<div class="users-icon-loading icon-loading" /> <div class="users-icon-loading icon-loading" />
...@@ -328,7 +336,10 @@ export default { ...@@ -328,7 +336,10 @@ export default {
}, },
quotaOptions() { quotaOptions() {
// convert the preset array into objects // convert the preset array into objects
let quotaPreset = this.settings.quotaPreset.reduce((acc, cur) => acc.concat({ id: cur, label: cur }), []) let quotaPreset = this.settings.quotaPreset.reduce((acc, cur) => acc.concat({
id: cur,
label: cur
}), [])
// add default presets // add default presets
quotaPreset.unshift(this.unlimitedQuota) quotaPreset.unshift(this.unlimitedQuota)
quotaPreset.unshift(this.defaultQuota) quotaPreset.unshift(this.defaultQuota)
...@@ -377,9 +388,9 @@ export default { ...@@ -377,9 +388,9 @@ export default {
// deleting the last user, reset the list // deleting the last user, reset the list
if (val === 0 && old === 1) { if (val === 0 && old === 1) {
this.$refs.infiniteLoading.stateChanger.reset() this.$refs.infiniteLoading.stateChanger.reset()
// adding the first user, warn the infiniteLoader that // adding the first user, warn the infiniteLoader that
// the list is not empty anymore (we don't fetch the newly // the list is not empty anymore (we don't fetch the newly
// added user as we already have all the info we need) // added user as we already have all the info we need)
} else if (val === 1 && old === 0) { } else if (val === 1 && old === 0) {
this.$refs.infiniteLoading.stateChanger.loaded() this.$refs.infiniteLoading.stateChanger.loaded()
} }
...@@ -437,7 +448,9 @@ export default { ...@@ -437,7 +448,9 @@ export default {
group: this.selectedGroup !== 'disabled' ? this.selectedGroup : '', group: this.selectedGroup !== 'disabled' ? this.selectedGroup : '',
search: this.searchQuery search: this.searchQuery
}) })
.then((response) => { response ? $state.loaded() : $state.complete() }) .then((response) => {
response ? $state.loaded() : $state.complete()
})
}, },
/* SEARCH */ /* SEARCH */
...@@ -492,10 +505,10 @@ export default { ...@@ -492,10 +505,10 @@ export default {
if (error.response && error.response.data && error.response.data.ocs && error.response.data.ocs.meta) { if (error.response && error.response.data && error.response.data.ocs && error.response.data.ocs.meta) {
const statuscode = error.response.data.ocs.meta.statuscode const statuscode = error.response.data.ocs.meta.statuscode
if (statuscode === 102) { if (statuscode === 102) {
// wrong username // wrong username
this.$refs.newusername.focus() this.$refs.newusername.focus()
} else if (statuscode === 107) { } else if (statuscode === 107) {
// wrong password // wrong password
this.$refs.newuserpassword.focus() this.$refs.newuserpassword.focus()
} }
} }
...@@ -542,7 +555,7 @@ export default { ...@@ -542,7 +555,7 @@ export default {
redirectIfDisabled() { redirectIfDisabled() {
const allGroups = this.$store.getters.getGroups const allGroups = this.$store.getters.getGroups
if (this.selectedGroup === 'disabled' if (this.selectedGroup === 'disabled'
&& allGroups.findIndex(group => group.id === 'disabled' && group.usercount === 0) > -1) { && allGroups.findIndex(group => group.id === 'disabled' && group.usercount === 0) > -1) {
// disabled group is empty, redirection to all users // disabled group is empty, redirection to all users
this.$router.push({ name: 'users' }) this.$router.push({ name: 'users' })
this.$refs.infiniteLoading.stateChanger.reset() this.$refs.infiniteLoading.stateChanger.reset()
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment