aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-03-25 23:45:39 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2024-03-27 12:04:03 +0100
commit5453c1d7fa5a96393c8ab2f7046ec95fe1c43cfa (patch)
tree7e8d5b5d0489554e8b23f078e4d749bd72f2867f /apps
parent6d3b4b0f270acbc10b50ea8a0c12e4d9ba4cde2a (diff)
downloadnextcloud-server-5453c1d7fa5a96393c8ab2f7046ec95fe1c43cfa.tar.gz
nextcloud-server-5453c1d7fa5a96393c8ab2f7046ec95fe1c43cfa.zip
feat(settings): Allow to sort groups in the account management alphabetically
We can do this purly in the frontend - but when enforced from the backend using the existing system config, we need to follow the requirement. We then show a warning about the configuration. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps')
-rw-r--r--apps/settings/lib/Controller/UsersController.php12
-rw-r--r--apps/settings/src/components/Users/UserSettingsDialog.vue51
-rw-r--r--apps/settings/src/constants/GroupManagement.ts29
-rw-r--r--apps/settings/src/store/users.js56
-rw-r--r--apps/settings/src/views/UserManagementNavigation.vue2
5 files changed, 126 insertions, 24 deletions
diff --git a/apps/settings/lib/Controller/UsersController.php b/apps/settings/lib/Controller/UsersController.php
index dbf86db20ac..10b8f690812 100644
--- a/apps/settings/lib/Controller/UsersController.php
+++ b/apps/settings/lib/Controller/UsersController.php
@@ -125,7 +125,7 @@ class UsersController extends Controller {
/* SORT OPTION: SORT_USERCOUNT or SORT_GROUPNAME */
$sortGroupsBy = \OC\Group\MetaData::SORT_USERCOUNT;
$isLDAPUsed = false;
- if ($this->config->getSystemValue('sort_groups_by_name', false)) {
+ if ($this->config->getSystemValueBool('sort_groups_by_name', false)) {
$sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME;
} else {
if ($this->appManager->isEnabledForUser('user_ldap')) {
@@ -212,13 +212,19 @@ class UsersController extends Controller {
/* LANGUAGES */
$languages = $this->l10nFactory->getLanguages();
+ /** Using LDAP or admins (system config) can enfore sorting by group name, in this case the frontend setting is overwritten */
+ $forceSortGroupByName = $sortGroupsBy === \OC\Group\MetaData::SORT_GROUPNAME;
+
/* FINAL DATA */
$serverData = [];
// groups
$serverData['groups'] = array_merge_recursive($adminGroup, [$disabledUsersGroup], $groups);
// Various data
$serverData['isAdmin'] = $isAdmin;
- $serverData['sortGroups'] = $sortGroupsBy;
+ $serverData['sortGroups'] = $forceSortGroupByName
+ ? \OC\Group\MetaData::SORT_GROUPNAME
+ : (int)$this->config->getAppValue('core', 'group.sortBy', (string)\OC\Group\MetaData::SORT_USERCOUNT);
+ $serverData['forceSortGroupByName'] = $forceSortGroupByName;
$serverData['quotaPreset'] = $quotaPreset;
$serverData['allowUnlimitedQuota'] = $allowUnlimitedQuota;
$serverData['userCount'] = $userCount;
@@ -247,7 +253,7 @@ class UsersController extends Controller {
* @return JSONResponse
*/
public function setPreference(string $key, string $value): JSONResponse {
- $allowed = ['newUser.sendEmail'];
+ $allowed = ['newUser.sendEmail', 'group.sortBy'];
if (!in_array($key, $allowed, true)) {
return new JSONResponse([], Http::STATUS_FORBIDDEN);
}
diff --git a/apps/settings/src/components/Users/UserSettingsDialog.vue b/apps/settings/src/components/Users/UserSettingsDialog.vue
index 8580fe5e3fb..d8db67514c4 100644
--- a/apps/settings/src/components/Users/UserSettingsDialog.vue
+++ b/apps/settings/src/components/Users/UserSettingsDialog.vue
@@ -48,6 +48,32 @@
</NcCheckboxRadioSwitch>
</NcAppSettingsSection>
+ <NcAppSettingsSection id="groups-sorting"
+ :name="t('settings', 'Sorting')">
+ <NcNoteCard v-if="isGroupSortingEnforced" type="warning">
+ {{ t('settings', 'The system config enforces sorting the groups by name. This also disables showing the member count.') }}
+ </NcNoteCard>
+ <fieldset>
+ <legend>{{ t('settings', 'Group list sorting') }}</legend>
+ <NcCheckboxRadioSwitch type="radio"
+ :checked.sync="groupSorting"
+ data-test="sortGroupsByMemberCount"
+ :disabled="isGroupSortingEnforced"
+ name="group-sorting-mode"
+ value="member-count">
+ {{ t('settings', 'By member count') }}
+ </NcCheckboxRadioSwitch>
+ <NcCheckboxRadioSwitch type="radio"
+ :checked.sync="groupSorting"
+ data-test="sortGroupsByName"
+ :disabled="isGroupSortingEnforced"
+ name="group-sorting-mode"
+ value="name">
+ {{ t('settings', 'By name') }}
+ </NcCheckboxRadioSwitch>
+ </fieldset>
+ </NcAppSettingsSection>
+
<NcAppSettingsSection id="email-settings"
:name="t('settings', 'Send email')">
<NcCheckboxRadioSwitch type="switch"
@@ -81,8 +107,10 @@ import axios from '@nextcloud/axios'
import NcAppSettingsDialog from '@nextcloud/vue/dist/Components/NcAppSettingsDialog.js'
import NcAppSettingsSection from '@nextcloud/vue/dist/Components/NcAppSettingsSection.js'
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
+import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
+import { GroupSorting } from '../../constants/GroupManagement.ts'
import { unlimitedQuota } from '../../utils/userUtils.ts'
export default {
@@ -92,6 +120,7 @@ export default {
NcAppSettingsDialog,
NcAppSettingsSection,
NcCheckboxRadioSwitch,
+ NcNoteCard,
NcSelect,
},
@@ -110,6 +139,22 @@ export default {
},
computed: {
+ groupSorting: {
+ get() {
+ return this.$store.getters.getGroupSorting === GroupSorting.GroupName ? 'name' : 'member-count'
+ },
+ set(sorting) {
+ this.$store.commit('setGroupSorting', sorting === 'name' ? GroupSorting.GroupName : GroupSorting.UserCount)
+ },
+ },
+
+ /**
+ * Admin has configured `sort_groups_by_name` in the system config
+ */
+ isGroupSortingEnforced() {
+ return this.$store.getters.getServerData.forceSortGroupByName
+ },
+
isModalOpen: {
get() {
return this.open
@@ -261,3 +306,9 @@ export default {
},
}
</script>
+
+<style scoped lang="scss">
+fieldset {
+ font-weight: bold;
+}
+</style>
diff --git a/apps/settings/src/constants/GroupManagement.ts b/apps/settings/src/constants/GroupManagement.ts
new file mode 100644
index 00000000000..573c8691c70
--- /dev/null
+++ b/apps/settings/src/constants/GroupManagement.ts
@@ -0,0 +1,29 @@
+/**
+ * @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de>
+ *
+ * @author Ferdinand Thiessen <opensource@fthiessen.de>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * https://github.com/nextcloud/server/blob/208e38e84e1a07a49699aa90dc5b7272d24489f0/lib/private/Group/MetaData.php#L34
+ */
+export enum GroupSorting {
+ UserCount = 1,
+ GroupName = 2
+}
diff --git a/apps/settings/src/store/users.js b/apps/settings/src/store/users.js
index 7fbd6cd7230..bfc0f4e119f 100644
--- a/apps/settings/src/store/users.js
+++ b/apps/settings/src/store/users.js
@@ -30,26 +30,16 @@
import { getBuilder } from '@nextcloud/browser-storage'
import { getCapabilities } from '@nextcloud/capabilities'
import { parseFileSize } from '@nextcloud/files'
-import { generateOcsUrl } from '@nextcloud/router'
+import { showError } from '@nextcloud/dialogs'
+import { generateOcsUrl, generateUrl } from '@nextcloud/router'
import axios from '@nextcloud/axios'
+import { GroupSorting } from '../constants/GroupManagement.ts'
import api from './api.js'
import logger from '../logger.ts'
const localStorage = getBuilder('settings').persist(true).build()
-const orderGroups = function(groups, orderBy) {
- /* const SORT_USERCOUNT = 1;
- * const SORT_GROUPNAME = 2;
- * https://github.com/nextcloud/server/blob/208e38e84e1a07a49699aa90dc5b7272d24489f0/lib/private/Group/MetaData.php#L34
- */
- if (orderBy === 1) {
- return groups.sort((a, b) => a.usercount - a.disabled < b.usercount - b.disabled)
- } else {
- return groups.sort((a, b) => a.name.localeCompare(b.name))
- }
-}
-
const defaults = {
group: {
id: '',
@@ -64,7 +54,7 @@ const defaults = {
const state = {
users: [],
groups: [],
- orderBy: 1,
+ orderBy: GroupSorting.UserCount,
minPasswordLength: 0,
usersOffset: 0,
usersLimit: 25,
@@ -100,8 +90,6 @@ const mutations = {
state.groups = groups.map(group => Object.assign({}, defaults.group, group))
state.orderBy = orderBy
state.userCount = userCount
- state.groups = orderGroups(state.groups, state.orderBy)
-
},
addGroup(state, { gid, displayName }) {
try {
@@ -114,7 +102,6 @@ const mutations = {
name: displayName,
})
state.groups.unshift(group)
- state.groups = orderGroups(state.groups, state.orderBy)
} catch (e) {
console.error('Can\'t create group', e)
}
@@ -125,7 +112,6 @@ const mutations = {
const updatedGroup = state.groups[groupIndex]
updatedGroup.name = displayName
state.groups.splice(groupIndex, 1, updatedGroup)
- state.groups = orderGroups(state.groups, state.orderBy)
}
},
removeGroup(state, gid) {
@@ -143,7 +129,6 @@ const mutations = {
}
const groups = user.groups
groups.push(gid)
- state.groups = orderGroups(state.groups, state.orderBy)
},
removeUserGroup(state, { userid, gid }) {
const group = state.groups.find(groupSearch => groupSearch.id === gid)
@@ -154,7 +139,6 @@ const mutations = {
}
const groups = user.groups
groups.splice(groups.indexOf(gid), 1)
- state.groups = orderGroups(state.groups, state.orderBy)
},
addUserSubAdmin(state, { userid, gid }) {
const groups = state.users.find(user => user.id === userid).subadmin
@@ -254,6 +238,23 @@ const mutations = {
localStorage.setItem(`account_settings__${key}`, JSON.stringify(value))
state.showConfig[key] = value
},
+
+ setGroupSorting(state, sorting) {
+ const oldValue = state.orderBy
+ state.orderBy = sorting
+
+ // Persist the value on the server
+ axios.post(
+ generateUrl('/settings/users/preferences/group.sortBy'),
+ {
+ value: String(sorting),
+ },
+ ).catch((error) => {
+ state.orderBy = oldValue
+ showError(t('settings', 'Could not set group sorting'))
+ logger.error(error)
+ })
+ },
}
const getters = {
@@ -267,6 +268,21 @@ const getters = {
// Can't be subadmin of admin or disabled
return state.groups.filter(group => group.id !== 'admin' && group.id !== 'disabled')
},
+ getSortedGroups(state) {
+ const groups = [...state.groups]
+ if (state.orderBy === GroupSorting.UserCount) {
+ return groups.sort((a, b) => {
+ const numA = a.usercount - a.disabled
+ const numB = b.usercount - b.disabled
+ return (numA < numB) ? 1 : (numB < numA ? -1 : a.name.localeCompare(b.name))
+ })
+ } else {
+ return groups.sort((a, b) => a.name.localeCompare(b.name))
+ }
+ },
+ getGroupSorting(state) {
+ return state.orderBy
+ },
getPasswordPolicyMinLength(state) {
return state.minPasswordLength
},
diff --git a/apps/settings/src/views/UserManagementNavigation.vue b/apps/settings/src/views/UserManagementNavigation.vue
index 4959040a1bf..51a5744543d 100644
--- a/apps/settings/src/views/UserManagementNavigation.vue
+++ b/apps/settings/src/views/UserManagementNavigation.vue
@@ -149,7 +149,7 @@ const selectedGroupDecoded = computed(() => selectedGroup.value ? decodeURICompo
/** Overall user count */
const userCount = computed(() => store.getters.getUserCount)
/** All available groups */
-const groups = computed(() => store.getters.getGroups)
+const groups = computed(() => store.getters.getSortedGroups)
const { adminGroup, disabledGroup, userGroups } = useFormatGroups(groups)
/** True if the current user is an administrator */