diff --git a/backend/open_webui/models/users.py b/backend/open_webui/models/users.py index 445eb51128..9779731a47 100644 --- a/backend/open_webui/models/users.py +++ b/backend/open_webui/models/users.py @@ -11,8 +11,8 @@ from open_webui.utils.misc import throttle from pydantic import BaseModel, ConfigDict -from sqlalchemy import BigInteger, Column, String, Text, Date -from sqlalchemy import or_ +from sqlalchemy import BigInteger, Column, String, Text, Date, exists, select +from sqlalchemy import or_, case import datetime @@ -243,20 +243,30 @@ class UsersTable: direction = filter.get("direction") if order_by and order_by.startswith("group_id:"): - query = query.outerjoin(GroupMember, GroupMember.user_id == User.id) group_id = order_by.split(":", 1)[1] - if direction == "asc": - query = query.order_by((GroupMember.group_id == group_id).asc()) - else: - query = query.order_by( - (GroupMember.group_id == group_id).desc() + # Subquery that checks if the user belongs to the group + membership_exists = exists( + select(GroupMember.id).where( + GroupMember.user_id == User.id, + GroupMember.group_id == group_id, ) + ) + + # CASE: user in group → 1, user not in group → 0 + group_sort = case((membership_exists, 1), else_=0) + + if direction == "asc": + query = query.order_by(group_sort.asc(), User.name.asc()) + else: + query = query.order_by(group_sort.desc(), User.name.asc()) + elif order_by == "name": if direction == "asc": query = query.order_by(User.name.asc()) else: query = query.order_by(User.name.desc()) + elif order_by == "email": if direction == "asc": query = query.order_by(User.email.asc()) diff --git a/src/lib/components/admin/Users/Groups/Users.svelte b/src/lib/components/admin/Users/Groups/Users.svelte index 298611a655..e017187677 100644 --- a/src/lib/components/admin/Users/Groups/Users.svelte +++ b/src/lib/components/admin/Users/Groups/Users.svelte @@ -11,21 +11,23 @@ import { getUsers } from '$lib/apis/users'; import { toast } from 'svelte-sonner'; + import { addUserToGroup, removeUserFromGroup } from '$lib/apis/groups'; + import { WEBUI_API_BASE_URL } from '$lib/constants'; + import Tooltip from '$lib/components/common/Tooltip.svelte'; import Checkbox from '$lib/components/common/Checkbox.svelte'; import Badge from '$lib/components/common/Badge.svelte'; import Search from '$lib/components/icons/Search.svelte'; import Pagination from '$lib/components/common/Pagination.svelte'; - import { addUserToGroup, removeUserFromGroup } from '$lib/apis/groups'; import ChevronDown from '$lib/components/icons/ChevronDown.svelte'; import ChevronUp from '$lib/components/icons/ChevronUp.svelte'; - import { WEBUI_API_BASE_URL } from '$lib/constants'; + import Spinner from '$lib/components/common/Spinner.svelte'; export let groupId: string; export let userCount = 0; - let users = []; - let total = 0; + let users = null; + let total = null; let query = ''; let orderBy = `group_id:${groupId}`; // default sort key @@ -100,163 +102,169 @@ - {#if users.length > 0} -