mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-27 11:43:54 +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,
|
userEmail: string | null = null,
|
||||||
userRole: string | null = null,
|
userRole: string | null = null,
|
||||||
team: string | null = null,
|
team: string | null = null,
|
||||||
|
sortBy: string | null = null,
|
||||||
|
sortOrder: 'asc' | 'desc' | null = null,
|
||||||
) => {
|
) => {
|
||||||
/**
|
/**
|
||||||
* Get all available teams on proxy
|
* Get all available teams on proxy
|
||||||
|
@ -714,6 +716,14 @@ export const userListCall = async (
|
||||||
queryParams.append('team', team);
|
queryParams.append('team', team);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sortBy) {
|
||||||
|
queryParams.append('sort_by', sortBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortOrder) {
|
||||||
|
queryParams.append('sort_order', sortOrder);
|
||||||
|
}
|
||||||
|
|
||||||
const queryString = queryParams.toString();
|
const queryString = queryParams.toString();
|
||||||
if (queryString) {
|
if (queryString) {
|
||||||
url += `?${queryString}`;
|
url += `?${queryString}`;
|
||||||
|
|
|
@ -88,6 +88,8 @@ interface FilterState {
|
||||||
model: string;
|
model: string;
|
||||||
min_spend: number | null;
|
min_spend: number | null;
|
||||||
max_spend: number | null;
|
max_spend: number | null;
|
||||||
|
sort_by: string;
|
||||||
|
sort_order: 'asc' | 'desc';
|
||||||
}
|
}
|
||||||
|
|
||||||
const isLocal = process.env.NODE_ENV === "development";
|
const isLocal = process.env.NODE_ENV === "development";
|
||||||
|
@ -127,7 +129,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
||||||
team: "",
|
team: "",
|
||||||
model: "",
|
model: "",
|
||||||
min_spend: null,
|
min_spend: null,
|
||||||
max_spend: null
|
max_spend: null,
|
||||||
|
sort_by: "created_at",
|
||||||
|
sort_order: "desc"
|
||||||
});
|
});
|
||||||
const [showFilters, setShowFilters] = useState(false);
|
const [showFilters, setShowFilters] = useState(false);
|
||||||
const [showColumnDropdown, setShowColumnDropdown] = useState(false);
|
const [showColumnDropdown, setShowColumnDropdown] = useState(false);
|
||||||
|
@ -155,6 +159,16 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
||||||
debouncedSearch(newFilters);
|
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
|
// Create a debounced version of the search function
|
||||||
const debouncedSearch = useCallback(
|
const debouncedSearch = useCallback(
|
||||||
debounce(async (filters: FilterState) => {
|
debounce(async (filters: FilterState) => {
|
||||||
|
@ -174,7 +188,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
||||||
defaultPageSize,
|
defaultPageSize,
|
||||||
filters.email || null,
|
filters.email || null,
|
||||||
filters.user_role || 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
|
// Only update state if this is the most recent search
|
||||||
|
@ -302,7 +318,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
||||||
defaultPageSize,
|
defaultPageSize,
|
||||||
filters.email || null,
|
filters.email || null,
|
||||||
filters.user_role || null,
|
filters.user_role || null,
|
||||||
filters.team || null
|
filters.team || null,
|
||||||
|
filters.sort_by,
|
||||||
|
filters.sort_order
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update session storage with new data
|
// Update session storage with new data
|
||||||
|
@ -339,7 +357,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
||||||
defaultPageSize,
|
defaultPageSize,
|
||||||
filters.email || null,
|
filters.email || null,
|
||||||
filters.user_role || null,
|
filters.user_role || null,
|
||||||
filters.team || null
|
filters.team || null,
|
||||||
|
filters.sort_by,
|
||||||
|
filters.sort_order
|
||||||
);
|
);
|
||||||
|
|
||||||
// Store in session storage
|
// Store in session storage
|
||||||
|
@ -475,7 +495,9 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
||||||
team: "",
|
team: "",
|
||||||
model: "",
|
model: "",
|
||||||
min_spend: null,
|
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>
|
</div>
|
||||||
|
|
||||||
<UserDataTable
|
<UserDataTable
|
||||||
data={userListResponse.users || []}
|
data={userListResponse?.users || []}
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
isLoading={!userListResponse}
|
isLoading={!userListResponse}
|
||||||
|
onSortChange={handleSortChange}
|
||||||
|
currentSort={{
|
||||||
|
sortBy: filters.sort_by,
|
||||||
|
sortOrder: filters.sort_order
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
|
@ -23,15 +23,25 @@ interface UserDataTableProps {
|
||||||
data: UserInfo[];
|
data: UserInfo[];
|
||||||
columns: ColumnDef<UserInfo, any>[];
|
columns: ColumnDef<UserInfo, any>[];
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
|
onSortChange?: (sortBy: string, sortOrder: 'asc' | 'desc') => void;
|
||||||
|
currentSort?: {
|
||||||
|
sortBy: string;
|
||||||
|
sortOrder: 'asc' | 'desc';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function UserDataTable({
|
export function UserDataTable({
|
||||||
data = [],
|
data = [],
|
||||||
columns,
|
columns,
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
|
onSortChange,
|
||||||
|
currentSort,
|
||||||
}: UserDataTableProps) {
|
}: UserDataTableProps) {
|
||||||
const [sorting, setSorting] = React.useState<SortingState>([
|
const [sorting, setSorting] = React.useState<SortingState>([
|
||||||
{ id: "created_at", desc: true }
|
{
|
||||||
|
id: currentSort?.sortBy || "created_at",
|
||||||
|
desc: currentSort?.sortOrder === "desc"
|
||||||
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
|
@ -40,12 +50,30 @@ export function UserDataTable({
|
||||||
state: {
|
state: {
|
||||||
sorting,
|
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(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
enableSorting: true,
|
enableSorting: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update local sorting state when currentSort prop changes
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (currentSort) {
|
||||||
|
setSorting([{
|
||||||
|
id: currentSort.sortBy,
|
||||||
|
desc: currentSort.sortOrder === 'desc'
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
}, [currentSort]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg custom-border relative">
|
<div className="rounded-lg custom-border relative">
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue