({
data,
prices,
page,
onPage,
pageSize,
}: {
data: SessionsResponse | null;
prices: PriceTable;
page: number;
onPage: (page: number) => void;
pageSize: number;
})
| 89 | } |
| 90 | |
| 91 | export default function SessionsPanel({ |
| 92 | data, |
| 93 | prices, |
| 94 | page, |
| 95 | onPage, |
| 96 | pageSize, |
| 97 | }: { |
| 98 | data: SessionsResponse | null; |
| 99 | prices: PriceTable; |
| 100 | page: number; |
| 101 | onPage: (page: number) => void; |
| 102 | pageSize: number; |
| 103 | }) { |
| 104 | const [expanded, setExpanded] = useState<string | null>(null); |
| 105 | |
| 106 | if (!data) { |
| 107 | return <EmptyState variant="dashed">Loading session accounting…</EmptyState>; |
| 108 | } |
| 109 | if (!data.available) { |
| 110 | return ( |
| 111 | <EmptyState variant="dashed"> |
| 112 | <h3>Session store unavailable</h3> |
| 113 | <p>No session database could be opened for this project.</p> |
| 114 | </EmptyState> |
| 115 | ); |
| 116 | } |
| 117 | if (!data.sessions.length) { |
| 118 | return ( |
| 119 | <EmptyState variant="dashed"> |
| 120 | <h3>No sessions in this range</h3> |
| 121 | <p> |
| 122 | Sessions appear here once agent transcripts are ingested into the |
| 123 | session store ({data.db}). Sessions without timestamps are only |
| 124 | listed in the “All time” range. |
| 125 | </p> |
| 126 | </EmptyState> |
| 127 | ); |
| 128 | } |
| 129 | |
| 130 | const pageCount = Math.max(1, Math.ceil(data.total / pageSize)); |
| 131 | |
| 132 | return ( |
| 133 | <Card> |
| 134 | <CardHeader> |
| 135 | <CardTitle>Session cost accounting</CardTitle> |
| 136 | </CardHeader> |
| 137 | <CardContent> |
| 138 | <div className="tss-table-scroll"> |
| 139 | <table className="tss-table"> |
| 140 | <thead> |
| 141 | <tr> |
| 142 | <th>Session</th> |
| 143 | <th>Models</th> |
| 144 | <th>Messages</th> |
| 145 | <th>Tokens in</th> |
| 146 | <th>Tokens out</th> |
| 147 | <th>Cost</th> |
| 148 | <th>Basis</th> |
nothing calls this directly
no test coverage detected