Переглянути джерело

Merge pull request #39402 from nextcloud/enh/a11y-users-settings

tags/v28.0.0beta1
Pytal 10 місяці тому
джерело
коміт
608ba174a3
Аккаунт користувача з таким Email не знайдено

+ 280
- 0
apps/settings/src/components/Users/UserSettingsDialog.vue Переглянути файл

@@ -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>

+ 119
- 264
apps/settings/src/views/Users.vue Переглянути файл

@@ -21,123 +21,102 @@
-->

<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>

+ 24
- 22
cypress/e2e/settings/users_columns.cy.ts Переглянути файл

@@ -32,16 +32,18 @@ describe('Settings: Show and hide columns', function() {
})

beforeEach(function() {
// open the settings pane
cy.get('.app-navigation button.settings-button').click()
// reset all toggles
cy.get('.app-navigation #app-settings__content input[type="checkbox"]').uncheck({ force: true })
// enable the last login toggle
cy.get('.app-navigation #app-settings__content').within(() => {
// open the settings dialog
cy.get('.app-navigation-entry__settings').contains('User management settings').click()
// reset all visibility toggles
cy.get('.modal-container #settings-section_visibility-settings input[type="checkbox"]').uncheck({ force: true })

cy.get('.modal-container').within(() => {
// enable the last login toggle
cy.get('[data-test="showLastLogin"] input[type="checkbox"]').check({ force: true })
// close the settings dialog
cy.get('button.modal-container__close').click()
})
// close the settings pane
cy.get('.app-navigation button.settings-button').click()
cy.waitUntil(() => cy.get('.modal-container').should('not.be.visible'))
})

it('Can show a column', function() {
@@ -55,18 +57,18 @@ describe('Settings: Show and hide columns', function() {
cy.wrap($row).get('[data-test="language"]').should('not.exist')
})

// open the settings pane
cy.get('.app-navigation button.settings-button').click()
// open the settings dialog
cy.get('.app-navigation-entry__settings').contains('User management settings').click()

// enable the languages toggle
cy.get('.app-navigation #app-settings__content').within(() => {
cy.get('.modal-container').within(() => {
// enable the language toggle
cy.get('[data-test="showLanguages"] input[type="checkbox"]').should('not.be.checked')
cy.get('[data-test="showLanguages"] input[type="checkbox"]').check({ force: true })
cy.get('[data-test="showLanguages"] input[type="checkbox"]').should('be.checked')
// close the settings dialog
cy.get('button.modal-container__close').click()
})

// close the settings pane
cy.get('.app-navigation button.settings-button').click()
cy.waitUntil(() => cy.get('.modal-container').should('not.be.visible'))

// see that the language column is in the header
cy.get(`.user-list__header tr`).within(() => {
@@ -90,18 +92,18 @@ describe('Settings: Show and hide columns', function() {
cy.wrap($row).get('[data-test="lastLogin"]').should('exist')
})

// open the settings pane
cy.get('.app-navigation button.settings-button').click()
// open the settings dialog
cy.get('.app-navigation-entry__settings').contains('User management settings').click()

// disable the last login toggle
cy.get('.app-navigation #app-settings__content').within(() => {
cy.get('.modal-container').within(() => {
// disable the last login toggle
cy.get('[data-test="showLastLogin"] input[type="checkbox"]').should('be.checked')
cy.get('[data-test="showLastLogin"] input[type="checkbox"]').uncheck({ force: true })
cy.get('[data-test="showLastLogin"] input[type="checkbox"]').should('not.be.checked')
// close the settings dialog
cy.get('button.modal-container__close').click()
})

// close the settings pane
cy.get('.app-navigation button.settings-button').click()
cy.waitUntil(() => cy.get('.modal-container').should('not.be.visible'))

// see that the last login column is not in the header
cy.get(`.user-list__header tr`).within(() => {

+ 2
- 2
dist/settings-users-8351.js
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 3
- 1
dist/settings-users-8351.js.LICENSE.txt Переглянути файл

@@ -4,6 +4,8 @@

/*! For license information please see NcAppNavigationNewItem.js.LICENSE.txt */

/*! For license information please see NcAppNavigationSettings.js.LICENSE.txt */
/*! For license information please see NcAppSettingsDialog.js.LICENSE.txt */

/*! For license information please see NcAppSettingsSection.js.LICENSE.txt */

/*! For license information please see NcIconSvgWrapper.js.LICENSE.txt */

+ 1
- 1
dist/settings-users-8351.js.map
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 2
- 2
dist/settings-vue-settings-apps-users-management.js
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 1
- 1
dist/settings-vue-settings-apps-users-management.js.map
Різницю між файлами не показано, бо вона завелика
Переглянути файл


Завантаження…
Відмінити
Зберегти