]> source.dussan.org Git - nextcloud-server.git/commitdiff
enh(a11y): User management settings dialog
authorChristopher Ng <chrng8@gmail.com>
Sat, 15 Jul 2023 01:29:25 +0000 (18:29 -0700)
committerChristopher Ng <chrng8@gmail.com>
Wed, 19 Jul 2023 03:28:10 +0000 (20:28 -0700)
Signed-off-by: Christopher Ng <chrng8@gmail.com>
apps/settings/src/components/Users/UserSettingsDialog.vue [new file with mode: 0644]
apps/settings/src/views/Users.vue

diff --git a/apps/settings/src/components/Users/UserSettingsDialog.vue b/apps/settings/src/components/Users/UserSettingsDialog.vue
new file mode 100644 (file)
index 0000000..818f5bd
--- /dev/null
@@ -0,0 +1,280 @@
+<!--
+       - @copyright 2023 Christopher Ng <chrng8@gmail.com>
+       -
+       - @author Christopher Ng <chrng8@gmail.com>
+       -
+       - @license AGPL-3.0-or-later
+       -
+       - This program is free software: you can redistribute it and/or modify
+       - it under the terms of the GNU Affero General Public License as
+       - published by the Free Software Foundation, either version 3 of the
+       - License, or (at your option) any later version.
+       -
+       - This program is distributed in the hope that it will be useful,
+       - but WITHOUT ANY WARRANTY; without even the implied warranty of
+       - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+       - GNU Affero General Public License for more details.
+       -
+       - You should have received a copy of the GNU Affero General Public License
+       - along with this program. If not, see <http://www.gnu.org/licenses/>.
+       -
+-->
+
+<template>
+       <NcAppSettingsDialog :open.sync="isModalOpen"
+               :show-navigation="true"
+               :title="t('settings', 'User management settings')">
+               <NcAppSettingsSection id="visibility-settings"
+                       :title="t('settings', 'Visibility')">
+                       <NcCheckboxRadioSwitch type="switch"
+                               data-test="showLanguages"
+                               :checked.sync="showLanguages">
+                               {{ t('settings', 'Show language') }}
+                       </NcCheckboxRadioSwitch>
+                       <NcCheckboxRadioSwitch type="switch"
+                               data-test="showUserBackend"
+                               :checked.sync="showUserBackend">
+                               {{ t('settings', 'Show user backend') }}
+                       </NcCheckboxRadioSwitch>
+                       <NcCheckboxRadioSwitch type="switch"
+                               data-test="showStoragePath"
+                               :checked.sync="showStoragePath">
+                               {{ t('settings', 'Show storage path') }}
+                       </NcCheckboxRadioSwitch>
+                       <NcCheckboxRadioSwitch type="switch"
+                               data-test="showLastLogin"
+                               :checked.sync="showLastLogin">
+                               {{ t('settings', 'Show last login') }}
+                       </NcCheckboxRadioSwitch>
+               </NcAppSettingsSection>
+
+               <NcAppSettingsSection id="email-settings"
+                       :title="t('settings', 'Send email')">
+                       <NcCheckboxRadioSwitch type="switch"
+                               data-test="sendWelcomeMail"
+                               :checked.sync="sendWelcomeMail"
+                               :disabled="loadingSendMail">
+                               {{ t('settings', 'Send welcome email to new users') }}
+                       </NcCheckboxRadioSwitch>
+               </NcAppSettingsSection>
+
+               <NcAppSettingsSection id="default-settings"
+                       :title="t('settings', 'Defaults')">
+                       <label for="default-quota-select">{{ t('settings', 'Default quota') }}</label>
+                       <NcSelect v-model="defaultQuota"
+                               input-id="default-quota-select"
+                               placement="top"
+                               :taggable="true"
+                               :options="quotaOptions"
+                               :create-option="validateQuota"
+                               :placeholder="t('settings', 'Select default quota')"
+                               :clearable="false"
+                               @option:selected="setDefaultQuota" />
+               </NcAppSettingsSection>
+       </NcAppSettingsDialog>
+</template>
+
+<script>
+import axios from '@nextcloud/axios'
+import { generateUrl } from '@nextcloud/router'
+
+import NcAppSettingsDialog from '@nextcloud/vue/dist/Components/NcAppSettingsDialog.js'
+import NcAppSettingsSection from '@nextcloud/vue/dist/Components/NcAppSettingsSection.js'
+import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
+import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
+
+import { unlimitedQuota } from '../../utils/userUtils.ts'
+
+export default {
+       name: 'UserSettingsDialog',
+
+       components: {
+               NcAppSettingsDialog,
+               NcAppSettingsSection,
+               NcCheckboxRadioSwitch,
+               NcSelect,
+       },
+
+       props: {
+               open: {
+                       type: Boolean,
+                       required: true,
+               },
+       },
+
+       data() {
+               return {
+                       selectedQuota: false,
+                       loadingSendMail: false,
+               }
+       },
+
+       computed: {
+               isModalOpen: {
+                       get() {
+                               return this.open
+                       },
+                       set(open) {
+                               this.$emit('update:open', open)
+                       },
+               },
+
+               showConfig() {
+                       return this.$store.getters.getShowConfig
+               },
+
+               settings() {
+                       return this.$store.getters.getServerData
+               },
+
+               showLanguages: {
+                       get() {
+                               return this.getLocalstorage('showLanguages')
+                       },
+                       set(status) {
+                               this.setLocalStorage('showLanguages', status)
+                       },
+               },
+
+               showLastLogin: {
+                       get() {
+                               return this.getLocalstorage('showLastLogin')
+                       },
+                       set(status) {
+                               this.setLocalStorage('showLastLogin', status)
+                       },
+               },
+
+               showUserBackend: {
+                       get() {
+                               return this.getLocalstorage('showUserBackend')
+                       },
+                       set(status) {
+                               this.setLocalStorage('showUserBackend', status)
+                       },
+               },
+
+               showStoragePath: {
+                       get() {
+                               return this.getLocalstorage('showStoragePath')
+                       },
+                       set(status) {
+                               this.setLocalStorage('showStoragePath', status)
+                       },
+               },
+
+               quotaOptions() {
+                       // convert the preset array into objects
+                       const quotaPreset = this.settings.quotaPreset.reduce((acc, cur) => acc.concat({ id: cur, label: cur }), [])
+                       // add default presets
+                       if (this.settings.allowUnlimitedQuota) {
+                               quotaPreset.unshift(unlimitedQuota)
+                       }
+                       return quotaPreset
+               },
+
+               defaultQuota: {
+                       get() {
+                               if (this.selectedQuota !== false) {
+                                       return this.selectedQuota
+                               }
+                               if (this.settings.defaultQuota !== unlimitedQuota.id && OC.Util.computerFileSize(this.settings.defaultQuota) >= 0) {
+                                       // if value is valid, let's map the quotaOptions or return custom quota
+                                       return { id: this.settings.defaultQuota, label: this.settings.defaultQuota }
+                               }
+                               return unlimitedQuota // unlimited
+                       },
+                       set(quota) {
+                               this.selectedQuota = quota
+                       },
+               },
+
+               sendWelcomeMail: {
+                       get() {
+                               return this.settings.newUserSendEmail
+                       },
+                       async set(value) {
+                               try {
+                                       this.loadingSendMail = true
+                                       this.$store.commit('setServerData', {
+                                               ...this.settings,
+                                               newUserSendEmail: value,
+                                       })
+                                       await axios.post(generateUrl('/settings/users/preferences/newUser.sendEmail'), { value: value ? 'yes' : 'no' })
+                               } catch (e) {
+                                       console.error('could not update newUser.sendEmail preference: ' + e.message, e)
+                               } finally {
+                                       this.loadingSendMail = false
+                               }
+                       },
+               },
+       },
+
+       methods: {
+               getLocalstorage(key) {
+                       // force initialization
+                       const localConfig = this.$localStorage.get(key)
+                       // if localstorage is null, fallback to original values
+                       this.$store.commit('setShowConfig', { key, value: localConfig !== null ? localConfig === 'true' : this.showConfig[key] })
+                       return this.showConfig[key]
+               },
+
+               setLocalStorage(key, status) {
+                       this.$store.commit('setShowConfig', { key, value: status })
+                       this.$localStorage.set(key, status)
+                       return status
+               },
+
+               /**
+                * Validate quota string to make sure it's a valid human file size
+                *
+                * @param {string | object} quota Quota in readable format '5 GB' or Object {id: '5 GB', label: '5GB'}
+                * @return {object} The validated quota object or unlimited quota if input is invalid
+                */
+               validateQuota(quota) {
+                       if (typeof quota === 'object') {
+                               quota = quota?.id || quota.label
+                       }
+                       // only used for new presets sent through @Tag
+                       const validQuota = OC.Util.computerFileSize(quota)
+                       if (validQuota === null) {
+                               return unlimitedQuota
+                       } else {
+                               // unify format output
+                               quota = OC.Util.humanFileSize(OC.Util.computerFileSize(quota))
+                               return { id: quota, label: quota }
+                       }
+               },
+
+               /**
+                * Dispatch default quota set request
+                *
+                * @param {string | object} quota Quota in readable format '5 GB' or Object {id: '5 GB', label: '5GB'}
+                */
+               setDefaultQuota(quota = 'none') {
+                       // Make sure correct label is set for unlimited quota
+                       if (quota === 'none') {
+                               quota = unlimitedQuota
+                       }
+                       this.$store.dispatch('setAppConfig', {
+                               app: 'files',
+                               key: 'default_quota',
+                               // ensure we only send the preset id
+                               value: quota.id ? quota.id : quota,
+                       }).then(() => {
+                               if (typeof quota !== 'object') {
+                                       quota = { id: quota, label: quota }
+                               }
+                               this.defaultQuota = quota
+                       })
+               },
+       },
+}
+</script>
+
+<style lang="scss" scoped>
+label[for="default-quota-select"] {
+       display: block;
+       padding: 4px 0;
+}
+</style>
index e1f26ea6ea3659ea22e4bf1c4747fd20eb259675..449308104eaa1b3b4d308cabba3e764c6dcaaac3 100644 (file)
   -->
 
 <template>
-       <NcContent app-name="settings" :navigation-class="{ 'icon-loading': loadingAddGroup }">
-               <NcAppNavigation>
-                       <NcAppNavigationNew button-id="new-user-button"
-                               :text="t('settings','New user')"
-                               button-class="icon-add"
-                               @click="showNewUserMenu"
-                               @keyup.enter="showNewUserMenu"
-                               @keyup.space="showNewUserMenu" />
-                       <template #list>
-                               <NcAppNavigationNewItem id="addgroup"
-                                       ref="addGroup"
-                                       :edit-placeholder="t('settings', 'Enter group name')"
-                                       :editable="true"
-                                       :loading="loadingAddGroup"
-                                       :title="t('settings', 'Add group')"
-                                       @click="showAddGroupForm"
-                                       @new-item="createGroup">
-                                       <template #icon>
-                                               <Plus :size="20" />
-                                       </template>
-                               </NcAppNavigationNewItem>
-                               <NcAppNavigationItem id="everyone"
-                                       :exact="true"
-                                       :title="t('settings', 'Active users')"
-                                       :to="{ name: 'users' }"
-                                       icon="icon-contacts-dark">
-                                       <template #counter>
-                                               <NcCounterBubble :type="!selectedGroupDecoded ? 'highlighted' : undefined">
-                                                       {{ userCount }}
-                                               </NcCounterBubble>
-                                       </template>
-                               </NcAppNavigationItem>
-                               <NcAppNavigationItem v-if="settings.isAdmin"
-                                       id="admin"
-                                       :exact="true"
-                                       :title="t('settings', 'Admins')"
-                                       :to="{ name: 'group', params: { selectedGroup: 'admin' } }"
-                                       icon="icon-user-admin">
-                                       <template v-if="adminGroupMenu.count > 0" #counter>
-                                               <NcCounterBubble :type="selectedGroupDecoded === 'admin' ? 'highlighted' : undefined">
-                                                       {{ adminGroupMenu.count }}
-                                               </NcCounterBubble>
-                                       </template>
-                               </NcAppNavigationItem>
-
-                               <!-- Hide the disabled if none, if we don't have the data (-1) show it -->
-                               <NcAppNavigationItem v-if="disabledGroupMenu.usercount > 0 || disabledGroupMenu.usercount === -1"
-                                       id="disabled"
-                                       :exact="true"
-                                       :title="t('settings', 'Disabled users')"
-                                       :to="{ name: 'group', params: { selectedGroup: 'disabled' } }"
-                                       icon="icon-disabled-users">
-                                       <template v-if="disabledGroupMenu.usercount > 0" #counter>
-                                               <NcCounterBubble :type="selectedGroupDecoded === 'disabled' ? 'highlighted' : undefined">
-                                                       {{ disabledGroupMenu.usercount }}
-                                               </NcCounterBubble>
-                                       </template>
-                               </NcAppNavigationItem>
-
-                               <NcAppNavigationCaption v-if="groupList.length > 0" :title="t('settings', 'Groups')" />
-                               <GroupListItem v-for="group in groupList"
-                                       :id="group.id"
-                                       :key="group.id"
-                                       :active="selectedGroupDecoded === group.id"
-                                       :title="group.title"
-                                       :count="group.count" />
-                       </template>
-                       <template #footer>
-                               <NcAppNavigationSettings exclude-click-outside-selectors=".vs__dropdown-menu">
-                                       <label for="default-quota-select">{{ t('settings', 'Default quota:') }}</label>
-                                       <NcSelect v-model="defaultQuota"
-                                               input-id="default-quota-select"
-                                               :taggable="true"
-                                               :options="quotaOptions"
-                                               :create-option="validateQuota"
-                                               :placeholder="t('settings', 'Select default quota')"
-                                               :clearable="false"
-                                               @option:selected="setDefaultQuota" />
-                                       <NcCheckboxRadioSwitch type="switch"
-                                               data-test="showLanguages"
-                                               :checked.sync="showLanguages">
-                                               {{ t('settings', 'Show languages') }}
-                                       </NcCheckboxRadioSwitch>
-                                       <NcCheckboxRadioSwitch type="switch"
-                                               data-test="showLastLogin"
-                                               :checked.sync="showLastLogin">
-                                               {{ t('settings', 'Show last login') }}
-                                       </NcCheckboxRadioSwitch>
-                                       <NcCheckboxRadioSwitch type="switch"
-                                               data-test="showUserBackend"
-                                               :checked.sync="showUserBackend">
-                                               {{ t('settings', 'Show user backend') }}
-                                       </NcCheckboxRadioSwitch>
-                                       <NcCheckboxRadioSwitch type="switch"
-                                               data-test="showStoragePath"
-                                               :checked.sync="showStoragePath">
-                                               {{ t('settings', 'Show storage path') }}
-                                       </NcCheckboxRadioSwitch>
-                                       <NcCheckboxRadioSwitch type="switch"
-                                               data-test="sendWelcomeMail"
-                                               :checked.sync="sendWelcomeMail"
-                                               :disabled="loadingSendMail">
-                                               {{ t('settings', 'Send email to new user') }}
-                                       </NcCheckboxRadioSwitch>
-                               </NcAppNavigationSettings>
-                       </template>
-               </NcAppNavigation>
-               <NcAppContent>
-                       <UserList :selected-group="selectedGroupDecoded"
-                               :external-actions="externalActions" />
-               </NcAppContent>
-       </NcContent>
+       <Fragment>
+               <NcContent app-name="settings" :navigation-class="{ 'icon-loading': loadingAddGroup }">
+                       <NcAppNavigation>
+                               <NcAppNavigationNew button-id="new-user-button"
+                                       :text="t('settings','New user')"
+                                       button-class="icon-add"
+                                       @click="showNewUserMenu"
+                                       @keyup.enter="showNewUserMenu"
+                                       @keyup.space="showNewUserMenu" />
+
+                               <template #list>
+                                       <NcAppNavigationNewItem id="addgroup"
+                                               ref="addGroup"
+                                               :edit-placeholder="t('settings', 'Enter group name')"
+                                               :editable="true"
+                                               :loading="loadingAddGroup"
+                                               :title="t('settings', 'Add group')"
+                                               @click="showAddGroupForm"
+                                               @new-item="createGroup">
+                                               <template #icon>
+                                                       <Plus :size="20" />
+                                               </template>
+                                       </NcAppNavigationNewItem>
+                                       <NcAppNavigationItem id="everyone"
+                                               :exact="true"
+                                               :title="t('settings', 'Active users')"
+                                               :to="{ name: 'users' }"
+                                               icon="icon-contacts-dark">
+                                               <template #counter>
+                                                       <NcCounterBubble :type="!selectedGroupDecoded ? 'highlighted' : undefined">
+                                                               {{ userCount }}
+                                                       </NcCounterBubble>
+                                               </template>
+                                       </NcAppNavigationItem>
+                                       <NcAppNavigationItem v-if="settings.isAdmin"
+                                               id="admin"
+                                               :exact="true"
+                                               :title="t('settings', 'Admins')"
+                                               :to="{ name: 'group', params: { selectedGroup: 'admin' } }"
+                                               icon="icon-user-admin">
+                                               <template v-if="adminGroupMenu.count > 0" #counter>
+                                                       <NcCounterBubble :type="selectedGroupDecoded === 'admin' ? 'highlighted' : undefined">
+                                                               {{ adminGroupMenu.count }}
+                                                       </NcCounterBubble>
+                                               </template>
+                                       </NcAppNavigationItem>
+
+                                       <!-- Hide the disabled if none, if we don't have the data (-1) show it -->
+                                       <NcAppNavigationItem v-if="disabledGroupMenu.usercount > 0 || disabledGroupMenu.usercount === -1"
+                                               id="disabled"
+                                               :exact="true"
+                                               :title="t('settings', 'Disabled users')"
+                                               :to="{ name: 'group', params: { selectedGroup: 'disabled' } }"
+                                               icon="icon-disabled-users">
+                                               <template v-if="disabledGroupMenu.usercount > 0" #counter>
+                                                       <NcCounterBubble :type="selectedGroupDecoded === 'disabled' ? 'highlighted' : undefined">
+                                                               {{ disabledGroupMenu.usercount }}
+                                                       </NcCounterBubble>
+                                               </template>
+                                       </NcAppNavigationItem>
+
+                                       <NcAppNavigationCaption v-if="groupList.length > 0" :title="t('settings', 'Groups')" />
+                                       <GroupListItem v-for="group in groupList"
+                                               :id="group.id"
+                                               :key="group.id"
+                                               :active="selectedGroupDecoded === group.id"
+                                               :title="group.title"
+                                               :count="group.count" />
+                               </template>
+
+                               <template #footer>
+                                       <ul class="app-navigation-entry__settings">
+                                               <NcAppNavigationItem :title="t('settings', 'User management settings')"
+                                                       @click="isDialogOpen = true">
+                                                       <template #icon>
+                                                               <Cog :size="20" />
+                                                       </template>
+                                               </NcAppNavigationItem>
+                                       </ul>
+                               </template>
+                       </NcAppNavigation>
+
+                       <NcAppContent>
+                               <UserList :selected-group="selectedGroupDecoded"
+                                       :external-actions="externalActions" />
+                       </NcAppContent>
+               </NcContent>
+
+               <UserSettingsDialog :open.sync="isDialogOpen" />
+       </Fragment>
 </template>
 
 <script>
 import Vue from 'vue'
 import VueLocalStorage from 'vue-localstorage'
+import { Fragment } from 'vue-frag'
 
 import NcAppContent from '@nextcloud/vue/dist/Components/NcAppContent.js'
 import NcAppNavigation from '@nextcloud/vue/dist/Components/NcAppNavigation.js'
@@ -145,26 +124,24 @@ import NcAppNavigationCaption from '@nextcloud/vue/dist/Components/NcAppNavigati
 import NcAppNavigationItem from '@nextcloud/vue/dist/Components/NcAppNavigationItem.js'
 import NcAppNavigationNew from '@nextcloud/vue/dist/Components/NcAppNavigationNew.js'
 import NcAppNavigationNewItem from '@nextcloud/vue/dist/Components/NcAppNavigationNewItem.js'
-import NcAppNavigationSettings from '@nextcloud/vue/dist/Components/NcAppNavigationSettings.js'
-import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
-import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js'
 import NcContent from '@nextcloud/vue/dist/Components/NcContent.js'
-import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
+import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js'
 
+import Cog from 'vue-material-design-icons/Cog.vue'
 import Plus from 'vue-material-design-icons/Plus.vue'
 
-import axios from '@nextcloud/axios'
-import { generateUrl } from '@nextcloud/router'
-
 import GroupListItem from '../components/GroupListItem.vue'
 import UserList from '../components/UserList.vue'
-import { unlimitedQuota } from '../utils/userUtils.ts'
+import UserSettingsDialog from '../components/Users/UserSettingsDialog.vue'
 
 Vue.use(VueLocalStorage)
 
 export default {
        name: 'Users',
+
        components: {
+               Cog,
+               Fragment,
                GroupListItem,
                NcAppContent,
                NcAppNavigation,
@@ -172,138 +149,62 @@ export default {
                NcAppNavigationItem,
                NcAppNavigationNew,
                NcAppNavigationNewItem,
-               NcAppNavigationSettings,
-               NcCheckboxRadioSwitch,
-               NcCounterBubble,
                NcContent,
-               NcSelect,
+               NcCounterBubble,
                Plus,
                UserList,
+               UserSettingsDialog,
        },
+
        props: {
                selectedGroup: {
                        type: String,
                        default: null,
                },
        },
+
        data() {
                return {
                        // temporary value used for multiselect change
-                       selectedQuota: false,
                        externalActions: [],
                        loadingAddGroup: false,
-                       loadingSendMail: false,
+                       isDialogOpen: false,
                }
        },
+
        computed: {
                showConfig() {
                        return this.$store.getters.getShowConfig
                },
+
                selectedGroupDecoded() {
                        return this.selectedGroup ? decodeURIComponent(this.selectedGroup) : null
                },
+
                users() {
                        return this.$store.getters.getUsers
                },
+
                groups() {
                        return this.$store.getters.getGroups
                },
+
                usersOffset() {
                        return this.$store.getters.getUsersOffset
                },
+
                usersLimit() {
                        return this.$store.getters.getUsersLimit
                },
 
-               // Local settings
-               showLanguages: {
-                       get() {
-                               return this.getLocalstorage('showLanguages')
-                       },
-                       set(status) {
-                               this.setLocalStorage('showLanguages', status)
-                       },
-               },
-               showLastLogin: {
-                       get() {
-                               return this.getLocalstorage('showLastLogin')
-                       },
-                       set(status) {
-                               this.setLocalStorage('showLastLogin', status)
-                       },
-               },
-               showUserBackend: {
-                       get() {
-                               return this.getLocalstorage('showUserBackend')
-                       },
-                       set(status) {
-                               this.setLocalStorage('showUserBackend', status)
-                       },
-               },
-               showStoragePath: {
-                       get() {
-                               return this.getLocalstorage('showStoragePath')
-                       },
-                       set(status) {
-                               this.setLocalStorage('showStoragePath', status)
-                       },
-               },
-
                userCount() {
                        return this.$store.getters.getUserCount
                },
+
                settings() {
                        return this.$store.getters.getServerData
                },
 
-               // default quota
-               quotaOptions() {
-                       // convert the preset array into objects
-                       const quotaPreset = this.settings.quotaPreset.reduce((acc, cur) => acc.concat({ id: cur, label: cur }), [])
-                       // add default presets
-                       if (this.settings.allowUnlimitedQuota) {
-                               quotaPreset.unshift(unlimitedQuota)
-                       }
-                       return quotaPreset
-               },
-               // mapping saved values to objects
-               defaultQuota: {
-                       get() {
-                               if (this.selectedQuota !== false) {
-                                       return this.selectedQuota
-                               }
-                               if (this.settings.defaultQuota !== unlimitedQuota.id && OC.Util.computerFileSize(this.settings.defaultQuota) >= 0) {
-                                       // if value is valid, let's map the quotaOptions or return custom quota
-                                       return { id: this.settings.defaultQuota, label: this.settings.defaultQuota }
-                               }
-                               return unlimitedQuota // unlimited
-                       },
-                       set(quota) {
-                               this.selectedQuota = quota
-                       },
-
-               },
-
-               sendWelcomeMail: {
-                       get() {
-                               return this.settings.newUserSendEmail
-                       },
-                       async set(value) {
-                               try {
-                                       this.loadingSendMail = true
-                                       this.$store.commit('setServerData', {
-                                               ...this.settings,
-                                               newUserSendEmail: value,
-                                       })
-                                       await axios.post(generateUrl('/settings/users/preferences/newUser.sendEmail'), { value: value ? 'yes' : 'no' })
-                               } catch (e) {
-                                       console.error('could not update newUser.sendEmail preference: ' + e.message, e)
-                               } finally {
-                                       this.loadingSendMail = false
-                               }
-                       },
-               },
-
                groupList() {
                        const groups = Array.isArray(this.groups) ? this.groups : []
 
@@ -316,10 +217,12 @@ export default {
                adminGroupMenu() {
                        return this.formatGroupMenu(this.groups.find(group => group.id === 'admin'))
                },
+
                disabledGroupMenu() {
                        return this.formatGroupMenu(this.groups.find(group => group.id === 'disabled'))
                },
        },
+
        beforeMount() {
                this.$store.commit('initGroups', {
                        groups: this.$store.getters.getServerData.groups,
@@ -328,6 +231,7 @@ export default {
                })
                this.$store.dispatch('getPasswordPolicyMinLength')
        },
+
        created() {
                // init the OCA.Settings.UserList object
                // and add the registerAction method
@@ -339,6 +243,7 @@ export default {
                        },
                })
        },
+
        methods: {
                showNewUserMenu() {
                        this.$store.commit('setShowConfig', {
@@ -346,62 +251,6 @@ export default {
                                value: true,
                        })
                },
-               getLocalstorage(key) {
-                       // force initialization
-                       const localConfig = this.$localStorage.get(key)
-                       // if localstorage is null, fallback to original values
-                       this.$store.commit('setShowConfig', { key, value: localConfig !== null ? localConfig === 'true' : this.showConfig[key] })
-                       return this.showConfig[key]
-               },
-               setLocalStorage(key, status) {
-                       this.$store.commit('setShowConfig', { key, value: status })
-                       this.$localStorage.set(key, status)
-                       return status
-               },
-
-               /**
-                * Dispatch default quota set request
-                *
-                * @param {string | object} quota Quota in readable format '5 GB' or Object {id: '5 GB', label: '5GB'}
-                */
-               setDefaultQuota(quota = 'none') {
-                       // Make sure correct label is set for unlimited quota
-                       if (quota === 'none') {
-                               quota = unlimitedQuota
-                       }
-                       this.$store.dispatch('setAppConfig', {
-                               app: 'files',
-                               key: 'default_quota',
-                               // ensure we only send the preset id
-                               value: quota.id ? quota.id : quota,
-                       }).then(() => {
-                               if (typeof quota !== 'object') {
-                                       quota = { id: quota, label: quota }
-                               }
-                               this.defaultQuota = quota
-                       })
-               },
-
-               /**
-                * Validate quota string to make sure it's a valid human file size
-                *
-                * @param {string | object} quota Quota in readable format '5 GB' or Object {id: '5 GB', label: '5GB'}
-                * @return {object} The validated quota object or unlimited quota if input is invalid
-                */
-               validateQuota(quota) {
-                       if (typeof quota === 'object') {
-                               quota = quota?.id || quota.label
-                       }
-                       // only used for new presets sent through @Tag
-                       const validQuota = OC.Util.computerFileSize(quota)
-                       if (validQuota === null) {
-                               return unlimitedQuota
-                       } else {
-                               // unify format output
-                               quota = OC.Util.humanFileSize(OC.Util.computerFileSize(quota))
-                               return { id: quota, label: quota }
-                       }
-               },
 
                /**
                 * Register a new action for the user menu
@@ -501,4 +350,10 @@ export default {
 .app-navigation__list #addgroup::v-deep .app-navigation-entry__utils {
        display: none;
 }
+
+.app-navigation-entry__settings {
+       height: auto !important;
+       // Prevent shrinking or growing
+       flex: 0 0 auto;
+}
 </style>