mirror of
https://github.com/nextcloud/server.git
synced 2026-06-11 01:30:50 -04:00
feat(settings): Namespace group routes
Signed-off-by: Christopher Ng <chrng8@gmail.com>
This commit is contained in:
parent
558fbcda72
commit
fb5dd8a259
9 changed files with 104 additions and 40 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue