The should ease the maintenance of it due to reduced complexity. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>pull/44092/head
parent
1100e908b7
commit
30d5b02811
@ -0,0 +1,52 @@ |
||||
import type { ComputedRef, Ref } from 'vue' |
||||
import type { IGroup } from '../views/user-types' |
||||
|
||||
import { computed } from 'vue' |
||||
|
||||
/** |
||||
* Format a group to a menu entry |
||||
* |
||||
* @param group the group |
||||
*/ |
||||
function formatGroupMenu(group?: IGroup) { |
||||
if (typeof group === 'undefined') { |
||||
return null |
||||
} |
||||
|
||||
const item = { |
||||
id: group.id, |
||||
title: group.name, |
||||
usercount: group.usercount, |
||||
count: Math.max(0, group.usercount - group.disabled), |
||||
} |
||||
|
||||
return item |
||||
} |
||||
|
||||
export const useFormatGroups = (groups: Ref<IGroup[]>|ComputedRef<IGroup[]>) => { |
||||
/** |
||||
* All non-disabled non-admin groups |
||||
*/ |
||||
const userGroups = computed(() => { |
||||
const formatted = groups.value |
||||
// filter out disabled and admin
|
||||
.filter(group => group.id !== 'disabled' && group.id !== 'admin') |
||||
// format group
|
||||
.map(group => formatGroupMenu(group)) |
||||
// remove invalid
|
||||
.filter(group => group !== null) |
||||
return formatted as NonNullable<ReturnType<typeof formatGroupMenu>>[] |
||||
}) |
||||
|
||||
/** |
||||
* The admin group if found otherwise null |
||||
*/ |
||||
const adminGroup = computed(() => formatGroupMenu(groups.value.find(group => group.id === 'admin'))) |
||||
|
||||
/** |
||||
* The group of disabled users |
||||
*/ |
||||
const disabledGroup = computed(() => formatGroupMenu(groups.value.find(group => group.id === 'disabled'))) |
||||
|
||||
return { adminGroup, disabledGroup, userGroups } |
||||
} |
@ -1,5 +1,222 @@ |
||||
<template> |
||||
<div>...</div> |
||||
<NcAppNavigation :aria-label="t('settings', 'Account management')"> |
||||
<NcAppNavigationNew button-id="new-user-button" |
||||
:text="t('settings','New account')" |
||||
@click="showNewUserMenu" |
||||
@keyup.enter="showNewUserMenu" |
||||
@keyup.space="showNewUserMenu"> |
||||
<template #icon> |
||||
<NcIconSvgWrapper :path="mdiPlus" /> |
||||
</template> |
||||
</NcAppNavigationNew> |
||||
|
||||
<NcAppNavigationList class="account-management__system-list" |
||||
data-cy-users-settings-navigation-groups="system"> |
||||
<NcAppNavigationItem id="everyone" |
||||
:exact="true" |
||||
:name="t('settings', 'Active accounts')" |
||||
:to="{ name: 'users' }"> |
||||
<template #icon> |
||||
<NcIconSvgWrapper :path="mdiAccount" /> |
||||
</template> |
||||
<template #counter> |
||||
<NcCounterBubble v-if="userCount" :type="!selectedGroupDecoded ? 'highlighted' : undefined"> |
||||
{{ userCount }} |
||||
</NcCounterBubble> |
||||
</template> |
||||
</NcAppNavigationItem> |
||||
|
||||
<NcAppNavigationItem v-if="isAdmin" |
||||
id="admin" |
||||
:exact="true" |
||||
:name="t('settings', 'Admins')" |
||||
:to="{ name: 'group', params: { selectedGroup: 'admin' } }"> |
||||
<template #icon> |
||||
<NcIconSvgWrapper :path="mdiShieldAccount" /> |
||||
</template> |
||||
<template #counter> |
||||
<NcCounterBubble v-if="adminGroup && adminGroup.count > 0" |
||||
:type="selectedGroupDecoded === 'admin' ? 'highlighted' : undefined"> |
||||
{{ adminGroup.count }} |
||||
</NcCounterBubble> |
||||
</template> |
||||
</NcAppNavigationItem> |
||||
|
||||
<!-- Hide the disabled if none, if we don't have the data (-1) show it --> |
||||
<NcAppNavigationItem v-if="disabledGroup && (disabledGroup.usercount > 0 || disabledGroup.usercount === -1)" |
||||
id="disabled" |
||||
:exact="true" |
||||
:name="t('settings', 'Disabled accounts')" |
||||
:to="{ name: 'group', params: { selectedGroup: 'disabled' } }"> |
||||
<template #icon> |
||||
<NcIconSvgWrapper :path="mdiAccountOff" /> |
||||
</template> |
||||
<template v-if="disabledGroup.usercount > 0" #counter> |
||||
<NcCounterBubble :type="selectedGroupDecoded === 'disabled' ? 'highlighted' : undefined"> |
||||
{{ disabledGroup.usercount }} |
||||
</NcCounterBubble> |
||||
</template> |
||||
</NcAppNavigationItem> |
||||
</NcAppNavigationList> |
||||
|
||||
<NcAppNavigationCaption :name="t('settings', 'Groups')" |
||||
:disabled="loadingAddGroup" |
||||
:aria-label="loadingAddGroup ? t('settings', 'Creating group…') : t('settings', 'Create group')" |
||||
force-menu |
||||
is-heading |
||||
:open.sync="isAddGroupOpen"> |
||||
<template #actionsTriggerIcon> |
||||
<NcLoadingIcon v-if="loadingAddGroup" /> |
||||
<NcIconSvgWrapper v-else :path="mdiPlus" /> |
||||
</template> |
||||
<template #actions> |
||||
<NcActionText> |
||||
<template #icon> |
||||
<AccountGroup :size="20" /> |
||||
</template> |
||||
{{ t('settings', 'Create group') }} |
||||
</NcActionText> |
||||
<NcActionInput :label="t('settings', 'Group name')" |
||||
data-cy-users-settings-new-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> |
||||
|
||||
<NcAppNavigationList class="account-management__group-list" data-cy-users-settings-navigation-groups="custom"> |
||||
<GroupListItem v-for="group in userGroups" |
||||
:id="group.id" |
||||
:key="group.id" |
||||
:active="selectedGroupDecoded === group.id" |
||||
:name="group.title" |
||||
:count="group.count" /> |
||||
</NcAppNavigationList> |
||||
|
||||
<template #footer> |
||||
<NcButton class="account-management__settings-toggle" |
||||
type="tertiary" |
||||
@click="isDialogOpen = true"> |
||||
<template #icon> |
||||
<NcIconSvgWrapper :path="mdiCog" /> |
||||
</template> |
||||
{{ t('settings', 'Account management settings') }} |
||||
</NcButton> |
||||
<UserSettingsDialog :open.sync="isDialogOpen" /> |
||||
</template> |
||||
</NcAppNavigation> |
||||
</template> |
||||
<script setup> |
||||
|
||||
<script setup lang="ts"> |
||||
import { mdiAccount, mdiAccountOff, mdiCog, mdiPlus, mdiShieldAccount } from '@mdi/js' |
||||
import { showError } from '@nextcloud/dialogs' |
||||
import { translate as t } from '@nextcloud/l10n' |
||||
import { computed, ref } from 'vue' |
||||
|
||||
import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js' |
||||
import NcActionText from '@nextcloud/vue/dist/Components/NcActionText.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 NcAppNavigationList from '@nextcloud/vue/dist/Components/NcAppNavigationList.js' |
||||
import NcAppNavigationNew from '@nextcloud/vue/dist/Components/NcAppNavigationNew.js' |
||||
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' |
||||
import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js' |
||||
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js' |
||||
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' |
||||
|
||||
import GroupListItem from '../components/GroupListItem.vue' |
||||
import UserSettingsDialog from '../components/Users/UserSettingsDialog.vue' |
||||
import { useStore } from '../store' |
||||
import { useRoute, useRouter } from 'vue-router/composables' |
||||
import { useFormatGroups } from '../composables/useGroupsNavigation' |
||||
|
||||
const route = useRoute() |
||||
const router = useRouter() |
||||
const store = useStore() |
||||
|
||||
/** State of the 'new-account' dialog */ |
||||
const isDialogOpen = ref(false) |
||||
|
||||
/** Current active group in the view - this is URL encoded */ |
||||
const selectedGroup = computed(() => route.params?.selectedGroup) |
||||
/** Current active group - URL decoded */ |
||||
const selectedGroupDecoded = computed(() => selectedGroup.value ? decodeURIComponent(selectedGroup.value) : null) |
||||
|
||||
/** Overall user count */ |
||||
const userCount = computed(() => store.getters.getUserCount) |
||||
/** All available groups */ |
||||
const groups = computed(() => store.getters.getGroups) |
||||
const { adminGroup, disabledGroup, userGroups } = useFormatGroups(groups) |
||||
|
||||
/** True if the current user is an administrator */ |
||||
const isAdmin = computed(() => store.getters.getServerData.isAdmin) |
||||
|
||||
/** True if the 'add-group' dialog is open - needed to be able to close it when the group is created */ |
||||
const isAddGroupOpen = ref(false) |
||||
/** True if the group creation is in progress to show loading spinner and disable adding another one */ |
||||
const loadingAddGroup = ref(false) |
||||
/** Error state for creating a new group */ |
||||
const hasAddGroupError = ref(false) |
||||
/** Name of the group to create (used in the group creation dialog) */ |
||||
const newGroupName = ref('') |
||||
|
||||
/** |
||||
* Create a new group |
||||
*/ |
||||
async function createGroup() { |
||||
hasAddGroupError.value = false |
||||
const groupId = newGroupName.value.trim() |
||||
if (groupId === '') { |
||||
hasAddGroupError.value = true |
||||
return |
||||
} |
||||
|
||||
isAddGroupOpen.value = false |
||||
loadingAddGroup.value = true |
||||
|
||||
try { |
||||
await store.dispatch('addGroup', groupId) |
||||
await router.push({ |
||||
name: 'group', |
||||
params: { |
||||
selectedGroup: encodeURIComponent(groupId), |
||||
}, |
||||
}) |
||||
newGroupName.value = '' |
||||
} catch { |
||||
showError(t('settings', 'Failed to create group')) |
||||
} |
||||
loadingAddGroup.value = false |
||||
} |
||||
|
||||
/** |
||||
* Open the new-user form dialog |
||||
*/ |
||||
function showNewUserMenu() { |
||||
store.commit('setShowConfig', { |
||||
key: 'showNewUserForm', |
||||
value: true, |
||||
}) |
||||
} |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
.account-management{ |
||||
&__system-list { |
||||
height: auto !important; |
||||
overflow: visible !important; |
||||
} |
||||
|
||||
&__group-list { |
||||
height: 100% !important; |
||||
} |
||||
|
||||
&__settings-toggle { |
||||
margin-bottom: 12px; |
||||
} |
||||
} |
||||
</style> |
||||
|
@ -0,0 +1,14 @@ |
||||
export interface IGroup { |
||||
id: string |
||||
name: string |
||||
|
||||
/** |
||||
* Overall user count |
||||
*/ |
||||
usercount: number |
||||
|
||||
/** |
||||
* Number of disabled users |
||||
*/ |
||||
disabled: number |
||||
} |
Loading…
Reference in new issue