mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-24 18:24:20 +00:00
fix(view_users.tsx): enable global sorting
allows finding user with highest spend
This commit is contained in:
parent
5969e8b650
commit
bacc2671e7
3 changed files with 73 additions and 8 deletions
|
@ -679,6 +679,8 @@ export const userListCall = async (
|
|||
userEmail: string | null = null,
|
||||
userRole: string | null = null,
|
||||
team: string | null = null,
|
||||
sortBy: string | null = null,
|
||||
sortOrder: 'asc' | 'desc' | null = null,
|
||||
) => {
|
||||
/**
|
||||
* Get all available teams on proxy
|
||||
|
@ -713,6 +715,14 @@ export const userListCall = async (
|
|||
if (team) {
|
||||
queryParams.append('team', team);
|
||||
}
|
||||
|
||||
if (sortBy) {
|
||||
queryParams.append('sort_by', sortBy);
|
||||
}
|
||||
|
||||
if (sortOrder) {
|
||||
queryParams.append('sort_order', sortOrder);
|
||||
}
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
if (queryString) {
|
||||
|
|
|
@ -88,6 +88,8 @@ interface FilterState {
|
|||
model: string;
|
||||
min_spend: number | null;
|
||||
max_spend: number | null;
|
||||
sort_by: string;
|
||||
sort_order: 'asc' | 'desc';
|
||||
}
|
||||
|
||||
const isLocal = process.env.NODE_ENV === "development";
|
||||
|
@ -127,7 +129,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
|||
team: "",
|
||||
model: "",
|
||||
min_spend: null,
|
||||
max_spend: null
|
||||
max_spend: null,
|
||||
sort_by: "created_at",
|
||||
sort_order: "desc"
|
||||
});
|
||||
const [showFilters, setShowFilters] = useState(false);
|
||||
const [showColumnDropdown, setShowColumnDropdown] = useState(false);
|
||||
|
@ -155,6 +159,16 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
|||
debouncedSearch(newFilters);
|
||||
};
|
||||
|
||||
const handleSortChange = (sortBy: string, sortOrder: 'asc' | 'desc') => {
|
||||
const newFilters = {
|
||||
...filters,
|
||||
sort_by: sortBy,
|
||||
sort_order: sortOrder
|
||||
};
|
||||
setFilters(newFilters);
|
||||
debouncedSearch(newFilters);
|
||||
};
|
||||
|
||||
// Create a debounced version of the search function
|
||||
const debouncedSearch = useCallback(
|
||||
debounce(async (filters: FilterState) => {
|
||||
|
@ -174,7 +188,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
|||
defaultPageSize,
|
||||
filters.email || null,
|
||||
filters.user_role || null,
|
||||
filters.team || null
|
||||
filters.team || null,
|
||||
filters.sort_by,
|
||||
filters.sort_order
|
||||
);
|
||||
|
||||
// Only update state if this is the most recent search
|
||||
|
@ -302,7 +318,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
|||
defaultPageSize,
|
||||
filters.email || null,
|
||||
filters.user_role || null,
|
||||
filters.team || null
|
||||
filters.team || null,
|
||||
filters.sort_by,
|
||||
filters.sort_order
|
||||
);
|
||||
|
||||
// Update session storage with new data
|
||||
|
@ -339,7 +357,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
|||
defaultPageSize,
|
||||
filters.email || null,
|
||||
filters.user_role || null,
|
||||
filters.team || null
|
||||
filters.team || null,
|
||||
filters.sort_by,
|
||||
filters.sort_order
|
||||
);
|
||||
|
||||
// Store in session storage
|
||||
|
@ -475,7 +495,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
|||
team: "",
|
||||
model: "",
|
||||
min_spend: null,
|
||||
max_spend: null
|
||||
max_spend: null,
|
||||
sort_by: "created_at",
|
||||
sort_order: "desc"
|
||||
});
|
||||
}}
|
||||
>
|
||||
|
@ -602,9 +624,14 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
|||
</div>
|
||||
|
||||
<UserDataTable
|
||||
data={userListResponse.users || []}
|
||||
data={userListResponse?.users || []}
|
||||
columns={tableColumns}
|
||||
isLoading={!userListResponse}
|
||||
onSortChange={handleSortChange}
|
||||
currentSort={{
|
||||
sortBy: filters.sort_by,
|
||||
sortOrder: filters.sort_order
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</TabPanel>
|
||||
|
|
|
@ -23,15 +23,25 @@ interface UserDataTableProps {
|
|||
data: UserInfo[];
|
||||
columns: ColumnDef<UserInfo, any>[];
|
||||
isLoading?: boolean;
|
||||
onSortChange?: (sortBy: string, sortOrder: 'asc' | 'desc') => void;
|
||||
currentSort?: {
|
||||
sortBy: string;
|
||||
sortOrder: 'asc' | 'desc';
|
||||
};
|
||||
}
|
||||
|
||||
export function UserDataTable({
|
||||
data = [],
|
||||
columns,
|
||||
isLoading = false,
|
||||
onSortChange,
|
||||
currentSort,
|
||||
}: UserDataTableProps) {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([
|
||||
{ id: "created_at", desc: true }
|
||||
{
|
||||
id: currentSort?.sortBy || "created_at",
|
||||
desc: currentSort?.sortOrder === "desc"
|
||||
}
|
||||
]);
|
||||
|
||||
const table = useReactTable({
|
||||
|
@ -40,12 +50,30 @@ export function UserDataTable({
|
|||
state: {
|
||||
sorting,
|
||||
},
|
||||
onSortingChange: setSorting,
|
||||
onSortingChange: (newSorting) => {
|
||||
setSorting(newSorting);
|
||||
if (newSorting.length > 0) {
|
||||
const sortState = newSorting[0];
|
||||
const sortBy = sortState.id;
|
||||
const sortOrder = sortState.desc ? 'desc' : 'asc';
|
||||
onSortChange?.(sortBy, sortOrder);
|
||||
}
|
||||
},
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
enableSorting: true,
|
||||
});
|
||||
|
||||
// Update local sorting state when currentSort prop changes
|
||||
React.useEffect(() => {
|
||||
if (currentSort) {
|
||||
setSorting([{
|
||||
id: currentSort.sortBy,
|
||||
desc: currentSort.sortOrder === 'desc'
|
||||
}]);
|
||||
}
|
||||
}, [currentSort]);
|
||||
|
||||
return (
|
||||
<div className="rounded-lg custom-border relative">
|
||||
<div className="overflow-x-auto">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue