Pipeline/frontend/src/components/dashboard/SessionsSection.tsx

112 lines
4.1 KiB
TypeScript
Raw Normal View History

2026-05-19 23:11:32 -05:00
import { DashboardSection } from "./DashboardSection";
import { DashboardEmptyState } from "./DashboardEmptyState";
export type SessionSummary = {
2026-05-19 23:11:32 -05:00
key: string;
title: string;
subtitle: string;
usage: string;
lastSeenAt: string | null;
isMain: boolean;
/** Enriched from runtime usage when session IDs match */
costUsd?: number | null;
totalTokens?: number | null;
model?: string | null;
2026-05-19 23:11:32 -05:00
};
interface SessionsSectionProps {
sessions: SessionSummary[];
activeSessions: number;
hasConfiguredGateways: boolean;
isLoading: boolean;
gatewayUnavailableCount: number;
gatewayTargetsCount: number;
formatCount: (n: number) => string;
formatRelative: (ts: string) => string;
dash: string;
}
export function SessionsSection({
sessions,
activeSessions,
hasConfiguredGateways,
isLoading,
gatewayUnavailableCount,
gatewayTargetsCount,
formatCount,
formatRelative,
dash,
}: SessionsSectionProps) {
return (
<DashboardSection title="Sessions" action={{ label: formatCount(activeSessions), href: "#" }}>
<div className="max-h-[310px] space-y-2 overflow-x-hidden overflow-y-auto pr-1">
{!hasConfiguredGateways ? (
<DashboardEmptyState message="No gateways are configured for any board yet." />
) : isLoading ? (
<DashboardEmptyState message="Loading sessions..." />
) : sessions.length > 0 ? (
<>
{gatewayUnavailableCount > 0 && (
<DashboardEmptyState
tone="warning"
message={`${formatCount(gatewayUnavailableCount)} gateway${gatewayUnavailableCount === 1 ? "" : "s"} unavailable; showing sessions from reachable gateways.`}
/>
)}
{sessions.map((session) => (
<div
key={session.key}
className="overflow-hidden rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-muted)] px-3 py-2"
>
<div className="flex items-center justify-between gap-3">
<div className="min-w-0 flex-1">
<p className="truncate text-sm font-medium text-strong">
<span
className={`mr-2 inline-block h-2 w-2 rounded-full ${
session.isMain
? "bg-[color:var(--success)]"
: "bg-[color:var(--border-strong)]"
}`}
/>
{session.title}
</p>
<p className="mt-0.5 truncate text-xs text-muted">{session.subtitle}</p>
</div>
<div className="min-w-0 max-w-[45%] text-right">
<p className="truncate text-xs font-medium text-strong">
{session.costUsd != null
? session.costUsd === 0
? "$0.00"
: session.costUsd < 0.01
? `$${session.costUsd.toFixed(4)}`
: `$${session.costUsd.toFixed(2)}`
: session.usage === dash
? "Usage unavailable"
: session.usage}
2026-05-19 23:11:32 -05:00
</p>
<p className="truncate text-[11px] text-muted">
{session.model
? session.model.includes("/")
? session.model.split("/")[1]
: session.model
: null}
{session.model && session.lastSeenAt ? " · " : null}
2026-05-19 23:11:32 -05:00
{session.lastSeenAt ? formatRelative(session.lastSeenAt) : "Activity unavailable"}
</p>
</div>
</div>
</div>
))}
</>
) : gatewayUnavailableCount === gatewayTargetsCount ? (
<DashboardEmptyState
tone="danger"
message="Session data is unavailable for all configured gateways."
/>
) : (
<DashboardEmptyState message="No active sessions detected." />
)}
</div>
</DashboardSection>
);
}