refac/fix: group member user list

This commit is contained in:
Timothy Jaeryang Baek 2025-11-25 01:37:33 -05:00
parent 38c6b0bff6
commit b1c1e68e56
2 changed files with 185 additions and 167 deletions

View file

@ -11,8 +11,8 @@ from open_webui.utils.misc import throttle
from pydantic import BaseModel, ConfigDict from pydantic import BaseModel, ConfigDict
from sqlalchemy import BigInteger, Column, String, Text, Date from sqlalchemy import BigInteger, Column, String, Text, Date, exists, select
from sqlalchemy import or_ from sqlalchemy import or_, case
import datetime import datetime
@ -243,20 +243,30 @@ class UsersTable:
direction = filter.get("direction") direction = filter.get("direction")
if order_by and order_by.startswith("group_id:"): 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] group_id = order_by.split(":", 1)[1]
if direction == "asc": # Subquery that checks if the user belongs to the group
query = query.order_by((GroupMember.group_id == group_id).asc()) membership_exists = exists(
else: select(GroupMember.id).where(
query = query.order_by( GroupMember.user_id == User.id,
(GroupMember.group_id == group_id).desc() 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": elif order_by == "name":
if direction == "asc": if direction == "asc":
query = query.order_by(User.name.asc()) query = query.order_by(User.name.asc())
else: else:
query = query.order_by(User.name.desc()) query = query.order_by(User.name.desc())
elif order_by == "email": elif order_by == "email":
if direction == "asc": if direction == "asc":
query = query.order_by(User.email.asc()) query = query.order_by(User.email.asc())

View file

@ -11,21 +11,23 @@
import { getUsers } from '$lib/apis/users'; import { getUsers } from '$lib/apis/users';
import { toast } from 'svelte-sonner'; 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 Tooltip from '$lib/components/common/Tooltip.svelte';
import Checkbox from '$lib/components/common/Checkbox.svelte'; import Checkbox from '$lib/components/common/Checkbox.svelte';
import Badge from '$lib/components/common/Badge.svelte'; import Badge from '$lib/components/common/Badge.svelte';
import Search from '$lib/components/icons/Search.svelte'; import Search from '$lib/components/icons/Search.svelte';
import Pagination from '$lib/components/common/Pagination.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 ChevronDown from '$lib/components/icons/ChevronDown.svelte';
import ChevronUp from '$lib/components/icons/ChevronUp.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 groupId: string;
export let userCount = 0; export let userCount = 0;
let users = []; let users = null;
let total = 0; let total = null;
let query = ''; let query = '';
let orderBy = `group_id:${groupId}`; // default sort key let orderBy = `group_id:${groupId}`; // default sort key
@ -100,6 +102,11 @@
</div> </div>
</div> </div>
{#if users === null || total === null}
<div class="my-10">
<Spinner className="size-5" />
</div>
{:else}
{#if users.length > 0} {#if users.length > 0}
<div class="scrollbar-hidden relative whitespace-nowrap overflow-x-auto max-w-full"> <div class="scrollbar-hidden relative whitespace-nowrap overflow-x-auto max-w-full">
<table <table
@ -204,7 +211,7 @@
</tr> </tr>
</thead> </thead>
<tbody class=""> <tbody class="">
{#each users as user, userIdx} {#each users as user, userIdx (user?.id ?? userIdx)}
<tr class="bg-white dark:bg-gray-900 dark:border-gray-850 text-xs"> <tr class="bg-white dark:bg-gray-900 dark:border-gray-850 text-xs">
<td class=" px-3 py-1 w-8"> <td class=" px-3 py-1 w-8">
<div class="flex w-full justify-center"> <div class="flex w-full justify-center">
@ -259,4 +266,5 @@
{#if total > 30} {#if total > 30}
<Pagination bind:page count={total} perPage={30} /> <Pagination bind:page count={total} perPage={30} />
{/if} {/if}
{/if}
</div> </div>