mirror of https://github.com/nextcloud/server.git
fix(settings): Migrate away from deprecated `NcPopoverMenu`
* Replace popover menu with `NcActions` * Deduplicate user actions code between `UserRow` and `UserRowSimple` * Fix user action to cover whole row heigh to prevent dropdown from shining through the actions * Fix user action popover to be overlayed by current edited row actions Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>pull/39073/head
parent
d76f39889a
commit
97683a5b66
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<NcActions :aria-label="t('settings', 'Toggle user actions menu')"
|
||||
:inline="1">
|
||||
<NcActionButton @click="toggleEdit">
|
||||
{{ edit ? t('settings', 'Done') : t('settings', 'Edit') }}
|
||||
<template #icon>
|
||||
<NcIconSvgWrapper :svg="editSvg" aria-hidden="true" />
|
||||
</template>
|
||||
</NcActionButton>
|
||||
<NcActionButton v-for="(action, index) in actions"
|
||||
:key="index"
|
||||
:aria-label="action.text"
|
||||
:icon="action.icon"
|
||||
@click="action.action">
|
||||
{{ action.text }}
|
||||
</NcActionButton>
|
||||
</NcActions>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue'
|
||||
|
||||
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
|
||||
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
|
||||
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
|
||||
import SvgCheck from '@mdi/svg/svg/check.svg?raw'
|
||||
import SvgPencil from '@mdi/svg/svg/pencil.svg?raw'
|
||||
|
||||
interface UserAction {
|
||||
action: (event: MouseEvent) => void,
|
||||
icon: string,
|
||||
text: string
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
NcActionButton,
|
||||
NcActions,
|
||||
NcIconSvgWrapper,
|
||||
},
|
||||
|
||||
props: {
|
||||
/**
|
||||
* Array of user actions
|
||||
*/
|
||||
actions: {
|
||||
type: Array as PropType<readonly UserAction[]>,
|
||||
required: true,
|
||||
},
|
||||
|
||||
/**
|
||||
* The state whether the row is currently edited
|
||||
*/
|
||||
edit: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
/**
|
||||
* Current MDI logo to show for edit toggle
|
||||
*/
|
||||
editSvg() {
|
||||
return this.edit ? SvgCheck : SvgPencil
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Toggle edit mode by emitting the update event
|
||||
*/
|
||||
toggleEdit() {
|
||||
this.$emit('update:edit', !this.edit)
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
*
|
||||
* @author Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
*
|
||||
* @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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import { User } from '@nextcloud/cypress'
|
||||
|
||||
const admin = new User('admin', 'admin')
|
||||
const jdoe = new User('jdoe', 'jdoe')
|
||||
|
||||
describe('Settings: Disable and enable users', function() {
|
||||
before(function() {
|
||||
cy.createUser(jdoe)
|
||||
cy.login(admin)
|
||||
})
|
||||
|
||||
after(() => {
|
||||
cy.deleteUser(jdoe)
|
||||
})
|
||||
|
||||
it('Can disable the user', function() {
|
||||
// ensure user is enabled
|
||||
cy.enableUser(jdoe)
|
||||
// open the User settings
|
||||
cy.visit('/settings/users')
|
||||
// see that the user is in the list of active users
|
||||
cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(() => {
|
||||
// see that the list of users contains the user jdoe
|
||||
cy.contains(jdoe.userId).should('exist')
|
||||
// open the actions menu for the user
|
||||
cy.get('.userActions button.action-item__menutoggle').click()
|
||||
})
|
||||
|
||||
// The "Disable user" action in the actions menu is shown and clicked
|
||||
cy.get('.action-item__popper .action').contains('Disable user').should('exist').click()
|
||||
// When clicked the section is not shown anymore
|
||||
cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).should('not.exist')
|
||||
// But the disabled user section now exists
|
||||
cy.get('#disabled').should('exist')
|
||||
// Open disabled users section
|
||||
cy.get('#disabled a').click()
|
||||
cy.url().should('match', /\/disabled/)
|
||||
// The list of disabled users should now contain the user
|
||||
cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).should('exist')
|
||||
})
|
||||
|
||||
it('Can enable the user', function() {
|
||||
// ensure user is disabled
|
||||
cy.enableUser(jdoe, false)
|
||||
// open the User settings
|
||||
cy.visit('/settings/users')
|
||||
|
||||
// Open disabled users section
|
||||
cy.get('#disabled a').click()
|
||||
cy.url().should('match', /\/disabled/)
|
||||
|
||||
cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(() => {
|
||||
// see that the list of disabled users contains the user jdoe
|
||||
cy.contains(jdoe.userId).should('exist')
|
||||
// open the actions menu for the user
|
||||
cy.get('.userActions button.action-item__menutoggle').click()
|
||||
})
|
||||
|
||||
// The "Enable user" action in the actions menu is shown and clicked
|
||||
cy.get('.action-item__popper .action').contains('Enable user').should('exist').click()
|
||||
// When clicked the section is not shown anymore
|
||||
cy.get('#disabled').should('not.exist')
|
||||
// Make sure it is still gone after the reload reload
|
||||
cy.reload().login(admin)
|
||||
cy.get('#disabled').should('not.exist')
|
||||
})
|
||||
})
|
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
*
|
||||
* @author Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
*
|
||||
* @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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import { User } from '@nextcloud/cypress'
|
||||
|
||||
const admin = new User('admin', 'admin')
|
||||
const jdoe = new User('jdoe', 'jdoe')
|
||||
|
||||
describe('Settings: Change user properties', function() {
|
||||
before(function() {
|
||||
cy.createUser(jdoe)
|
||||
cy.login(admin)
|
||||
})
|
||||
|
||||
after(() => {
|
||||
cy.deleteUser(jdoe)
|
||||
})
|
||||
|
||||
it('Can change the password', function() {
|
||||
// open the User settings
|
||||
cy.visit('/settings/users')
|
||||
|
||||
cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(($row) => {
|
||||
// see that the list of users contains the user jdoe
|
||||
cy.contains(jdoe.userId).should('exist')
|
||||
// toggle the edit mode for the user jdoe
|
||||
cy.get('.userActions .action-items > button:first-of-type').click()
|
||||
})
|
||||
|
||||
cy.get(`.user-list-grid .row[data-id="${jdoe.userId}"]`).within(($row) => {
|
||||
// see that the edit mode is on
|
||||
cy.wrap($row).should('have.class', 'row--editable')
|
||||
// see that the password of user0 is ""
|
||||
cy.get('input[type="password"]').should('exist').and('have.value', '')
|
||||
// set the password for user0 to 123456
|
||||
cy.get('input[type="password"]').type('123456')
|
||||
// When I set the password for user0 to 123456
|
||||
cy.get('input[type="password"]').should('have.value', '123456')
|
||||
cy.get('.password button').click()
|
||||
|
||||
// Ignore failure if modal is not shown
|
||||
cy.once('fail', (error) => {
|
||||
expect(error.name).to.equal('AssertionError')
|
||||
expect(error).to.have.property('node', '.modal-container')
|
||||
})
|
||||
// Make sure no confirmation modal is shown
|
||||
cy.root().closest('body').find('.modal-container').then(($modal) => {
|
||||
if ($modal.length > 0) {
|
||||
cy.wrap($modal).find('input[type="password"]').type(admin.password)
|
||||
cy.wrap($modal).find('button').contains('Confirm').click()
|
||||
}
|
||||
})
|
||||
|
||||
// see that the password cell for user user0 is done loading
|
||||
cy.get('.user-row-text-field.icon-loading-small').should('exist')
|
||||
cy.waitUntil(() => cy.get('.user-row-text-field.icon-loading-small').should('not.exist'), { timeout: 10000 })
|
||||
// password input is emptied on change
|
||||
cy.get('input[type="password"]').should('have.value', '')
|
||||
})
|
||||
// Success message is shown
|
||||
cy.get('.toastify.toast-success').contains(/Password.+successfully.+changed/i).should('exist')
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue