Skip to content

Commit

Permalink
Merge pull request #45315 from nextcloud/fix/new-user-dialog
Browse files Browse the repository at this point in the history
fix(settings): Move new user modal to dialog + minor refactoring
  • Loading branch information
Pytal authored May 31, 2024
2 parents 48e6240 + 930e47d commit 0687853
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 82 deletions.
10 changes: 5 additions & 5 deletions apps/settings/src/components/UserList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@

<template>
<Fragment>
<NewUserModal v-if="showConfig.showNewUserForm"
<NewUserDialog v-if="showConfig.showNewUserForm"
:loading="loading"
:new-user="newUser"
:quota-options="quotaOptions"
@reset="resetForm"
@close="closeModal" />
@closing="closeDialog" />

<NcEmptyContent v-if="filteredUsers.length === 0"
class="empty"
Expand Down Expand Up @@ -88,7 +88,7 @@ import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
import VirtualList from './Users/VirtualList.vue'
import NewUserModal from './Users/NewUserModal.vue'
import NewUserDialog from './Users/NewUserDialog.vue'
import UserListFooter from './Users/UserListFooter.vue'
import UserListHeader from './Users/UserListHeader.vue'
import UserRow from './Users/UserRow.vue'
Expand Down Expand Up @@ -119,7 +119,7 @@ export default {
NcEmptyContent,
NcIconSvgWrapper,
NcLoadingIcon,
NewUserModal,
NewUserDialog,
UserListFooter,
UserListHeader,
VirtualList,
Expand Down Expand Up @@ -332,7 +332,7 @@ export default {
this.isInitialLoad = false
},
closeModal() {
closeDialog() {
this.$store.commit('setShowConfig', {
key: 'showNewUserForm',
value: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,18 @@
-->

<template>
<NcModal class="modal"
<NcDialog class="dialog"
size="small"
:name="t('settings', 'New account')"
out-transition
v-on="$listeners">
<form class="modal__form"
<form id="new-user-form"
class="dialog__form"
data-test="form"
:disabled="loading.all"
@submit.prevent="createUser">
<h2>{{ t('settings', 'New user') }}</h2>
<NcTextField ref="username"
class="modal__item"
class="dialog__item"
data-test="username"
:value.sync="newUser.id"
:disabled="settings.newUserGenerateUserID"
Expand All @@ -40,7 +42,7 @@
spellcheck="false"
pattern="[a-zA-Z0-9 _\.@\-']+"
required />
<NcTextField class="modal__item"
<NcTextField class="dialog__item"
data-test="displayName"
:value.sync="newUser.displayName"
:label="t('settings', 'Display name')"
Expand All @@ -49,11 +51,11 @@
spellcheck="false" />
<span v-if="!settings.newUserRequireEmail"
id="password-email-hint"
class="modal__hint">
class="dialog__hint">
{{ t('settings', 'Either password or email is required') }}
</span>
<NcPasswordField ref="password"
class="modal__item"
class="dialog__item"
data-test="password"
:value.sync="newUser.password"
:minlength="minPasswordLength"
Expand All @@ -64,7 +66,7 @@
autocomplete="new-password"
spellcheck="false"
:required="newUser.mailAddress === ''" />
<NcTextField class="modal__item"
<NcTextField class="dialog__item"
data-test="email"
type="email"
:value.sync="newUser.mailAddress"
Expand All @@ -74,14 +76,10 @@
autocomplete="off"
spellcheck="false"
:required="newUser.password === '' || settings.newUserRequireEmail" />
<div class="modal__item">
<label class="modal__label"
for="new-user-groups">
{{ !settings.isAdmin ? t('settings', 'Groups (required)') : t('settings', 'Groups') }}
</label>
<NcSelect class="modal__select"
input-id="new-user-groups"
:placeholder="t('settings', 'Set user groups')"
<div class="dialog__item">
<NcSelect class="dialog__select"
:input-label="!settings.isAdmin ? t('settings', 'Groups (required)') : t('settings', 'Groups')"
:placeholder="t('settings', 'Set account groups')"
:disabled="loading.groups || loading.all"
:options="canAddGroups"
:value="newUser.groups"
Expand All @@ -97,88 +95,75 @@
Therefore, empty select is forbidden -->
</div>
<div v-if="subAdminsGroups.length > 0"
class="modal__item">
<label class="modal__label"
for="new-user-sub-admin">
{{ t('settings', 'Administered groups') }}
</label>
class="dialog__item">
<NcSelect v-model="newUser.subAdminsGroups"
class="modal__select"
input-id="new-user-sub-admin"
:placeholder="t('settings', 'Set user as admin for …')"
class="dialog__select"
:input-label="t('settings', 'Administered groups')"
:placeholder="t('settings', 'Set account as admin for …')"
:options="subAdminsGroups"
:close-on-select="false"
:multiple="true"
label="name" />
</div>
<div class="modal__item">
<label class="modal__label"
for="new-user-quota">
{{ t('settings', 'Quota') }}
</label>
<div class="dialog__item">
<NcSelect v-model="newUser.quota"
class="modal__select"
input-id="new-user-quota"
:placeholder="t('settings', 'Set user quota')"
class="dialog__select"
:input-label="t('settings', 'Quota')"
:placeholder="t('settings', 'Set account quota')"
:options="quotaOptions"
:clearable="false"
:taggable="true"
:create-option="validateQuota" />
</div>
<div v-if="showConfig.showLanguages"
class="modal__item">
<label class="modal__label"
for="new-user-language">
{{ t('settings', 'Language') }}
</label>
class="dialog__item">
<NcSelect v-model="newUser.language"
class="modal__select"
input-id="new-user-language"
class="dialog__select"
:input-label="t('settings', 'Language')"
:placeholder="t('settings', 'Set default language')"
:clearable="false"
:selectable="option => !option.languages"
:filter-by="languageFilterBy"
:options="languages"
label="name" />
</div>
<div :class="['modal__item managers', { 'icon-loading-small': loading.manager }]">
<label class="modal__label"
for="new-user-manager">
<!-- TRANSLATORS This string describes a manager in the context of an organization -->
{{ t('settings', 'Manager') }}
</label>
<div :class="['dialog__item dialog__managers', { 'icon-loading-small': loading.manager }]">
<NcSelect v-model="newUser.manager"
class="modal__select"
input-id="new-user-manager"
class="dialog__select"
:input-label="managerInputLabel"
:placeholder="managerLabel"
:options="possibleManagers"
:user-select="true"
label="displayname"
@search="searchUserManager" />
</div>
<NcButton class="modal__submit"
</form>

<template #actions>
<NcButton class="dialog__submit"
data-test="submit"
form="new-user-form"
type="primary"
native-type="submit">
{{ t('settings', 'Add new user') }}
{{ t('settings', 'Add new account') }}
</NcButton>
</form>
</NcModal>
</template>
</NcDialog>
</template>

<script>
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcModal from '@nextcloud/vue/dist/Components/NcModal.js'
import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js'
import NcPasswordField from '@nextcloud/vue/dist/Components/NcPasswordField.js'
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
export default {
name: 'NewUserModal',
name: 'NewUserDialog',
components: {
NcButton,
NcModal,
NcDialog,
NcPasswordField,
NcSelect,
NcTextField,
Expand All @@ -205,7 +190,9 @@ export default {
return {
possibleManagers: [],
// TRANSLATORS This string describes a manager in the context of an organization
managerLabel: t('settings', 'Set user manager'),
managerInputLabel: t('settings', 'Manager'),
// TRANSLATORS This string describes a manager in the context of an organization
managerLabel: t('settings', 'Set account manager'),
}
},
Expand Down Expand Up @@ -272,6 +259,10 @@ export default {
await this.searchUserManager()
},
mounted() {
this.$refs.username?.focus?.()
},
methods: {
async createUser() {
this.loading.all = true
Expand All @@ -289,18 +280,18 @@ export default {
})
this.$emit('reset')
this.$refs.username?.$refs?.inputField?.$refs?.input?.focus?.()
this.$emit('close')
this.$refs.username?.focus?.()
this.$emit('closing')
} catch (error) {
this.loading.all = false
if (error.response && error.response.data && error.response.data.ocs && error.response.data.ocs.meta) {
const statuscode = error.response.data.ocs.meta.statuscode
if (statuscode === 102) {
// wrong username
this.$refs.username?.$refs?.inputField?.$refs?.input?.focus?.()
this.$refs.username?.focus?.()
} else if (statuscode === 107) {
// wrong password
this.$refs.password?.$refs?.inputField?.$refs?.input?.focus?.()
this.$refs.password?.focus?.()
}
}
}
Expand Down Expand Up @@ -383,12 +374,12 @@ export default {
</script>
<style lang="scss" scoped>
.modal {
.dialog {
&__form {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
padding: 0 8px;
gap: 4px 0;
}
Expand All @@ -415,8 +406,19 @@ export default {
width: 100%;
}
&__managers {
margin-bottom: 12px;
}
&__submit {
margin-top: 20px;
margin-top: 4px;
margin-bottom: 8px;
}
:deep {
.dialog__actions {
margin: auto;
}
}
}
</style>
10 changes: 5 additions & 5 deletions apps/settings/src/components/Users/UserListFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</th>
<td class="footer__cell footer__cell--loading">
<NcLoadingIcon v-if="loading"
:title="t('settings', 'Loading users')"
:title="t('settings', 'Loading accounts')"
:size="32" />
</td>
<td class="footer__cell footer__cell--count footer__cell--multiline">
Expand Down Expand Up @@ -73,8 +73,8 @@ export default Vue.extend({
if (this.loading) {
return this.n(
'settings',
'{userCount} user',
'{userCount} users',
'{userCount} account',
'{userCount} accounts',
this.filteredUsers.length,
{
userCount: this.filteredUsers.length,
Expand All @@ -83,8 +83,8 @@ export default Vue.extend({
}
return this.n(
'settings',
'{userCount} user',
'{userCount} users',
'{userCount} account',
'{userCount} accounts',
this.filteredUsers.length,
{
userCount: this.filteredUsers.length,
Expand Down
2 changes: 1 addition & 1 deletion apps/settings/src/components/Users/UserListHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
data-cy-user-list-header-actions
scope="col">
<span class="hidden-visually">
{{ t('settings', 'User actions') }}
{{ t('settings', 'Account actions') }}
</span>
</th>
</tr>
Expand Down
2 changes: 1 addition & 1 deletion apps/settings/src/components/Users/UserRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
<template v-if="editing">
<label class="hidden-visually"
:for="'groups' + uniqueId">
{{ t('settings', 'Add user to group') }}
{{ t('settings', 'Add account to group') }}
</label>
<NcSelect data-cy-user-list-input-groups
:data-loading="loading.groups || undefined"
Expand Down
6 changes: 6 additions & 0 deletions cypress/e2e/settings/users.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ describe('Settings: Create and delete accounts', function() {
cy.get('input[type="password"]').type(john.password)
// see that the password is 123456
cy.get('input[type="password"]').should('have.value', john.password)
})

cy.get('form[data-test="form"]').parents('[role="dialog"]').within(() => {
// submit the new user form
cy.get('button[type="submit"]').click({ force: true })
})
Expand Down Expand Up @@ -73,6 +76,9 @@ describe('Settings: Create and delete accounts', function() {
cy.get('input[type="password"]').should('exist').and('have.value', '')
cy.get('input[type="password"]').type(john.password)
cy.get('input[type="password"]').should('have.value', john.password)
})

cy.get('form[data-test="form"]').parents('[role="dialog"]').within(() => {
// submit the new user form
cy.get('button[type="submit"]').click({ force: true })
})
Expand Down
6 changes: 3 additions & 3 deletions dist/settings-users-3239.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/settings-users-3239.js.map

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/settings-vue-settings-apps-users-management.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/settings-vue-settings-apps-users-management.js.map

Large diffs are not rendered by default.

0 comments on commit 0687853

Please sign in to comment.