Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/app/routers/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def trending(n: int = Query(10, ge=1, le=50)):
}
agents.append(agent)

agents_sorted = sorted(agents, key=lambda a: (-a.get("installs", 0), -a.get("rating", 0.0)))
agents_sorted = sorted(agents, key=lambda a: (-(a.get("installs") or 0), -(a.get("rating") or 0.0)))
return [AgentSummary(**a) for a in agents_sorted[:n]]


Expand Down
94 changes: 57 additions & 37 deletions frontend/src/pages/TrendingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,66 @@
import { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { fetchTrending, type AgentSummary } from '../api/client'
import AgentCard from '../components/AgentCard'
import { useEffect, useState } from "react";

/**
* TrendingPage — agents ranked by installs then rating.
*/
export default function TrendingPage() {
const [agents, setAgents] = useState<AgentSummary[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
interface Agent {
id: string;
name: string;
description: string;
category: string;
rating: number;
installs: number;
downloads: number;
tags: string[];
tools_required: string[];
}

export default function TrendingAgents() {
const [agents, setAgents] = useState<Agent[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
fetchTrending(10)
.then(setAgents)
.catch((e) => setError(e.message))
.finally(() => setLoading(false))
}, [])
fetch("http://localhost:8000/agents/trending?n=10")
.then((res) => {
if (!res.ok) throw new Error("Failed to fetch trending agents");
return res.json();
})
.then((data) => {
setAgents(data);
setLoading(false);
})
.catch((err) => {
setError(err.message);
setLoading(false);
});
}, []);

if (loading) return <p>Loading trending agents...</p>
if (error) {
return (
<div>
<h1 className="page-title">Trending Agents</h1>
<div className="placeholder-notice">
Could not load trending agents ({error}). Is the backend running?
</div>
</div>
)
}
if (loading) return <p>Loading trending agents...</p>;
if (error) return <p>Error: {error}</p>;

return (
<div>
<h1 className="page-title">Trending Agents</h1>
<p style={{ marginBottom: '1rem', color: '#6b7280' }}>
Ranked by installs and rating. <Link to="/agents">Browse all agents</Link>
</p>
<div className="agent-grid">
{agents.map((agent) => (
<AgentCard key={agent.id} agent={agent} />
))}
</div>
<h1>Trending Agents</h1>
{agents.map((agent) => (
<div
key={agent.id}
style={{ border: "1px solid #ccc", margin: "1rem", padding: "1rem" }}
>
<h2>{agent.name}</h2>
<p>{agent.description}</p>
<p>
<strong>Category:</strong> {agent.category}
</p>
<p>
<strong>Rating:</strong> {agent.rating} ⭐
</p>
<p>
<strong>Installs:</strong> {agent.installs.toLocaleString()}
</p>
<p>
<strong>Tools:</strong> {agent.tools_required.join(", ")}
</p>
<a href={`/agents/${agent.id}`}>View Details →</a>
</div>
))}
</div>
)
);
}