Platform breakdown on Pulse, cost display on sessions
This commit is contained in:
@@ -7,6 +7,7 @@ import { StatusCard } from "@/components/StatusCard";
|
|||||||
import { StatsCard } from "@/components/StatsCard";
|
import { StatsCard } from "@/components/StatsCard";
|
||||||
import { SessionCard } from "@/components/SessionCard";
|
import { SessionCard } from "@/components/SessionCard";
|
||||||
import { MemorySnapshotCard } from "@/components/MemorySnapshotCard";
|
import { MemorySnapshotCard } from "@/components/MemorySnapshotCard";
|
||||||
|
import { PlatformBreakdown } from "@/components/PlatformBreakdown";
|
||||||
import { useSessions } from "@/lib/hooks";
|
import { useSessions } from "@/lib/hooks";
|
||||||
import { usePullToRefresh } from "@/lib/usePullToRefresh";
|
import { usePullToRefresh } from "@/lib/usePullToRefresh";
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ export default function PulsePage() {
|
|||||||
<StatusCard />
|
<StatusCard />
|
||||||
<StatsCard />
|
<StatsCard />
|
||||||
<MemorySnapshotCard />
|
<MemorySnapshotCard />
|
||||||
|
<PlatformBreakdown />
|
||||||
|
|
||||||
<div className="grid grid-cols-4 gap-2">
|
<div className="grid grid-cols-4 gap-2">
|
||||||
{QUICK_LINKS.map(({ href, label, icon: Icon }) => (
|
{QUICK_LINKS.map(({ href, label, icon: Icon }) => (
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useSessions } from "@/lib/hooks";
|
||||||
|
import { platformBadgeClass } from "@/lib/utils";
|
||||||
|
|
||||||
|
export function PlatformBreakdown() {
|
||||||
|
const { data } = useSessions(50);
|
||||||
|
const items = data?.items || [];
|
||||||
|
|
||||||
|
if (items.length === 0) return null;
|
||||||
|
|
||||||
|
const counts: Record<string, number> = {};
|
||||||
|
for (const s of items) {
|
||||||
|
counts[s.source] = (counts[s.source] || 0) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1]);
|
||||||
|
const total = items.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="card p-4">
|
||||||
|
<div className="section-label mb-3">Platforms</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{sorted.map(([platform, count]) => {
|
||||||
|
const pct = Math.round((count / total) * 100);
|
||||||
|
return (
|
||||||
|
<div key={platform} className="flex items-center gap-3">
|
||||||
|
<span className={`badge ${platformBadgeClass(platform)} w-16 text-center`}>
|
||||||
|
{platform}
|
||||||
|
</span>
|
||||||
|
<div className="flex-1 h-1.5 rounded-full" style={{ background: "var(--border)" }}>
|
||||||
|
<div
|
||||||
|
className="h-full rounded-full transition-all"
|
||||||
|
style={{ width: pct + "%", background: "var(--accent)" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="text-[11px] font-mono w-8 text-right" style={{ color: "var(--text-3)" }}>
|
||||||
|
{count}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -8,13 +8,14 @@ import type { Session } from "@/lib/types";
|
|||||||
export function SessionCard({ session }: { session: Session }) {
|
export function SessionCard({ session }: { session: Session }) {
|
||||||
const tokens = session.input_tokens + session.output_tokens;
|
const tokens = session.input_tokens + session.output_tokens;
|
||||||
const title = session.title || "Untitled session";
|
const title = session.title || "Untitled session";
|
||||||
|
const cost = session.estimated_cost_usd;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={`/history/${session.id}`}>
|
<Link href={`/history/${session.id}`}>
|
||||||
<div className="flex items-center gap-3 py-3 px-1 border-b border-white/[0.04] active:bg-white/[0.02] transition-colors">
|
<div className="flex items-center gap-3 py-3 px-1 border-b border-white/[0.04] active:bg-white/[0.02] transition-colors">
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="text-[14px] text-[var(--text-1)] truncate">{title}</div>
|
<div className="text-[14px] text-[var(--text-1)] truncate">{title}</div>
|
||||||
<div className="flex items-center gap-2 mt-0.5">
|
<div className="flex items-center gap-2 mt-0.5 flex-wrap">
|
||||||
<span className={`badge ${platformBadgeClass(session.source)}`}>
|
<span className={`badge ${platformBadgeClass(session.source)}`}>
|
||||||
{session.source}
|
{session.source}
|
||||||
</span>
|
</span>
|
||||||
@@ -26,6 +27,11 @@ export function SessionCard({ session }: { session: Session }) {
|
|||||||
{formatTokens(tokens)}
|
{formatTokens(tokens)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
{cost != null && cost > 0 && (
|
||||||
|
<span className="text-[11px]" style={{ color: "var(--text-3)" }}>
|
||||||
|
${cost.toFixed(2)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
<span className="text-[11px] ml-auto" style={{ color: "var(--text-3)" }}>
|
<span className="text-[11px] ml-auto" style={{ color: "var(--text-3)" }}>
|
||||||
{timeAgo(session.started_at)}
|
{timeAgo(session.started_at)}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user