mirror of
https://github.com/open-webui/open-webui
synced 2025-06-04 03:37:35 +00:00
Support pagination in /admin/users API
Update Users.svelte Update index.ts Update users.py Update users.py Update UserList.svelte
This commit is contained in:
parent
1349bc47b1
commit
2112067054
@ -160,11 +160,26 @@ class UsersTable:
|
||||
return None
|
||||
|
||||
def get_users(
|
||||
self, skip: Optional[int] = None, limit: Optional[int] = None
|
||||
self,
|
||||
skip: Optional[int] = None,
|
||||
limit: Optional[int] = None,
|
||||
query_key: Optional[int] = None
|
||||
) -> list[UserModel]:
|
||||
with get_db() as db:
|
||||
|
||||
query = db.query(User).order_by(User.created_at.desc())
|
||||
if not query_key:
|
||||
query = db.query(User).order_by(User.created_at.desc())
|
||||
else:
|
||||
query = (
|
||||
db.query(User)
|
||||
.filter(
|
||||
or_(
|
||||
User.name.ilike(f'%{query_key}%'),
|
||||
User.email.ilike(f'%{query_key}%')
|
||||
)
|
||||
)
|
||||
.order_by(User.created_at.desc())
|
||||
)
|
||||
|
||||
if skip:
|
||||
query = query.offset(skip)
|
||||
|
@ -35,11 +35,21 @@ router = APIRouter()
|
||||
|
||||
@router.get("/", response_model=list[UserModel])
|
||||
async def get_users(
|
||||
skip: Optional[int] = None,
|
||||
page: Optional[int] = None,
|
||||
limit: Optional[int] = None,
|
||||
q: Optional[str] = None,
|
||||
user=Depends(get_admin_user),
|
||||
):
|
||||
return Users.get_users(skip, limit)
|
||||
if q:
|
||||
skip: Optional[int] = None
|
||||
if page:
|
||||
skip = (page - 1) * limit
|
||||
return Users.get_users(skip=skip, limit=limit, query_key=q)
|
||||
else:
|
||||
skip: Optional[int] = None
|
||||
if page:
|
||||
skip = (page - 1) * limit
|
||||
return Users.get_users(skip=skip, limit=limit)
|
||||
|
||||
|
||||
############################
|
||||
|
@ -116,30 +116,64 @@ export const updateUserRole = async (token: string, id: string, role: string) =>
|
||||
return res;
|
||||
};
|
||||
|
||||
export const getUsers = async (token: string) => {
|
||||
export const getUsers = async (token: string, page?: number, limit: number = 10, q?: string) => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${WEBUI_API_BASE_URL}/users/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (!res.ok) throw await res.json();
|
||||
return res.json();
|
||||
let res = null;
|
||||
if (q !== undefined) {
|
||||
res = await fetch(`${WEBUI_API_BASE_URL}/users/?q=${q}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
error = err.detail;
|
||||
return null;
|
||||
});
|
||||
|
||||
.then(async (res) => {
|
||||
if (!res.ok) throw await res.json();
|
||||
return res.json();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
error = err.detail;
|
||||
return null;
|
||||
});
|
||||
} else if (page !== undefined) {
|
||||
res = await fetch(`${WEBUI_API_BASE_URL}/users/?page=${page}&limit=${limit}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (!res.ok) throw await res.json();
|
||||
return res.json();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
error = err.detail;
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
res = await fetch(`${WEBUI_API_BASE_URL}/users/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (!res.ok) throw await res.json();
|
||||
return res.json();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
error = err.detail;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return res ? res : [];
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
let users = [];
|
||||
let totalUsers = 0;
|
||||
|
||||
let selectedTab = 'overview';
|
||||
let loaded = false;
|
||||
@ -30,6 +31,7 @@
|
||||
await goto('/');
|
||||
} else {
|
||||
users = await getUsers(localStorage.token);
|
||||
totalUsers = users.length;
|
||||
}
|
||||
loaded = true;
|
||||
|
||||
@ -102,7 +104,7 @@
|
||||
|
||||
<div class="flex-1 mt-1 lg:mt-0 overflow-y-scroll">
|
||||
{#if selectedTab === 'overview'}
|
||||
<UserList {users} />
|
||||
<UserList {totalUsers}/>
|
||||
{:else if selectedTab === 'groups'}
|
||||
<Groups {users} />
|
||||
{/if}
|
||||
|
@ -33,7 +33,8 @@
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
export let users = [];
|
||||
export let totalUsers = 0;
|
||||
let users = []
|
||||
|
||||
let search = '';
|
||||
let selectedUser = null;
|
||||
@ -67,6 +68,13 @@
|
||||
}
|
||||
};
|
||||
|
||||
const fetchUserPage = async () => {
|
||||
try {
|
||||
users = await getUsers(localStorage.token, page);
|
||||
} catch (err) {
|
||||
console.error("Error fetching users: " + err);
|
||||
}
|
||||
};
|
||||
let sortKey = 'created_at'; // default sort key
|
||||
let sortOrder = 'asc'; // default sort order
|
||||
|
||||
@ -79,25 +87,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
let filteredUsers;
|
||||
const queryUser = async (q) => {
|
||||
try {
|
||||
const result = await getUsers(localStorage.token, undefined, 10, q);
|
||||
filteredUsers = result.slice((page - 1) * 10, page * 10);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
$: filteredUsers = users
|
||||
.filter((user) => {
|
||||
if (search === '') {
|
||||
return true;
|
||||
} else {
|
||||
let name = user.name.toLowerCase();
|
||||
let email = user.email.toLowerCase();
|
||||
const query = search.toLowerCase();
|
||||
return name.includes(query) || email.includes(query);
|
||||
}
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (a[sortKey] < b[sortKey]) return sortOrder === 'asc' ? -1 : 1;
|
||||
if (a[sortKey] > b[sortKey]) return sortOrder === 'asc' ? 1 : -1;
|
||||
return 0;
|
||||
})
|
||||
.slice((page - 1) * 20, page * 20);
|
||||
let filteredUsers;
|
||||
$: if (search.trim() === '') {
|
||||
filteredUsers = users
|
||||
.sort((a, b) => {
|
||||
if (a[sortKey] < b[sortKey]) return sortOrder === 'asc' ? -1 : 1;
|
||||
if (a[sortKey] > b[sortKey]) return sortOrder === 'asc' ? 1 : -1;
|
||||
return 0;
|
||||
})
|
||||
} else {
|
||||
queryUser(search);
|
||||
}
|
||||
</script>
|
||||
|
||||
<ConfirmDialog
|
||||
@ -486,10 +495,10 @@
|
||||
ⓘ {$i18n.t("Click on the user role button to change a user's role.")}
|
||||
</div>
|
||||
|
||||
<Pagination bind:page count={users.length} />
|
||||
<Pagination bind:page count={totalUsers} perPage={10}/>
|
||||
|
||||
{#if !$config?.license_metadata}
|
||||
{#if users.length > 50}
|
||||
{#if totalUsers > 50}
|
||||
<div class="text-sm">
|
||||
<Markdown
|
||||
content={`
|
||||
|
Loading…
Reference in New Issue
Block a user