Add HUD widget for tracking active projects and running agent sessions. Backend: - Add getActiveProjectsData() and getAgentChainsData() to WidgetDataService - Create POST /api/widgets/data/active-projects endpoint - Create POST /api/widgets/data/agent-chains endpoint - Add WidgetProjectItem and WidgetAgentSessionItem response types Frontend: - Create ActiveProjectsWidget component with dual panels - Active Projects panel: name, color, task/event counts, last activity - Agent Chains panel: status, runtime, message count, expandable details - Real-time updates (projects: 30s, agents: 10s) - PDA-friendly status indicators (Running vs URGENT) Testing: - 7 comprehensive tests covering loading, rendering, empty states, expandability - All tests passing (7/7) Refs #52 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
130 lines
3.8 KiB
TypeScript
130 lines
3.8 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Post,
|
|
Body,
|
|
Param,
|
|
UseGuards,
|
|
Request,
|
|
UnauthorizedException,
|
|
} from "@nestjs/common";
|
|
import { WidgetsService } from "./widgets.service";
|
|
import { WidgetDataService } from "./widget-data.service";
|
|
import { AuthGuard } from "../auth/guards/auth.guard";
|
|
import type { StatCardQueryDto, ChartQueryDto, ListQueryDto, CalendarPreviewQueryDto } from "./dto";
|
|
import type { AuthenticatedRequest } from "../common/types/user.types";
|
|
|
|
/**
|
|
* Controller for widget definition and data endpoints
|
|
* All endpoints require authentication
|
|
*/
|
|
@Controller("widgets")
|
|
@UseGuards(AuthGuard)
|
|
export class WidgetsController {
|
|
constructor(
|
|
private readonly widgetsService: WidgetsService,
|
|
private readonly widgetDataService: WidgetDataService
|
|
) {}
|
|
|
|
/**
|
|
* GET /api/widgets
|
|
* List all available widget definitions
|
|
* Returns only active widgets
|
|
*/
|
|
@Get()
|
|
async findAll() {
|
|
return this.widgetsService.findAll();
|
|
}
|
|
|
|
/**
|
|
* GET /api/widgets/:name
|
|
* Get a widget definition by name
|
|
* Useful for fetching widget configuration schemas
|
|
*/
|
|
@Get(":name")
|
|
async findByName(@Param("name") name: string) {
|
|
return this.widgetsService.findByName(name);
|
|
}
|
|
|
|
/**
|
|
* POST /api/widgets/data/stat-card
|
|
* Get stat card widget data
|
|
*/
|
|
@Post("data/stat-card")
|
|
async getStatCardData(@Request() req: AuthenticatedRequest, @Body() query: StatCardQueryDto) {
|
|
const workspaceId = req.user?.currentWorkspaceId ?? req.user?.workspaceId;
|
|
if (!workspaceId) {
|
|
throw new UnauthorizedException("Workspace ID required");
|
|
}
|
|
return this.widgetDataService.getStatCardData(workspaceId, query);
|
|
}
|
|
|
|
/**
|
|
* POST /api/widgets/data/chart
|
|
* Get chart widget data
|
|
*/
|
|
@Post("data/chart")
|
|
async getChartData(@Request() req: AuthenticatedRequest, @Body() query: ChartQueryDto) {
|
|
const workspaceId = req.user?.currentWorkspaceId ?? req.user?.workspaceId;
|
|
if (!workspaceId) {
|
|
throw new UnauthorizedException("Workspace ID required");
|
|
}
|
|
return this.widgetDataService.getChartData(workspaceId, query);
|
|
}
|
|
|
|
/**
|
|
* POST /api/widgets/data/list
|
|
* Get list widget data
|
|
*/
|
|
@Post("data/list")
|
|
async getListData(@Request() req: AuthenticatedRequest, @Body() query: ListQueryDto) {
|
|
const workspaceId = req.user?.currentWorkspaceId ?? req.user?.workspaceId;
|
|
if (!workspaceId) {
|
|
throw new UnauthorizedException("Workspace ID required");
|
|
}
|
|
return this.widgetDataService.getListData(workspaceId, query);
|
|
}
|
|
|
|
/**
|
|
* POST /api/widgets/data/calendar-preview
|
|
* Get calendar preview widget data
|
|
*/
|
|
@Post("data/calendar-preview")
|
|
async getCalendarPreviewData(
|
|
@Request() req: AuthenticatedRequest,
|
|
@Body() query: CalendarPreviewQueryDto
|
|
) {
|
|
const workspaceId = req.user?.currentWorkspaceId ?? req.user?.workspaceId;
|
|
if (!workspaceId) {
|
|
throw new UnauthorizedException("Workspace ID required");
|
|
}
|
|
return this.widgetDataService.getCalendarPreviewData(workspaceId, query);
|
|
}
|
|
|
|
/**
|
|
* POST /api/widgets/data/active-projects
|
|
* Get active projects widget data
|
|
*/
|
|
@Post("data/active-projects")
|
|
async getActiveProjectsData(@Request() req: AuthenticatedRequest) {
|
|
const workspaceId = req.user?.currentWorkspaceId ?? req.user?.workspaceId;
|
|
if (!workspaceId) {
|
|
throw new UnauthorizedException("Workspace ID required");
|
|
}
|
|
return this.widgetDataService.getActiveProjectsData(workspaceId);
|
|
}
|
|
|
|
/**
|
|
* POST /api/widgets/data/agent-chains
|
|
* Get agent chains widget data (active agent sessions)
|
|
*/
|
|
@Post("data/agent-chains")
|
|
async getAgentChainsData(@Request() req: AuthenticatedRequest) {
|
|
const workspaceId = req.user?.currentWorkspaceId ?? req.user?.workspaceId;
|
|
if (!workspaceId) {
|
|
throw new UnauthorizedException("Workspace ID required");
|
|
}
|
|
return this.widgetDataService.getAgentChainsData(workspaceId);
|
|
}
|
|
}
|