Skip to content

Commit

Permalink
feat!: Add Recent accounts section
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The "recent" group id is now reserved for the Recent accounts section and will not be shown under the Groups heading

Signed-off-by: Christopher Ng <chrng8@gmail.com>
  • Loading branch information
Pytal committed Jul 9, 2024
1 parent 9005ab0 commit b7a16db
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 11 deletions.
8 changes: 7 additions & 1 deletion apps/settings/lib/Controller/UsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ public function usersList(): TemplateResponse {
$userCount -= $disabledUsers;
}

$recentUsersGroup = [
'id' => 'recent',
'name' => 'Recent accounts',
'usercount' => $userCount,
];

$disabledUsersGroup = [
'id' => 'disabled',
'name' => 'Disabled accounts',
Expand Down Expand Up @@ -192,7 +198,7 @@ public function usersList(): TemplateResponse {
/* 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
Expand Down
10 changes: 8 additions & 2 deletions apps/settings/src/components/UserList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 !== 'recent' && group.id !== 'disabled')
.sort((a, b) => a.name.localeCompare(b.name))
},
Expand Down Expand Up @@ -298,6 +298,12 @@ export default {
limit: this.disabledUsersLimit,
search: this.searchQuery,
})
} else if (this.selectedGroup === 'recent') {
await this.$store.dispatch('getRecentUsers', {
offset: this.usersOffset,
limit: this.usersLimit,
search: this.searchQuery,
})
} else {
await this.$store.dispatch('getUsers', {
offset: this.usersOffset,
Expand Down
4 changes: 2 additions & 2 deletions apps/settings/src/components/Users/NewUserDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 !== 'recent' && group.id !== 'disabled')
.sort((a, b) => a.name.localeCompare(b.name))
},
Expand Down
9 changes: 7 additions & 2 deletions apps/settings/src/composables/useGroupsNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 !== 'recent' && group.id !== 'admin')
// format group
.map(group => formatGroupMenu(group))
// remove invalid
Expand All @@ -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 === 'recent')))

return { adminGroup, recentGroup, disabledGroup, userGroups }
}
32 changes: 30 additions & 2 deletions apps/settings/src/store/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,21 @@ const mutations = {
return
}

const recentGroup = state.groups.find(group => group.id === '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)
group.disabled += user.enabled ? -1 : 1 // update group disabled count
})
break
case 'create':
recentGroup.usercount++
state.userCount++ // increment Active Users count

user.groups.forEach(userGroup => {
Expand All @@ -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)
Expand Down Expand Up @@ -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 !== 'recent' && group.id !== 'disabled')
},
getSortedGroups(state) {
const groups = [...state.groups]
Expand Down Expand Up @@ -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
*
Expand Down
19 changes: 17 additions & 2 deletions apps/settings/src/views/UserManagementNavigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@
</template>
</NcAppNavigationItem>

<NcAppNavigationItem id="recent"
:exact="true"
:name="t('settings', 'Recent accounts')"
:to="{ name: 'group', params: { selectedGroup: 'recent' } }">
<template #icon>
<NcIconSvgWrapper :path="mdiHistory" />
</template>
<template #counter>
<NcCounterBubble v-if="recentGroup?.usercount > 0"
:type="selectedGroupDecoded === '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"
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit b7a16db

Please sign in to comment.