feat: Add Recent accounts section

Signed-off-by: Christopher Ng <chrng8@gmail.com>
This commit is contained in:
Christopher Ng 2024-07-11 11:19:09 -07:00
parent 19c8c63f32
commit 07319a118b
6 changed files with 71 additions and 11 deletions

View file

@ -164,6 +164,12 @@ class UsersController extends Controller {
$userCount -= $disabledUsers;
}
$recentUsersGroup = [
'id' => '__nc_internal_recent',
'name' => 'Recent accounts',
'usercount' => $userCount,
];
$disabledUsersGroup = [
'id' => 'disabled',
'name' => 'Disabled accounts',
@ -192,7 +198,7 @@ class UsersController extends Controller {
/* FINAL DATA */
$serverData = [];
// groups
$serverData['groups'] = array_merge_recursive($adminGroup, [$disabledUsersGroup], $groups);
$serverData['groups'] = array_merge_recursive($adminGroup, [$recentUsersGroup, $disabledUsersGroup], $groups);
// Various data
$serverData['isAdmin'] = $isAdmin;
$serverData['sortGroups'] = $forceSortGroupByName

View file

@ -177,9 +177,9 @@ export default {
},
groups() {
// data provided php side + remove the disabled group
// data provided php side + remove the recent and disabled groups
return this.$store.getters.getGroups
.filter(group => group.id !== 'disabled')
.filter(group => group.id !== '__nc_internal_recent' && group.id !== 'disabled')
.sort((a, b) => a.name.localeCompare(b.name))
},
@ -298,6 +298,12 @@ export default {
limit: this.disabledUsersLimit,
search: this.searchQuery,
})
} else if (this.selectedGroup === '__nc_internal_recent') {
await this.$store.dispatch('getRecentUsers', {
offset: this.usersOffset,
limit: this.usersLimit,
search: this.searchQuery,
})
} else {
await this.$store.dispatch('getUsers', {
offset: this.usersOffset,

View file

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

View file

@ -34,7 +34,7 @@ export const useFormatGroups = (groups: Ref<IGroup[]>|ComputedRef<IGroup[]>) =>
const userGroups = computed(() => {
const formatted = groups.value
// filter out disabled and admin
.filter(group => group.id !== 'disabled' && group.id !== 'admin')
.filter(group => group.id !== 'disabled' && group.id !== '__nc_internal_recent' && group.id !== 'admin')
// format group
.map(group => formatGroupMenu(group))
// remove invalid
@ -52,5 +52,10 @@ export const useFormatGroups = (groups: Ref<IGroup[]>|ComputedRef<IGroup[]>) =>
*/
const disabledGroup = computed(() => formatGroupMenu(groups.value.find(group => group.id === 'disabled')))
return { adminGroup, disabledGroup, userGroups }
/**
* The group of recent users
*/
const recentGroup = computed(() => formatGroupMenu(groups.value.find(group => group.id === '__nc_internal_recent')))
return { adminGroup, recentGroup, disabledGroup, userGroups }
}

View file

@ -146,11 +146,13 @@ const mutations = {
return
}
const recentGroup = state.groups.find(group => group.id === '__nc_internal_recent')
const disabledGroup = state.groups.find(group => group.id === 'disabled')
switch (actionType) {
case 'enable':
case 'disable':
disabledGroup.usercount += user.enabled ? -1 : 1 // update Disabled Users count
recentGroup.usercount += user.enabled ? 1 : -1
state.userCount += user.enabled ? 1 : -1 // update Active Users count
user.groups.forEach(userGroup => {
const group = state.groups.find(groupSearch => groupSearch.id === userGroup)
@ -158,6 +160,7 @@ const mutations = {
})
break
case 'create':
recentGroup.usercount++
state.userCount++ // increment Active Users count
user.groups.forEach(userGroup => {
@ -168,6 +171,7 @@ const mutations = {
break
case 'remove':
if (user.enabled) {
recentGroup.usercount--
state.userCount-- // decrement Active Users count
user.groups.forEach(userGroup => {
const group = state.groups.find(groupSearch => groupSearch.id === userGroup)
@ -241,8 +245,8 @@ const getters = {
return state.groups
},
getSubadminGroups(state) {
// Can't be subadmin of admin or disabled
return state.groups.filter(group => group.id !== 'admin' && group.id !== 'disabled')
// 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')
},
getSortedGroups(state) {
const groups = [...state.groups]
@ -383,6 +387,30 @@ const actions = {
})
},
/**
* Get recent users with full details
*
* @param {object} context store context
* @param {object} options destructuring object
* @param {number} options.offset List offset to request
* @param {number} options.limit List number to return from offset
* @param {string} options.search Search query
* @return {Promise<number>}
*/
async getRecentUsers(context, { offset, limit, search }) {
const url = generateOcsUrl('cloud/users/recent?offset={offset}&limit={limit}&search={search}', { offset, limit, search })
try {
const response = await api.get(url)
const usersCount = Object.keys(response.data.ocs.data.users).length
if (usersCount > 0) {
context.commit('appendUsers', response.data.ocs.data.users)
}
return usersCount
} catch (error) {
context.commit('API_FAILURE', error)
}
},
/**
* Get disabled users with full details
*

View file

@ -46,6 +46,21 @@
</template>
</NcAppNavigationItem>
<NcAppNavigationItem id="recent"
:exact="true"
:name="t('settings', 'Recent accounts')"
:to="{ name: 'group', params: { selectedGroup: '__nc_internal_recent' } }">
<template #icon>
<NcIconSvgWrapper :path="mdiHistory" />
</template>
<template #counter>
<NcCounterBubble v-if="recentGroup?.usercount > 0"
:type="selectedGroupDecoded === '__nc_internal_recent' ? 'highlighted' : undefined">
{{ recentGroup.usercount }}
</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"
@ -115,7 +130,7 @@
</template>
<script setup lang="ts">
import { mdiAccount, mdiAccountOff, mdiCog, mdiPlus, mdiShieldAccount } from '@mdi/js'
import { mdiAccount, mdiAccountOff, mdiCog, mdiPlus, mdiShieldAccount, mdiHistory } from '@mdi/js'
import { showError } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import { computed, ref } from 'vue'
@ -154,7 +169,7 @@ const selectedGroupDecoded = computed(() => selectedGroup.value ? decodeURICompo
const userCount = computed(() => store.getters.getUserCount)
/** All available groups */
const groups = computed(() => store.getters.getSortedGroups)
const { adminGroup, disabledGroup, userGroups } = useFormatGroups(groups)
const { adminGroup, recentGroup, disabledGroup, userGroups } = useFormatGroups(groups)
/** True if the current user is an administrator */
const isAdmin = computed(() => store.getters.getServerData.isAdmin)