Settings: new user row replaced by a modal
Signed-off-by: Simounet <contact@simounet.net>
This commit is contained in:
parent
d2ea068552
commit
45c3b2a478
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -22,14 +22,12 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="app-content" class="user-list-grid" @scroll.passive="onScroll">
|
<div id="app-content" class="user-list-grid" @scroll.passive="onScroll">
|
||||||
<form v-show="showConfig.showNewUserForm"
|
<Modal v-if="showConfig.showNewUserForm" @close="closeModal">
|
||||||
id="new-user"
|
<form id="new-user"
|
||||||
:class="{'sticky': scrolled && showConfig.showNewUserForm}"
|
|
||||||
:disabled="loading.all"
|
:disabled="loading.all"
|
||||||
class="row"
|
class="modal__content"
|
||||||
@submit.prevent="createUser">
|
@submit.prevent="createUser">
|
||||||
<div :class="loading.all?'icon-loading-small':'icon-add'" />
|
<h2>{{ t('settings','New user') }}</h2>
|
||||||
<div class="name">
|
|
||||||
<input id="newusername"
|
<input id="newusername"
|
||||||
ref="newusername"
|
ref="newusername"
|
||||||
v-model="newUser.id"
|
v-model="newUser.id"
|
||||||
|
@ -40,22 +38,20 @@
|
||||||
autocapitalize="none"
|
autocapitalize="none"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
|
class="modal__item"
|
||||||
name="username"
|
name="username"
|
||||||
pattern="[a-zA-Z0-9 _\.@\-']+"
|
pattern="[a-zA-Z0-9 _\.@\-']+"
|
||||||
required
|
required
|
||||||
type="text">
|
type="text">
|
||||||
<div class="displayName">
|
|
||||||
<input id="newdisplayname"
|
<input id="newdisplayname"
|
||||||
v-model="newUser.displayName"
|
v-model="newUser.displayName"
|
||||||
:placeholder="t('settings', 'Display name')"
|
:placeholder="t('settings', 'Display name')"
|
||||||
autocapitalize="none"
|
autocapitalize="none"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
|
class="modal__item"
|
||||||
name="displayname"
|
name="displayname"
|
||||||
type="text">
|
type="text">
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="password">
|
|
||||||
<input id="newuserpassword"
|
<input id="newuserpassword"
|
||||||
ref="newuserpassword"
|
ref="newuserpassword"
|
||||||
v-model="newUser.password"
|
v-model="newUser.password"
|
||||||
|
@ -65,10 +61,9 @@
|
||||||
autocapitalize="none"
|
autocapitalize="none"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
|
class="modal__item"
|
||||||
name="password"
|
name="password"
|
||||||
type="password">
|
type="password">
|
||||||
</div>
|
|
||||||
<div class="mailAddress">
|
|
||||||
<input id="newemail"
|
<input id="newemail"
|
||||||
v-model="newUser.mailAddress"
|
v-model="newUser.mailAddress"
|
||||||
:placeholder="t('settings', 'Email')"
|
:placeholder="t('settings', 'Email')"
|
||||||
|
@ -76,10 +71,10 @@
|
||||||
autocapitalize="none"
|
autocapitalize="none"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
|
class="modal__item"
|
||||||
name="email"
|
name="email"
|
||||||
type="email">
|
type="email">
|
||||||
</div>
|
<div class="groups modal__item">
|
||||||
<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"
|
||||||
|
@ -108,7 +103,7 @@
|
||||||
</Multiselect>
|
</Multiselect>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="subAdminsGroups.length>0 && settings.isAdmin"
|
<div v-if="subAdminsGroups.length>0 && settings.isAdmin"
|
||||||
class="subadmins">
|
class="subadmins modal__item">
|
||||||
<Multiselect v-model="newUser.subAdminsGroups"
|
<Multiselect v-model="newUser.subAdminsGroups"
|
||||||
:close-on-select="false"
|
:close-on-select="false"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
|
@ -121,7 +116,7 @@
|
||||||
<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 modal__item">
|
||||||
<Multiselect v-model="newUser.quota"
|
<Multiselect v-model="newUser.quota"
|
||||||
:allow-empty="false"
|
:allow-empty="false"
|
||||||
:options="quotaOptions"
|
:options="quotaOptions"
|
||||||
|
@ -132,7 +127,7 @@
|
||||||
track-by="id"
|
track-by="id"
|
||||||
@tag="validateQuota" />
|
@tag="validateQuota" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showConfig.showLanguages" class="languages">
|
<div v-if="showConfig.showLanguages" class="languages modal__item">
|
||||||
<Multiselect v-model="newUser.language"
|
<Multiselect v-model="newUser.language"
|
||||||
:allow-empty="false"
|
:allow-empty="false"
|
||||||
:options="languages"
|
:options="languages"
|
||||||
|
@ -146,21 +141,16 @@
|
||||||
<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="user-actions">
|
||||||
<input id="newsubmit"
|
<button id="newsubmit"
|
||||||
:title="t('settings', 'Add a new user')"
|
class="button primary"
|
||||||
class="button primary icon-checkmark-white has-tooltip"
|
|
||||||
type="submit"
|
type="submit"
|
||||||
value="">
|
value="">
|
||||||
<div class="closeButton">
|
{{ t('settings', 'Add a new user') }}
|
||||||
<Actions>
|
</button>
|
||||||
<ActionButton icon="icon-close" @click="onClose">
|
|
||||||
{{ t('settings', 'Close') }}
|
|
||||||
</ActionButton>
|
|
||||||
</Actions>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</Modal>
|
||||||
<div id="grid-header"
|
<div id="grid-header"
|
||||||
:class="{'sticky': scrolled && !showConfig.showNewUserForm}"
|
:class="{'sticky': scrolled && !showConfig.showNewUserForm}"
|
||||||
class="row">
|
class="row">
|
||||||
|
@ -244,10 +234,9 @@
|
||||||
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
|
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
|
||||||
import InfiniteLoading from 'vue-infinite-loading'
|
import InfiniteLoading from 'vue-infinite-loading'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
import { Modal } from '@nextcloud/vue'
|
||||||
|
|
||||||
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
|
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
|
||||||
import Actions from '@nextcloud/vue/dist/Components/Actions'
|
|
||||||
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
|
|
||||||
|
|
||||||
import userRow from './UserList/UserRow'
|
import userRow from './UserList/UserRow'
|
||||||
|
|
||||||
|
@ -276,11 +265,10 @@ const newUser = {
|
||||||
export default {
|
export default {
|
||||||
name: 'UserList',
|
name: 'UserList',
|
||||||
components: {
|
components: {
|
||||||
|
Modal,
|
||||||
userRow,
|
userRow,
|
||||||
Multiselect,
|
Multiselect,
|
||||||
InfiniteLoading,
|
InfiniteLoading,
|
||||||
Actions,
|
|
||||||
ActionButton,
|
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
users: {
|
users: {
|
||||||
|
@ -522,6 +510,7 @@ export default {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.resetForm()
|
this.resetForm()
|
||||||
this.$refs.newusername.focus()
|
this.$refs.newusername.focus()
|
||||||
|
this.closeModal()
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.loading.all = false
|
this.loading.all = false
|
||||||
|
@ -584,13 +573,45 @@ export default {
|
||||||
this.$refs.infiniteLoading.stateChanger.reset()
|
this.$refs.infiniteLoading.stateChanger.reset()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClose() {
|
closeModal() {
|
||||||
this.showConfig.showNewUserForm = false
|
this.showConfig.showNewUserForm = false
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.modal-wrapper {
|
||||||
|
margin: 2vh 0;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.modal__content {
|
||||||
|
display: flex;
|
||||||
|
padding: 20px;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.modal__item {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.modal__item:not(:focus):not(:active) {
|
||||||
|
border-color: var(--color-border-dark);
|
||||||
|
}
|
||||||
|
.modal__item::v-deep .multiselect {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.user-actions {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.modal__content::v-deep .multiselect__single {
|
||||||
|
text-align: left;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.modal__content::v-deep .multiselect__content-wrapper {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
.row::v-deep .multiselect__single {
|
.row::v-deep .multiselect__single {
|
||||||
z-index: auto !important;
|
z-index: auto !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
<AppNavigationNew button-id="new-user-button"
|
<AppNavigationNew button-id="new-user-button"
|
||||||
:text="t('settings','New user')"
|
:text="t('settings','New user')"
|
||||||
button-class="icon-add"
|
button-class="icon-add"
|
||||||
@click="toggleNewUserMenu" />
|
@click="showNewUserMenu"
|
||||||
|
@keyup.enter="showNewUserMenu"
|
||||||
|
@keyup.space="showNewUserMenu" />
|
||||||
<template #list>
|
<template #list>
|
||||||
<AppNavigationItem
|
<AppNavigationItem
|
||||||
id="addgroup"
|
id="addgroup"
|
||||||
|
@ -348,8 +350,8 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleNewUserMenu() {
|
showNewUserMenu() {
|
||||||
this.showConfig.showNewUserForm = !this.showConfig.showNewUserForm
|
this.showConfig.showNewUserForm = true
|
||||||
if (this.showConfig.showNewUserForm) {
|
if (this.showConfig.showNewUserForm) {
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
window.newusername.focus()
|
window.newusername.focus()
|
||||||
|
|
|
@ -74,7 +74,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface {
|
||||||
* @return Locator
|
* @return Locator
|
||||||
*/
|
*/
|
||||||
public static function createNewUserButton() {
|
public static function createNewUserButton() {
|
||||||
return Locator::forThe()->xpath("//form[@id = 'new-user']//input[@type = 'submit']")->
|
return Locator::forThe()->xpath("//form[@id = 'new-user']//button[@type = 'submit']")->
|
||||||
describedAs("Create user button in Users Settings");
|
describedAs("Create user button in Users Settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue