Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enh(settings): Add and remove groups accessibly #40110

Merged
merged 4 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 107 additions & 43 deletions apps/settings/src/components/GroupListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,56 +21,101 @@
-->

<template>
<NcAppNavigationItem :key="id"
:exact="true"
:name="name"
:to="{ name: 'group', params: { selectedGroup: encodeURIComponent(id) } }"
:loading="loadingRenameGroup"
:menu-open="openGroupMenu"
@update:menuOpen="handleGroupMenuOpen">
<template #icon>
<AccountGroup :size="20" />
</template>
<template #counter>
<NcCounterBubble v-if="count"
:type="active ? 'highlighted' : undefined">
{{ count }}
</NcCounterBubble>
</template>
<template #actions>
<NcActionInput v-if="id !== 'admin' && id !== 'disabled' && settings.isAdmin"
ref="displayNameInput"
icon="icon-edit"
:trailing-button-label="t('settings', 'Submit')"
type="text"
:value="name"
:label=" t('settings', 'Rename group')"
@submit="renameGroup(id)" />
<NcActionButton v-if="id !== 'admin' && id !== 'disabled' && settings.isAdmin"
icon="icon-delete"
@click="removeGroup(id)">
{{ t('settings', 'Remove group') }}
</NcActionButton>
</template>
</NcAppNavigationItem>
<Fragment>
<NcModal v-if="showRemoveGroupModal"
@close="showRemoveGroupModal = false">
<div class="modal__content">
<h2 class="modal__header">
{{ t('settings', 'Please confirm the group removal') }}
</h2>
<NcNoteCard type="warning"
show-alert>
{{ t('settings', 'You are about to remove the group "{group}". The users will NOT be deleted.', { group: name }) }}
</NcNoteCard>
<div class="modal__button-row">
<NcButton type="secondary"
@click="showRemoveGroupModal = false">
{{ t('settings', 'Cancel') }}
</NcButton>
<NcButton type="primary"
@click="removeGroup">
{{ t('settings', 'Confirm') }}
</NcButton>
</div>
</div>
</NcModal>

<NcAppNavigationItem :key="id"
:exact="true"
:name="name"
:to="{ name: 'group', params: { selectedGroup: encodeURIComponent(id) } }"
:loading="loadingRenameGroup"
:menu-open="openGroupMenu"
@update:menuOpen="handleGroupMenuOpen">
<template #icon>
<AccountGroup :size="20" />
</template>
<template #counter>
<NcCounterBubble v-if="count"
:type="active ? 'highlighted' : undefined">
{{ count }}
</NcCounterBubble>
</template>
<template #actions>
<NcActionInput v-if="id !== 'admin' && id !== 'disabled' && settings.isAdmin"
ref="displayNameInput"
:trailing-button-label="t('settings', 'Submit')"
type="text"
:value="name"
:label=" t('settings', 'Rename group')"
@submit="renameGroup(id)">
<template #icon>
<Pencil :size="20" />
</template>
</NcActionInput>
<NcActionButton v-if="id !== 'admin' && id !== 'disabled' && settings.isAdmin"
@click="showRemoveGroupModal = true">
<template #icon>
<Delete :size="20" />
</template>
{{ t('settings', 'Remove group') }}
</NcActionButton>
</template>
</NcAppNavigationItem>
</Fragment>
</template>

<script>
import { Fragment } from 'vue-frag'

import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js'
import NcAppNavigationItem from '@nextcloud/vue/dist/Components/NcAppNavigationItem.js'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js'
import NcModal from '@nextcloud/vue/dist/Components/NcModal.js'
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'

import AccountGroup from 'vue-material-design-icons/AccountGroup.vue'
import Delete from 'vue-material-design-icons/Delete.vue'
import Pencil from 'vue-material-design-icons/Pencil.vue'

import { showError } from '@nextcloud/dialogs'

export default {
name: 'GroupListItem',
components: {
AccountGroup,
Delete,
Fragment,
NcActionButton,
NcActionInput,
NcAppNavigationItem,
NcButton,
NcCounterBubble,
NcModal,
NcNoteCard,
Pencil,
},
props: {
/**
Expand Down Expand Up @@ -106,6 +151,7 @@ export default {
return {
loadingRenameGroup: false,
openGroupMenu: false,
showRemoveGroupModal: false,
}
},
computed: {
Expand Down Expand Up @@ -144,18 +190,36 @@ export default {
this.loadingRenameGroup = false
}
},
removeGroup(groupid) {
// TODO migrate to a vue js confirm dialog component
OC.dialogs.confirm(
t('settings', 'You are about to remove the group {group}. The users will NOT be deleted.', { group: groupid }),
t('settings', 'Please confirm the group removal '),
(success) => {
if (success) {
this.$store.dispatch('removeGroup', groupid)
}
},
)
async removeGroup() {
try {
await this.$store.dispatch('removeGroup', this.id)
this.showRemoveGroupModal = false
} catch (error) {
showError(t('settings', 'Failed to remove group "{group}"', { group: this.name }))
}
},
},
}
</script>

<style lang="scss" scoped>
.modal {
&__header {
margin: 0;
}

&__content {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
gap: 4px 0;
}

&__button-row {
display: flex;
width: 100%;
justify-content: space-between;
}
}
</style>
2 changes: 1 addition & 1 deletion apps/settings/src/store/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ const mutations = {
id: gid,
name: displayName,
})
state.groups.push(group)
state.groups.unshift(group)
state.groups = orderGroups(state.groups, state.orderBy)
} catch (e) {
console.error('Can\'t create group', e)
Expand Down
99 changes: 53 additions & 46 deletions apps/settings/src/views/Users.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<template>
<Fragment>
<NcContent app-name="settings" :navigation-class="{ 'icon-loading': loadingAddGroup }">
<NcContent app-name="settings">
<NcAppNavigation>
<NcAppNavigationNew button-id="new-user-button"
:text="t('settings','New user')"
Expand All @@ -36,18 +36,6 @@
</NcAppNavigationNew>

<template #list>
<NcAppNavigationNewItem id="addgroup"
ref="addGroup"
:edit-placeholder="t('settings', 'Enter group name')"
:editable="true"
:loading="loadingAddGroup"
:name="t('settings', 'Add group')"
@click="showAddGroupForm"
@new-item="createGroup">
<template #icon>
<Plus :size="20" />
</template>
</NcAppNavigationNewItem>
<NcAppNavigationItem id="everyone"
:exact="true"
:name="t('settings', 'Active users')"
Expand All @@ -61,6 +49,7 @@
</NcCounterBubble>
</template>
</NcAppNavigationItem>

<NcAppNavigationItem v-if="settings.isAdmin"
id="admin"
:exact="true"
Expand Down Expand Up @@ -92,7 +81,32 @@
</template>
</NcAppNavigationItem>

<NcAppNavigationCaption v-if="groupList.length > 0" :name="t('settings', 'Groups')" />
<NcAppNavigationCaption :name="t('settings', 'Groups')"
:disabled="loadingAddGroup"
:aria-label="loadingAddGroup ? t('settings', 'Creating group …') : t('settings', 'Create group')"
force-menu
:open.sync="isAddGroupOpen">
<template #actionsTriggerIcon>
<NcLoadingIcon v-if="loadingAddGroup" />
<Plus v-else :size="20" />
</template>
<template #actions>
<NcActionText>
<template #icon>
<AccountGroup :size="20" />
</template>
{{ t('settings', 'Create group') }}
</NcActionText>
<NcActionInput :label="t('settings', 'Group name')"
:label-outside="false"
:disabled="loadingAddGroup"
:value.sync="newGroupName"
:error="hasAddGroupError"
:helper-text="hasAddGroupError ? t('settings', 'Please enter a valid group name') : ''"
@submit="createGroup" />
</template>
</NcAppNavigationCaption>

<GroupListItem v-for="group in groupList"
:id="group.id"
:key="group.id"
Expand Down Expand Up @@ -127,15 +141,19 @@
import Vue from 'vue'
import VueLocalStorage from 'vue-localstorage'
import { Fragment } from 'vue-frag'
import { translate as t } from '@nextcloud/l10n'
import { showError } from '@nextcloud/dialogs'

import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js'
import NcActionText from '@nextcloud/vue/dist/Components/NcActionText.js'
import NcAppContent from '@nextcloud/vue/dist/Components/NcAppContent.js'
import NcAppNavigation from '@nextcloud/vue/dist/Components/NcAppNavigation.js'
import NcAppNavigationCaption from '@nextcloud/vue/dist/Components/NcAppNavigationCaption.js'
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 NcContent from '@nextcloud/vue/dist/Components/NcContent.js'
import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'

import AccountGroup from 'vue-material-design-icons/AccountGroup.vue'
import AccountOff from 'vue-material-design-icons/AccountOff.vue'
Expand All @@ -158,14 +176,16 @@ export default {
Cog,
Fragment,
GroupListItem,
NcActionInput,
NcActionText,
NcAppContent,
NcAppNavigation,
NcAppNavigationCaption,
NcAppNavigationItem,
NcAppNavigationNew,
NcAppNavigationNewItem,
NcContent,
NcCounterBubble,
NcLoadingIcon,
Plus,
ShieldAccount,
UserList,
Expand All @@ -183,7 +203,10 @@ export default {
return {
// temporary value used for multiselect change
externalActions: [],
newGroupName: '',
isAddGroupOpen: false,
loadingAddGroup: false,
hasAddGroupError: false,
isDialogOpen: false,
}
},
Expand Down Expand Up @@ -261,6 +284,8 @@ export default {
},

methods: {
t,

showNewUserMenu() {
this.$store.commit('setShowConfig', {
key: 'showNewUserForm',
Expand All @@ -287,43 +312,30 @@ export default {

/**
* Create a new group
*
* @param {string} gid The group id
*/
async createGroup(gid) {
// group is not valid
if (gid.trim() === '') {
async createGroup() {
this.hasAddGroupError = false
const groupId = this.newGroupName.trim()
if (groupId === '') {
this.hasAddGroupError = true
return
}

this.isAddGroupOpen = false
this.loadingAddGroup = true
try {
this.loadingAddGroup = true
await this.$store.dispatch('addGroup', gid.trim())

this.hideAddGroupForm()
await this.$store.dispatch('addGroup', groupId)
await this.$router.push({
name: 'group',
params: {
selectedGroup: encodeURIComponent(gid.trim()),
selectedGroup: encodeURIComponent(groupId),
},
})
this.newGroupName = ''
} catch {
this.showAddGroupForm()
} finally {
this.loadingAddGroup = false
showError(t('settings', 'Failed to create group'))
}
},

showAddGroupForm() {
this.$refs.addGroup.newItemActive = true
this.$nextTick(() => {
this.$refs.addGroup.$refs.newItemInput.focusInput()
})
},

hideAddGroupForm() {
this.$refs.addGroup.newItemActive = false
this.$refs.addGroup.newItemValue = ''
this.loadingAddGroup = false
},

/**
Expand Down Expand Up @@ -362,11 +374,6 @@ export default {
max-height: 100%;
}

// force hiding the editing action for the add group entry
.app-navigation__list #addgroup::v-deep .app-navigation-entry__utils {
display: none;
}

Pytal marked this conversation as resolved.
Show resolved Hide resolved
.app-navigation-entry__settings {
height: auto !important;
// Prevent shrinking or growing
Expand Down
Loading