feat(settings): Namespace group routes

Signed-off-by: Christopher Ng <chrng8@gmail.com>
This commit is contained in:
Christopher Ng 2024-08-30 16:29:57 -07:00
parent 558fbcda72
commit fb5dd8a259
9 changed files with 104 additions and 40 deletions

View file

@ -170,7 +170,7 @@ class UsersController extends Controller {
}
$recentUsersGroup = [
'id' => '__nc_internal_recent',
'id' => 'recent',
'name' => $this->l10n->t('Recently active'),
'usercount' => $userCount,
];
@ -203,7 +203,8 @@ class UsersController extends Controller {
/* FINAL DATA */
$serverData = [];
// groups
$serverData['groups'] = array_merge_recursive($adminGroup, [$recentUsersGroup, $disabledUsersGroup], $groups);
$serverData['sectionGroups'] = [$recentUsersGroup, $disabledUsersGroup];
$serverData['groups'] = array_merge($adminGroup, $groups);
// Various data
$serverData['isAdmin'] = $isAdmin;
$serverData['isDelegatedAdmin'] = $isDelegatedAdmin;

View file

@ -31,7 +31,7 @@
<NcAppNavigationItem :key="id"
:exact="true"
:name="name"
:to="{ name: 'group', params: { selectedGroup: encodeURIComponent(id) } }"
:to="{ name: 'group', params: { group: encodeURIComponent(id) } }"
:loading="loadingRenameGroup"
:menu-open="openGroupMenu"
@update:menuOpen="handleGroupMenuOpen">
@ -45,7 +45,7 @@
</NcCounterBubble>
</template>
<template #actions>
<NcActionInput v-if="id !== 'admin' && id !== 'disabled' && (settings.isAdmin || settings.isDelegatedAdmin)"
<NcActionInput v-if="id !== 'admin' && (settings.isAdmin || settings.isDelegatedAdmin)"
ref="displayNameInput"
:trailing-button-label="t('settings', 'Submit')"
type="text"
@ -56,7 +56,7 @@
<Pencil :size="20" />
</template>
</NcActionInput>
<NcActionButton v-if="id !== 'admin' && id !== 'disabled' && (settings.isAdmin || settings.isDelegatedAdmin)"
<NcActionButton v-if="id !== 'admin' && (settings.isAdmin || settings.isDelegatedAdmin)"
@click="showRemoveGroupModal = true">
<template #icon>
<Delete :size="20" />

View file

@ -113,6 +113,10 @@ export default {
type: String,
default: null,
},
selectedSection: {
type: String,
default: null,
},
externalActions: {
type: Array,
default: () => [],
@ -166,17 +170,15 @@ export default {
},
filteredUsers() {
if (this.selectedGroup === 'disabled') {
if (this.selectedSection === 'disabled') {
return this.users.filter(user => user.enabled === false)
}
return this.users.filter(user => user.enabled !== false)
},
groups() {
// data provided php side + remove the recent and disabled groups
return this.$store.getters.getGroups
.filter(group => group.id !== '__nc_internal_recent' && group.id !== 'disabled')
.sort((a, b) => a.name.localeCompare(b.name))
.toSorted((a, b) => a.name.localeCompare(b.name))
},
subAdminsGroups() {
@ -234,8 +236,8 @@ export default {
},
watch: {
// watch url change and group select
async selectedGroup(val) {
// watch url change and section select
async selectedSection(val) {
this.isInitialLoad = true
// if selected is the disabled group but it's empty
await this.redirectIfDisabled()
@ -244,6 +246,14 @@ export default {
this.setNewUserDefaultGroup(val)
},
// watch url change and group select
async selectedGroup(val) {
this.isInitialLoad = true
this.$store.commit('resetUsers')
await this.loadUsers()
this.setNewUserDefaultGroup(val)
},
filteredUsers(filteredUsers) {
logger.debug(`${filteredUsers.length} filtered user(s)`)
},
@ -288,13 +298,13 @@ export default {
async loadUsers() {
this.loading.users = true
try {
if (this.selectedGroup === 'disabled') {
if (this.selectedSection === 'disabled') {
await this.$store.dispatch('getDisabledUsers', {
offset: this.disabledUsersOffset,
limit: this.disabledUsersLimit,
search: this.searchQuery,
})
} else if (this.selectedGroup === '__nc_internal_recent') {
} else if (this.selectedSection === 'recent') {
await this.$store.dispatch('getRecentUsers', {
offset: this.usersOffset,
limit: this.usersLimit,
@ -385,9 +395,9 @@ export default {
* and we therefore set the usercount to -1 in this specific case
*/
async redirectIfDisabled() {
const allGroups = this.$store.getters.getGroups
if (this.selectedGroup === 'disabled'
&& allGroups.findIndex(group => group.id === 'disabled' && group.usercount === 0) > -1) {
const sectionGroups = this.$store.getters.getSectionGroups
if (this.selectedSection === 'disabled'
&& sectionGroups.find(group => group.id === 'disabled' && group.usercount === 0) !== undefined) {
// disabled group is empty, redirection to all users
this.$router.push({ name: 'users' })
await this.loadUsers()

View file

@ -200,10 +200,8 @@ export default {
},
groups() {
// data provided php side + remove the recent and disabled groups
return this.$store.getters.getGroups
.filter(group => group.id !== '__nc_internal_recent' && group.id !== 'disabled')
.sort((a, b) => a.name.localeCompare(b.name))
.toSorted((a, b) => a.name.localeCompare(b.name))
},
subAdminsGroups() {

View file

@ -27,14 +27,14 @@ function formatGroupMenu(group?: IGroup) {
return item
}
export const useFormatGroups = (groups: Ref<IGroup[]>|ComputedRef<IGroup[]>) => {
export const useFormatGroups = (sectionGroups: Ref<IGroup[]>|ComputedRef<IGroup[]>, 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 !== '__nc_internal_recent' && group.id !== 'admin')
// filter out admin group
.filter(group => group.id !== 'admin')
// format group
.map(group => formatGroupMenu(group))
// remove invalid
@ -50,12 +50,12 @@ export const useFormatGroups = (groups: Ref<IGroup[]>|ComputedRef<IGroup[]>) =>
/**
* The group of disabled users
*/
const disabledGroup = computed(() => formatGroupMenu(groups.value.find(group => group.id === 'disabled')))
const disabledGroup = computed(() => formatGroupMenu(sectionGroups.value.find(group => group.id === 'disabled')))
/**
* The group of recent users
*/
const recentGroup = computed(() => formatGroupMenu(groups.value.find(group => group.id === '__nc_internal_recent')))
const recentGroup = computed(() => formatGroupMenu(sectionGroups.value.find(group => group.id === 'recent')))
return { adminGroup, recentGroup, disabledGroup, userGroups }
}

View file

@ -20,11 +20,26 @@ const routes: RouteConfig[] = [
default: UserManagement,
navigation: UserManagementNavigation,
},
props: true,
props: {
default: true,
navigation: true,
},
children: [
{
path: ':selectedGroup',
path: 'group/:group',
name: 'group',
props: {
default: true,
navigation: true,
},
},
{
path: ':sectionGroup',
name: 'section',
props: {
default: true,
navigation: true,
},
},
],
},

View file

@ -29,6 +29,7 @@ const defaults = {
const state = {
users: [],
sectionGroups: [],
groups: [],
orderBy: GroupSorting.UserCount,
minPasswordLength: 0,
@ -62,6 +63,9 @@ const mutations = {
setPasswordPolicyMinLength(state, length) {
state.minPasswordLength = length !== '' ? length : 0
},
initSectionGroups(state, { sectionGroups }) {
state.sectionGroups = sectionGroups.map(group => Object.assign({}, defaults.group, group))
},
initGroups(state, { groups, orderBy, userCount }) {
state.groups = groups.map(group => Object.assign({}, defaults.group, group))
state.orderBy = orderBy
@ -146,8 +150,8 @@ const mutations = {
return
}
const recentGroup = state.groups.find(group => group.id === '__nc_internal_recent')
const disabledGroup = state.groups.find(group => group.id === 'disabled')
const recentGroup = state.sectionGroups.find(group => group.id === 'recent')
const disabledGroup = state.sectionGroups.find(group => group.id === 'disabled')
switch (actionType) {
case 'enable':
case 'disable':
@ -241,12 +245,14 @@ const getters = {
getUsers(state) {
return state.users
},
getSectionGroups(state) {
return state.sectionGroups
},
getGroups(state) {
return state.groups
},
getSubadminGroups(state) {
// Can't be subadmin of admin, recent, or disabled
return state.groups.filter(group => group.id !== 'admin' && group.id !== '__nc_internal_recent' && group.id !== 'disabled')
return state.groups.filter(group => group.id !== 'admin')
},
getSortedGroups(state) {
const groups = [...state.groups]

View file

@ -6,6 +6,7 @@
<template>
<NcAppContent :page-heading="pageHeading">
<UserList :selected-group="selectedGroupDecoded"
:selected-section="selectedSection"
:external-actions="externalActions" />
</NcAppContent>
</template>
@ -26,6 +27,17 @@ export default defineComponent({
UserList,
},
props: {
group: {
type: String,
default: null,
},
sectionGroup: {
type: String,
default: null,
},
},
data() {
return {
// temporary value used for multiselect change
@ -46,15 +58,28 @@ export default defineComponent({
},
selectedGroup() {
return this.$route.params.selectedGroup
if (this.sectionGroup === 'admin') {
return this.sectionGroup
}
return this.group
},
selectedGroupDecoded() {
return this.selectedGroup ? decodeURIComponent(this.selectedGroup) : null
},
selectedSection() {
if (this.sectionGroup === 'admin') {
return null
}
return this.sectionGroup
},
},
beforeMount() {
this.$store.commit('initSectionGroups', {
sectionGroups: this.$store.getters.getServerData.sectionGroups,
})
this.$store.commit('initGroups', {
groups: this.$store.getters.getServerData.groups,
orderBy: this.$store.getters.getServerData.sortGroups,

View file

@ -34,7 +34,8 @@
id="admin"
:exact="true"
:name="t('settings', 'Admins')"
:to="{ name: 'group', params: { selectedGroup: 'admin' } }">
:to="{ name: 'section', params: { sectionGroup: 'admin' } }">
<!-- This is a group but it should be routed to as a section -->
<template #icon>
<NcIconSvgWrapper :path="mdiShieldAccount" />
</template>
@ -50,13 +51,13 @@
id="recent"
:exact="true"
:name="t('settings', 'Recently active')"
:to="{ name: 'group', params: { selectedGroup: '__nc_internal_recent' } }">
:to="{ name: 'section', params: { sectionGroup: 'recent' } }">
<template #icon>
<NcIconSvgWrapper :path="mdiHistory" />
</template>
<template #counter>
<NcCounterBubble v-if="recentGroup?.usercount"
:type="selectedGroupDecoded === '__nc_internal_recent' ? 'highlighted' : undefined">
:type="selectedSectionGroup === 'recent' ? 'highlighted' : undefined">
{{ recentGroup.usercount }}
</NcCounterBubble>
</template>
@ -67,12 +68,12 @@
id="disabled"
:exact="true"
:name="t('settings', 'Disabled accounts')"
:to="{ name: 'group', params: { selectedGroup: 'disabled' } }">
:to="{ name: 'section', params: { sectionGroup: 'disabled' } }">
<template #icon>
<NcIconSvgWrapper :path="mdiAccountOff" />
</template>
<template v-if="disabledGroup.usercount > 0" #counter>
<NcCounterBubble :type="selectedGroupDecoded === 'disabled' ? 'highlighted' : undefined">
<NcCounterBubble :type="selectedSectionGroup === 'disabled' ? 'highlighted' : undefined">
{{ disabledGroup.usercount }}
</NcCounterBubble>
</template>
@ -151,10 +152,14 @@ 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 { useRouter } from 'vue-router/composables'
import { useFormatGroups } from '../composables/useGroupsNavigation'
const route = useRoute()
const props = defineProps<{
group?: string,
sectionGroup?: string,
}>()
const router = useRouter()
const store = useStore()
@ -162,15 +167,19 @@ const store = useStore()
const isDialogOpen = ref(false)
/** Current active group in the view - this is URL encoded */
const selectedGroup = computed(() => route.params?.selectedGroup)
const selectedGroup = computed(() => props.group)
/** Current active group - URL decoded */
const selectedGroupDecoded = computed(() => selectedGroup.value ? decodeURIComponent(selectedGroup.value) : null)
/** Current active section in the view */
const selectedSectionGroup = computed(() => props.sectionGroup)
/** Overall user count */
const userCount = computed(() => store.getters.getUserCount)
/** All available sections */
const sectionGroups = computed(() => store.getters.getSectionGroups)
/** All available groups */
const groups = computed(() => store.getters.getSortedGroups)
const { adminGroup, recentGroup, disabledGroup, userGroups } = useFormatGroups(groups)
const { adminGroup, recentGroup, disabledGroup, userGroups } = useFormatGroups(sectionGroups, groups)
/** Server settings for current user */
const settings = computed(() => store.getters.getServerData)