Skip to content

Commit

Permalink
Merge pull request #236 from giselles-ai/feat/agent-logs-view
Browse files Browse the repository at this point in the history
feat: Add agent activity logs viewer with detailed dialog
  • Loading branch information
gentamura authored Dec 17, 2024
2 parents faea333 + 20029cc commit 43eb896
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 1 deletion.
52 changes: 51 additions & 1 deletion app/(main)/settings/team/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import {
type TeamRole,
type UserId,
agentActivities,
agents,
db,
supabaseUserMappings,
teamMemberships,
Expand All @@ -11,7 +13,7 @@ import {
} from "@/drizzle";
import { getUser } from "@/lib/supabase";
import { fetchCurrentTeam, isProPlan } from "@/services/teams";
import { and, asc, count, eq, ne } from "drizzle-orm";
import { and, asc, count, desc, eq, ne } from "drizzle-orm";
import { revalidatePath } from "next/cache";

function isUserId(value: string): value is UserId {
Expand Down Expand Up @@ -422,3 +424,51 @@ export async function getCurrentUserRole() {
};
}
}

export async function getAgentActivities({
limit = 50,
}: { limit?: number } = {}) {
try {
const currentTeam = await fetchCurrentTeam();

const activities = await db
.select({
agentId: agents.id,
agentName: agents.name,
startTime: agentActivities.startedAt,
endTime: agentActivities.endedAt,
usedCharge: agentActivities.totalDurationMs,
})
.from(agentActivities)
.innerJoin(
agents,
and(
eq(agentActivities.agentDbId, agents.dbId),
eq(agents.teamDbId, currentTeam.dbId),
),
)
.orderBy(desc(agentActivities.startedAt))
.limit(limit);

const formattedActivities = activities.map((activity) => ({
...activity,
// Convert milliseconds to seconds and round to 2 decimal places
usedCharge: Math.ceil((activity.usedCharge / 1000) * 100) / 100,
}));

return {
success: true,
data: formattedActivities,
};
} catch (error) {
console.error("Failed to get agent activities:", error);

return {
success: false,
error:
error instanceof Error
? error.message
: "Failed to get agent activities",
};
}
}
32 changes: 32 additions & 0 deletions app/(main)/settings/team/agent-usage-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { type AgentActivity, AgentUsageTable } from "./agent-usage-table";

type AgentUsageDialogProps = {
activities: AgentActivity[];
};

export function AgentUsageDialog({ activities }: AgentUsageDialogProps) {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="link">View all logs</Button>
</DialogTrigger>
<DialogContent className="max-w-7xl">
<DialogHeader>
<DialogTitle>Agent Usage Logs</DialogTitle>
</DialogHeader>
<AgentUsageTable
activities={activities}
containerClassName="max-h-[60vh] overflow-y-auto"
/>
</DialogContent>
</Dialog>
);
}
59 changes: 59 additions & 0 deletions app/(main)/settings/team/agent-usage-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { LocalDateTime } from "./components/local-date-time";

export type AgentActivity = {
agentId: string;
agentName: string | null;
startTime: Date;
endTime: Date | null;
usedCharge: number;
};

type AgentUsageTableProps = {
activities: AgentActivity[];
containerClassName?: string;
};

export function AgentUsageTable({
activities,
containerClassName,
}: AgentUsageTableProps) {
return (
<div className="font-avenir rounded-[16px]">
<div className="grid grid-cols-4 gap-4 border-b border-zinc-800 bg-zinc-900/50 p-4 font-medium text-zinc-200">
<div>Agent</div>
<div>Start Time</div>
<div>End Time</div>
<div>Charge</div>
</div>
<div className={containerClassName}>
<div className="divide-y divide-zinc-800">
{activities.length > 0 ? (
activities.map((activity) => (
<div
key={`${activity.agentId}-${activity.startTime}`}
className="grid grid-cols-4 gap-4 p-4 items-center text-zinc-200"
>
<div className="break-words max-w-xs">
{activity.agentName ?? activity.agentId}
</div>
<div className="text-zinc-400">
<LocalDateTime date={new Date(activity.startTime)} />
</div>
<div className="text-zinc-400">
{activity.endTime ? (
<LocalDateTime date={new Date(activity.endTime)} />
) : (
"-"
)}
</div>
<div>{activity.usedCharge} seconds</div>
</div>
))
) : (
<div className="p-4 text-zinc-400">No agent activities</div>
)}
</div>
</div>
</div>
);
}
33 changes: 33 additions & 0 deletions app/(main)/settings/team/agent-usage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Card } from "@/app/(main)/settings/components/card";
import { getAgentActivities } from "./actions";
import { AgentUsageDialog } from "./agent-usage-dialog";
import { AgentUsageTable } from "./agent-usage-table";

export async function AgentUsage() {
const result = await getAgentActivities({ limit: 50 });

if (!result.success || !result.data) {
return (
<Card title="Recent Agent Usage">
<div className="text-zinc-400 p-4">Failed to load agent activities</div>
</Card>
);
}

const activities = result.data;
const recentActivities = activities.slice(0, 3);

return (
<Card
title="Recent Agent Usage"
action={{
component:
activities.length > 0 ? (
<AgentUsageDialog activities={activities} />
) : null,
}}
>
<AgentUsageTable activities={recentActivities} />
</Card>
);
}
21 changes: 21 additions & 0 deletions app/(main)/settings/team/components/local-date-time.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use client";

export function LocalDateTime({
date,
format = {
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
hour12: false,
timeZoneName: "short",
},
}: {
date: Date;
format?: Intl.DateTimeFormatOptions;
}) {
const formattedDate = new Intl.DateTimeFormat("en-US", format).format(date);

return <time dateTime={date.toISOString()}>{formattedDate}</time>;
}
2 changes: 2 additions & 0 deletions app/(main)/settings/team/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Skeleton } from "@/components/ui/skeleton";
import { Suspense } from "react";
import { AgentTimeCharge } from "./agent-time-charge";
import { AgentUsage } from "./agent-usage";
import BillingSection from "./billing-section";
import { TeamMembers } from "./team-members";
import { TeamName } from "./team-name";
Expand Down Expand Up @@ -34,6 +35,7 @@ export default function TeamPage() {
<TeamName />
</Suspense>
<TeamMembers />
<AgentUsage />
<BillingSection />
</div>
);
Expand Down

0 comments on commit 43eb896

Please sign in to comment.