fix(#338): Handle non-OK responses in ActiveProjectsWidget

- Add error state tracking for both projects and agents API calls
- Show error UI (amber alert icon + message) when fetch fails
- Clear data on error to avoid showing stale information
- Added tests for error handling: API failures, network errors

Refs #338

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-05 17:50:18 -06:00
parent 1a15c12c56
commit 1c79da70a6
2 changed files with 130 additions and 0 deletions

View File

@@ -38,17 +38,23 @@ export function ActiveProjectsWidget({ id: _id, config: _config }: WidgetProps):
const [agentSessions, setAgentSessions] = useState<AgentSession[]>([]);
const [isLoadingProjects, setIsLoadingProjects] = useState(true);
const [isLoadingAgents, setIsLoadingAgents] = useState(true);
const [projectsError, setProjectsError] = useState<string | null>(null);
const [agentsError, setAgentsError] = useState<string | null>(null);
const [expandedSession, setExpandedSession] = useState<string | null>(null);
// Fetch active projects
useEffect(() => {
const fetchProjects = async (): Promise<void> => {
try {
setProjectsError(null);
// Use API client to ensure CSRF token is included
const data = await apiPost<ActiveProject[]>("/api/widgets/data/active-projects");
setProjects(data);
} catch (error) {
console.error("Failed to fetch active projects:", error);
const errorMessage = error instanceof Error ? error.message : "Unknown error";
setProjectsError(errorMessage);
setProjects([]);
} finally {
setIsLoadingProjects(false);
}
@@ -67,11 +73,15 @@ export function ActiveProjectsWidget({ id: _id, config: _config }: WidgetProps):
useEffect(() => {
const fetchAgentSessions = async (): Promise<void> => {
try {
setAgentsError(null);
// Use API client to ensure CSRF token is included
const data = await apiPost<AgentSession[]>("/api/widgets/data/agent-chains");
setAgentSessions(data);
} catch (error) {
console.error("Failed to fetch agent sessions:", error);
const errorMessage = error instanceof Error ? error.message : "Unknown error";
setAgentsError(errorMessage);
setAgentSessions([]);
} finally {
setIsLoadingAgents(false);
}
@@ -137,6 +147,13 @@ export function ActiveProjectsWidget({ id: _id, config: _config }: WidgetProps):
<div className="overflow-auto max-h-48 space-y-2">
{isLoadingProjects ? (
<div className="text-center text-gray-500 text-xs py-4">Loading projects...</div>
) : projectsError ? (
<div className="text-center text-xs py-4">
<div className="flex items-center justify-center gap-1 text-amber-600">
<AlertCircle className="w-3 h-3" />
<span>Unable to load projects</span>
</div>
</div>
) : projects.length === 0 ? (
<div className="text-center text-gray-500 text-xs py-4">No active projects</div>
) : (
@@ -185,6 +202,13 @@ export function ActiveProjectsWidget({ id: _id, config: _config }: WidgetProps):
<div className="overflow-auto max-h-48 space-y-2">
{isLoadingAgents ? (
<div className="text-center text-gray-500 text-xs py-4">Loading agents...</div>
) : agentsError ? (
<div className="text-center text-xs py-4">
<div className="flex items-center justify-center gap-1 text-amber-600">
<AlertCircle className="w-3 h-3" />
<span>Unable to load agents</span>
</div>
</div>
) : agentSessions.length === 0 ? (
<div className="text-center text-gray-500 text-xs py-4">No running agents</div>
) : (