From 07b903b0b469663cf101d7e7ea3f6a6b238366e7 Mon Sep 17 00:00:00 2001 From: yu-i-i Date: Fri, 30 Jan 2026 00:23:02 +0100 Subject: [PATCH] Admin Tools: Fix sorting --- .../app/src/ProjectListController.mjs | 19 +++++++++----- .../app/src/UserListController.mjs | 22 ++++++++++++---- .../user-list/context/user-list-context.tsx | 25 ++++++------------- .../admin-tools/types/project/api.d.ts | 2 +- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/services/web/modules/admin-tools/app/src/ProjectListController.mjs b/services/web/modules/admin-tools/app/src/ProjectListController.mjs index 24d6bf0786..3d84457dd2 100644 --- a/services/web/modules/admin-tools/app/src/ProjectListController.mjs +++ b/services/web/modules/admin-tools/app/src/ProjectListController.mjs @@ -111,16 +111,23 @@ function _applyFilters(projects, filters) { function _sortAndPaginate(projects, sort, page) { if ( - (sort.by && !['lastUpdated', 'title', 'deletedAt'].includes(sort.by)) || + (sort.by && !['lastUpdated', 'title', 'deletedAt', 'owner'].includes(sort.by)) || (sort.order && !['asc', 'desc'].includes(sort.order)) ) { throw new OError('Invalid sorting criteria', { sort }) } - const sortedProjects = _.orderBy( - projects, - [sort.by || 'lastUpdated'], - [sort.order || 'desc'] - ) + +// sorting by owner is not implemented, it is mot needed + const sortedProjects = + sort.by === 'title' + ? [...projects].sort((a, b) => + (a.name ?? '\uffff').localeCompare(b.name ?? '\uffff') + ) + : _.orderBy( + projects, + [sort.by || 'lastUpdated'], + [sort.order || 'desc'] + ) return sortedProjects } diff --git a/services/web/modules/admin-tools/app/src/UserListController.mjs b/services/web/modules/admin-tools/app/src/UserListController.mjs index f3eaeec396..b3534b97d8 100644 --- a/services/web/modules/admin-tools/app/src/UserListController.mjs +++ b/services/web/modules/admin-tools/app/src/UserListController.mjs @@ -266,11 +266,23 @@ function _sortAndPaginate(users, sort, page) { throw new OError('Invalid sorting criteria', { sort }) } - const sortedUsers = _.orderBy( - users, - [sort.by || 'signUpDate'], - [sort.order || 'desc'] - ) + const LAST = '\uffff' + const sortedUsers = + sort.by === 'name' + ? [...users].sort((a, b) => + (a.lastName ?? LAST).localeCompare(b.lastName ?? LAST, undefined, { sensitivity: 'base' }) || + (a.firstName ?? LAST).localeCompare(b.firstName ?? LAST, undefined, { sensitivity: 'base' }) || + (a.email ?? LAST).localeCompare(b.email ?? LAST, undefined, { sensitivity: 'base' }) + ) + : _.orderBy( + users, + [u => { + const key = sort.by || 'signUpDate' + const value = u[key] + return typeof value === 'string' ? (value ?? LAST).toLowerCase() : value + }], + [sort.order || 'desc'] + ) return sortedUsers } diff --git a/services/web/modules/admin-tools/frontend/js/user-list/context/user-list-context.tsx b/services/web/modules/admin-tools/frontend/js/user-list/context/user-list-context.tsx index 5332bef0b4..f256a94c53 100644 --- a/services/web/modules/admin-tools/frontend/js/user-list/context/user-list-context.tsx +++ b/services/web/modules/admin-tools/frontend/js/user-list/context/user-list-context.tsx @@ -5,7 +5,6 @@ import { useContext, useEffect, useMemo, - useRef, useState, } from 'react' import { @@ -130,7 +129,6 @@ export function UserListProvider({ children }: UserListProviderProps) { 'user-list-filter', 'all' ) - const prevSortRef = useRef(sort) const [searchText, setSearchText] = useState('') @@ -160,11 +158,11 @@ export function UserListProvider({ children }: UserListProviderProps) { }, [prefetchedUsersBlob, runAsync]) const addUserToView = useCallback((newUser: Partial) => { - setLoadedUsers(prev => sortUsers([newUser, ...prev], prevSortRef.current)) + setLoadedUsers(prev => [newUser as User, ...prev]) }, []) const processedUsers = useMemo(() => { - let users = [...loadedUsers] + let users = loadedUsers if (searchText.length) { const searchTextLowerCase = searchText.toLowerCase() @@ -177,11 +175,7 @@ export function UserListProvider({ children }: UserListProviderProps) { users = arrayFilter(users, filters[filter]) - if (prevSortRef.current !== sort) { - users = sortUsers(users, sort) - } - - return users + return sortUsers(users, sort) }, [loadedUsers, searchText, filter, sort]) const visibleUsers = useMemo(() => { @@ -198,10 +192,6 @@ export function UserListProvider({ children }: UserListProviderProps) { MAX_USER_PER_PAGE ) - useEffect(() => { - prevSortRef.current = sort - }, [sort]) - const selfVisibleCount = useMemo(() => { return visibleUsers.some(u => u.id === selfId) ? 1 : 0 }, [visibleUsers]) @@ -238,8 +228,8 @@ export function UserListProvider({ children }: UserListProviderProps) { ) const selectedUsers = useMemo(() => { - return visibleUsers.filter(user => selectedUserIds.has(user.id)) - }, [selectedUserIds, visibleUsers]) + return loadedUsers.filter(user => selectedUserIds.has(user.id)) + }, [selectedUserIds, loadedUsers]) const selectOrUnselectAllUsers = useCallback( (checked: any) => { @@ -258,7 +248,7 @@ export function UserListProvider({ children }: UserListProviderProps) { } return selectedUserIds }) - } , + }, [visibleUsers] ) @@ -356,7 +346,7 @@ export function UserListProvider({ children }: UserListProviderProps) { ) if (!loadedUsers || loadedUsers.length === 0) { - return null + return null } return ( @@ -377,4 +367,3 @@ export function useUserListContext() { } return context } - diff --git a/services/web/modules/admin-tools/types/project/api.d.ts b/services/web/modules/admin-tools/types/project/api.d.ts index 2257c0c0f8..a6102945b1 100644 --- a/services/web/modules/admin-tools/types/project/api.d.ts +++ b/services/web/modules/admin-tools/types/project/api.d.ts @@ -8,7 +8,7 @@ export type Page = { } export type Sort = { - by: 'lastUpdated' | 'title' | 'deletedAt' + by: 'lastUpdated' | 'title' | 'deletedAt' | 'owner' order: SortingOrder }