Skip to content
Merged
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
104 changes: 104 additions & 0 deletions apps/web/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* Main Agent Observability Dashboard
*
* Primary landing page showing real-time agent activity across all projects
*/

import { Suspense } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';
import { Activity, Zap, Clock, TrendingUp } from 'lucide-react';

export default function DashboardPage() {
return (
<div className="container mx-auto py-6 space-y-6">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight">Agent Activity Dashboard</h1>
<p className="text-muted-foreground mt-2">
Monitor AI coding agents in real-time across all your projects
</p>
</div>
</div>

{/* Overview Stats */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Active Sessions</CardTitle>
<Activity className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">0</div>
<p className="text-xs text-muted-foreground">No active agent sessions</p>
</CardContent>
</Card>

<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Events Today</CardTitle>
<Zap className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">0</div>
<p className="text-xs text-muted-foreground">Agent events logged</p>
</CardContent>
</Card>

<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Avg Session Duration</CardTitle>
<Clock className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">-</div>
<p className="text-xs text-muted-foreground">No sessions yet</p>
</CardContent>
</Card>

<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Events Per Minute</CardTitle>
<TrendingUp className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">0</div>
<p className="text-xs text-muted-foreground">Current rate</p>
</CardContent>
</Card>
</div>

{/* Recent Activity */}
<Card>
<CardHeader>
<CardTitle>Recent Agent Activity</CardTitle>
</CardHeader>
<CardContent>
<div className="flex flex-col items-center justify-center py-12 text-center">
<div className="text-muted-foreground mb-4 text-4xl">🤖</div>
<h3 className="text-lg font-semibold mb-2">No Agent Activity Yet</h3>
<p className="text-sm text-muted-foreground max-w-md">
Start monitoring your AI coding agents by configuring collectors and starting agent sessions.
Visit the Settings page to set up your first collector.
</p>
</div>
</CardContent>
</Card>

{/* Active Sessions */}
<Card>
<CardHeader>
<CardTitle>Live Agent Sessions</CardTitle>
</CardHeader>
<CardContent>
<Suspense fallback={<Skeleton className="h-32 w-full" />}>
<div className="text-sm text-muted-foreground text-center py-8">
No active sessions
</div>
</Suspense>
</CardContent>
</Card>
</div>
);
}
4 changes: 2 additions & 2 deletions apps/web/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { AppLayout } from '@/components/layout/app-layout';
import { headers } from 'next/headers';

export const metadata: Metadata = {
title: 'Devlog Management',
description: 'Development log tracking and management dashboard',
title: 'Devlog - AI Agent Observability Platform',
description: 'Monitor and analyze AI coding agent activities in real-time',
icons: {
icon: '/devlog-logo.svg',
},
Expand Down
4 changes: 2 additions & 2 deletions apps/web/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import { redirect } from 'next/navigation';
export const dynamic = 'force-dynamic';

export default function Home() {
// Redirect to the projects page as the main entry point
redirect('/projects');
// Redirect to the dashboard as the main entry point (agent observability)
redirect('/dashboard');
}
4 changes: 2 additions & 2 deletions apps/web/app/projects/[name]/agent-sessions/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/

import { Suspense } from 'react';
import { SessionList } from '@/components/feature/agent-sessions/session-list';
import { ActiveSessionsPanel } from '@/components/feature/agent-sessions/active-sessions-panel';
import { SessionList } from '@/components/agent-observability/agent-sessions/session-list';
import { ActiveSessionsPanel } from '@/components/agent-observability/agent-sessions/active-sessions-panel';

export default function AgentSessionsPage({ params }: { params: { name: string } }) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { toast } from 'sonner';
import { DevlogEntry } from '@codervisor/devlog-core';
import { useProjectName } from '@/components/provider/project-provider';
import { useDevlogId } from '@/components/provider/devlog-provider';
import { DevlogDetails } from '@/components/feature/devlog/devlog-details';
import { DevlogDetails } from '@/components/project-management/devlog/devlog-details';

export function DevlogDetailsPage() {
const projectName = useProjectName();
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/projects/[name]/devlogs/devlog-list-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useDevlogEvents } from '@/hooks/use-realtime';
import { DevlogEntry, DevlogId } from '@codervisor/devlog-core';
import { useRouter } from 'next/navigation';
import { useProjectName } from '@/components/provider/project-provider';
import { DevlogList } from '@/components/feature/devlog/devlog-list';
import { DevlogList } from '@/components/project-management/devlog/devlog-list';

export function DevlogListPage() {
const projectName = useProjectName();
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/projects/[name]/project-details-page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import React, { useEffect } from 'react';
import { Dashboard } from '@/components/feature/dashboard/dashboard';
import { Dashboard } from '@/components/project-management/dashboard/dashboard';
import { useDevlogStore, useProjectStore } from '@/stores';
import { useDevlogEvents } from '@/hooks/use-realtime';
import { DevlogEntry } from '@codervisor/devlog-core';
Expand Down
61 changes: 61 additions & 0 deletions apps/web/app/sessions/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Global Agent Sessions Page
*
* Displays all AI agent sessions across all projects with filtering and search
*/

import { Suspense } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';

export default function SessionsPage() {
return (
<div className="container mx-auto py-6 space-y-6">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight">Agent Sessions</h1>
<p className="text-muted-foreground mt-2">
View and manage AI coding agent sessions across all projects
</p>
</div>
</div>

{/* Active Sessions */}
<Card>
<CardHeader>
<CardTitle>Active Sessions</CardTitle>
</CardHeader>
<CardContent>
<Suspense fallback={<Skeleton className="h-32 w-full" />}>
<div className="flex flex-col items-center justify-center py-12 text-center">
<div className="text-muted-foreground mb-4 text-4xl">⚡</div>
<h3 className="text-lg font-semibold mb-2">No Active Sessions</h3>
<p className="text-sm text-muted-foreground max-w-md">
No agents are currently running. Start a coding session with your AI agent to see it here.
</p>
</div>
</Suspense>
</CardContent>
</Card>

{/* Recent Sessions */}
<Card>
<CardHeader>
<CardTitle>Recent Sessions</CardTitle>
</CardHeader>
<CardContent>
<Suspense fallback={<Skeleton className="h-96 w-full" />}>
<div className="flex flex-col items-center justify-center py-12 text-center">
<div className="text-muted-foreground mb-4 text-4xl">📊</div>
<h3 className="text-lg font-semibold mb-2">No Session History</h3>
<p className="text-sm text-muted-foreground max-w-md">
Once you start using AI coding agents, their sessions will appear here for review and analysis.
</p>
</div>
</Suspense>
</CardContent>
</Card>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { SessionList } from './session-list';
export { SessionCard } from './session-card';
export { ActiveSessionsPanel } from './active-sessions-panel';
9 changes: 6 additions & 3 deletions apps/web/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ export * from './custom';
// Form Components
export * from './forms';

// Feature Components
export * from './feature/dashboard';
export * from './feature/devlog';
// Agent Observability Components (PRIMARY)
export * from './agent-observability/agent-sessions';

// Project Management Components (SECONDARY)
export * from './project-management/dashboard';
export * from './project-management/devlog';

// Project Components
// Note: ProjectResolver is not exported as it's only used server-side in layout.tsx
Expand Down
35 changes: 28 additions & 7 deletions apps/web/components/layout/navigation-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
SidebarTrigger,
useSidebar,
} from '@/components/ui/sidebar';
import { Boxes, Home, Settings, SquareKanban } from 'lucide-react';
import { Boxes, Home, Settings, SquareKanban, Activity, Zap } from 'lucide-react';

interface SidebarItem {
key: string;
Expand Down Expand Up @@ -42,6 +42,18 @@ export function NavigationSidebar() {
};

const projectsMenuItems = [
{
key: 'dashboard',
label: 'Dashboard',
icon: <Activity />,
onClick: () => router.push('/dashboard'),
},
{
key: 'sessions',
label: 'Agent Sessions',
icon: <Zap />,
onClick: () => router.push('/sessions'),
},
{
key: 'projects',
label: 'Projects',
Expand All @@ -57,8 +69,14 @@ export function NavigationSidebar() {
onClick: () => router.push(`/projects/${getProjectId()}`),
},
{
key: 'list',
label: 'Devlogs',
key: 'agent-sessions',
label: 'Agent Sessions',
icon: <Zap />,
onClick: () => router.push(`/projects/${getProjectId()}/agent-sessions`),
},
{
key: 'work-items',
label: 'Work Items',
icon: <SquareKanban />,
onClick: () => router.push(`/projects/${getProjectId()}/devlogs`),
},
Expand All @@ -85,16 +103,19 @@ export function NavigationSidebar() {

// Determine selected key based on current pathname and menu items
const getSelectedKey = () => {
if (!mounted) return 'overview';
if (!mounted) return 'dashboard';

const pathParts = pathname.split('/').filter(Boolean);

if (pathname === '/' || pathname === '/projects') return 'projects';
if (pathname === '/' || pathname === '/dashboard') return 'dashboard';
if (pathname === '/sessions') return 'sessions';
if (pathname === '/projects') return 'projects';
if (pathParts.length === 2 && pathParts[0] === 'projects') return 'overview';
if (pathParts.length >= 3 && pathParts[2] === 'devlogs') return 'list';
if (pathParts.length >= 3 && pathParts[2] === 'agent-sessions') return 'agent-sessions';
if (pathParts.length >= 3 && pathParts[2] === 'devlogs') return 'work-items';
if (pathParts.length >= 3 && pathParts[2] === 'settings') return 'settings';

return 'overview';
return 'dashboard';
}; // Don't render menu items until mounted to prevent hydration issues
Comment on lines +118 to 119
Copy link

Copilot AI Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Missing newline between function closing brace and comment. Add a blank line before the comment for better readability.

Copilot uses AI. Check for mistakes.
if (!mounted) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,10 @@ export function Dashboard({
</div>
</div>

{/* Recent Devlogs Section */}
{/* Recent Work Items Section */}
<Card className="flex-1 flex flex-col">
<CardHeader className="section-header">
<CardTitle>Recent Devlogs</CardTitle>
<CardTitle>Recent Work Items</CardTitle>
</CardHeader>
<CardContent className="flex-1 overflow-hidden">
<div className="h-full overflow-y-auto">
Expand Down Expand Up @@ -250,7 +250,7 @@ export function Dashboard({
) : recentDevlogs?.length === 0 ? (
<div className="flex flex-col items-center justify-center py-12 text-center">
<div className="text-muted-foreground mb-2 text-2xl">📝</div>
<p className="text-sm text-muted-foreground">No devlogs found</p>
<p className="text-sm text-muted-foreground">No work items found</p>
</div>
) : (
<div className="space-y-0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ export function DevlogList({
<div className="relative h-full px-6">
{/* Header with search, filters, and actions - Sticky */}
<div className="sticky top-0 z-20 bg-background border-b h-16 flex items-center justify-between">
<div className="font-semibold leading-none tracking-tight">Devlogs</div>
<div className="font-semibold leading-none tracking-tight">Work Items</div>
<div className="flex items-center space-x-2">
{/* Batch Operations */}
{selectedRowKeys.length > 0 && (
Expand Down Expand Up @@ -356,10 +356,10 @@ export function DevlogList({
</div>
</div>

{/* Devlogs Table */}
{/* Work Items Table */}
{!loading && devlogs.length === 0 ? (
<div className="text-center py-12">
<p className="text-muted-foreground mb-4">No devlogs found</p>
<p className="text-muted-foreground mb-4">No work items found</p>
</div>
) : (
<div
Expand Down Expand Up @@ -517,9 +517,9 @@ export function DevlogList({
>
<DialogContent>
<DialogHeader>
<DialogTitle>Batch Update Devlogs</DialogTitle>
<DialogTitle>Batch Update Work Items</DialogTitle>
<DialogDescription>
Update {selectedRowKeys.length} selected devlog(s). Leave fields empty to keep current
Update {selectedRowKeys.length} selected work item(s). Leave fields empty to keep current
values.
</DialogDescription>
</DialogHeader>
Expand Down Expand Up @@ -604,7 +604,7 @@ export function DevlogList({
>
Cancel
</Button>
<Button onClick={handleBatchUpdate}>Update {selectedRowKeys.length} Devlog(s)</Button>
<Button onClick={handleBatchUpdate}>Update {selectedRowKeys.length} Work Item(s)</Button>
</DialogFooter>
</DialogContent>
</Dialog>
Expand All @@ -613,9 +613,9 @@ export function DevlogList({
<AlertDialog open={deleteConfirmVisible} onOpenChange={setDeleteConfirmVisible}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete Selected Devlogs</AlertDialogTitle>
<AlertDialogTitle>Delete Selected Work Items</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to delete {selectedRowKeys.length} selected devlog(s)? This
Are you sure you want to delete {selectedRowKeys.length} selected work item(s)? This
action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
Expand All @@ -628,7 +628,7 @@ export function DevlogList({
}}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
Delete {selectedRowKeys.length} Devlog(s)
Delete {selectedRowKeys.length} Work Item(s)
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
Expand Down
Loading