feat: responsive SVG calendar, GitHub-style outline glow, interactive day inspector with session breakdown

This commit is contained in:
katR 2026-10-09 22:59:15 +05:30
parent 992983b9e2
commit 2e3f1d8a25
6 changed files with 487 additions and 211 deletions

View file

@ -166,7 +166,8 @@ async function aggregateTokens(customSessionsRoot) {
outputTokens: 0, outputTokens: 0,
cacheReadTokens: 0, cacheReadTokens: 0,
cacheWriteTokens: 0, cacheWriteTokens: 0,
turns: 0 turns: 0,
sessions: []
}; };
} }
days[date].totalTokens += stats.totalTokens; days[date].totalTokens += stats.totalTokens;
@ -175,6 +176,21 @@ async function aggregateTokens(customSessionsRoot) {
days[date].cacheReadTokens += stats.cacheReadTokens; days[date].cacheReadTokens += stats.cacheReadTokens;
days[date].cacheWriteTokens += stats.cacheWriteTokens; days[date].cacheWriteTokens += stats.cacheWriteTokens;
days[date].turns += stats.turns; days[date].turns += stats.turns;
days[date].sessions.push({
sessionId: session.id,
sessionTitle: session.title,
createdAt: session.createdAt,
totalTokens: stats.totalTokens,
inputTokens: stats.inputTokens,
outputTokens: stats.outputTokens,
cacheReadTokens: stats.cacheReadTokens,
turns: stats.turns
});
}
}
for (const day of Object.values(days)) {
if (day.sessions) {
day.sessions.sort((a, b) => b.totalTokens - a.totalTokens);
} }
} }
const positiveValues = Object.values(days).map((d) => d.totalTokens).filter((t) => t > 0).sort((a, b) => a - b); const positiveValues = Object.values(days).map((d) => d.totalTokens).filter((t) => t > 0).sort((a, b) => a - b);

File diff suppressed because one or more lines are too long

View file

@ -50,7 +50,6 @@ function formatExact(num) {
return num.toLocaleString(); return num.toLocaleString();
} }
var MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; var MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var DAY_LABELS = ["", "Mon", "", "Wed", "", "Fri", ""];
var DEEPSEEK_LEVELS = [ var DEEPSEEK_LEVELS = [
"#0f1117", "#0f1117",
// Level 0: Black / dark void tile // Level 0: Black / dark void tile
@ -63,23 +62,12 @@ var DEEPSEEK_LEVELS = [
"#4f85ff" "#4f85ff"
// Level 4: Bright electric DeepSeek blue // Level 4: Bright electric DeepSeek blue
]; ];
var TILE_SHADOWS = [
"none",
// Level 0: Black / flat
"none",
// Level 1: Dark deep blue / flat
"none",
// Level 2: Mid blue / flat
"0 0 4px rgba(51, 109, 250, 0.4)",
// Level 3: Faint brand blue edge
"0 0 10px rgba(79, 133, 255, 0.85), 0 0 2px rgba(255, 255, 255, 0.5)"
// Level 4: Bright electric blue glow
];
function HeatmapView() { function HeatmapView() {
const [data, setData] = (0, import_react.useState)(null); const [data, setData] = (0, import_react.useState)(null);
const [loading, setLoading] = (0, import_react.useState)(true); const [loading, setLoading] = (0, import_react.useState)(true);
const [error, setError] = (0, import_react.useState)(null); const [error, setError] = (0, import_react.useState)(null);
const [selectedSessionId, setSelectedSessionId] = (0, import_react.useState)("all"); const [selectedSessionId, setSelectedSessionId] = (0, import_react.useState)("all");
const [selectedDate, setSelectedDate] = (0, import_react.useState)(null);
const [hoveredDay, setHoveredDay] = (0, import_react.useState)(null); const [hoveredDay, setHoveredDay] = (0, import_react.useState)(null);
const [tooltipPos, setTooltipPos] = (0, import_react.useState)(null); const [tooltipPos, setTooltipPos] = (0, import_react.useState)(null);
const fetchStats = () => { const fetchStats = () => {
@ -240,6 +228,7 @@ function HeatmapView() {
if (!data || !activeView) return null; if (!data || !activeView) return null;
const { summary } = activeView; const { summary } = activeView;
const cacheHitPercent = summary.totalTokens > 0 ? Math.round(summary.totalCacheReadTokens / summary.totalTokens * 100) : 0; const cacheHitPercent = summary.totalTokens > 0 ? Math.round(summary.totalCacheReadTokens / summary.totalTokens * 100) : 0;
const inspectedDayStats = selectedDate ? activeView.days[selectedDate] : null;
return /* @__PURE__ */ import_react.default.createElement( return /* @__PURE__ */ import_react.default.createElement(
"div", "div",
{ {
@ -309,7 +298,10 @@ function HeatmapView() {
"select", "select",
{ {
value: selectedSessionId, value: selectedSessionId,
onChange: (e) => setSelectedSessionId(e.target.value), onChange: (e) => {
setSelectedSessionId(e.target.value);
setSelectedDate(null);
},
style: { style: {
background: "var(--dsw-alias-bg-layer-2, #2c2c2c)", background: "var(--dsw-alias-bg-layer-2, #2c2c2c)",
border: "1px solid var(--dsw-alias-border-l2, #494949)", border: "1px solid var(--dsw-alias-border-l2, #494949)",
@ -426,7 +418,6 @@ function HeatmapView() {
borderRadius: 12, borderRadius: 12,
padding: "20px 22px", padding: "20px 22px",
position: "relative", position: "relative",
overflowX: "auto",
boxShadow: "0 4px 16px rgba(0, 0, 0, 0.2)" boxShadow: "0 4px 16px rgba(0, 0, 0, 0.2)"
} }
}, },
@ -445,103 +436,185 @@ function HeatmapView() {
/* @__PURE__ */ import_react.default.createElement("span", null, "Contribution Calendar"), /* @__PURE__ */ import_react.default.createElement("span", null, "Contribution Calendar"),
summary.peakDay && /* @__PURE__ */ import_react.default.createElement("span", { style: { fontSize: 12, fontWeight: 400, color: "var(--dsw-alias-label-secondary)" } }, "Peak day: ", /* @__PURE__ */ import_react.default.createElement("strong", { style: { color: "var(--dsw-alias-label-primary)" } }, summary.peakDay.date), " (", formatNumber(summary.peakDay.tokens), " tokens)") summary.peakDay && /* @__PURE__ */ import_react.default.createElement("span", { style: { fontSize: 12, fontWeight: 400, color: "var(--dsw-alias-label-secondary)" } }, "Peak day: ", /* @__PURE__ */ import_react.default.createElement("strong", { style: { color: "var(--dsw-alias-label-primary)" } }, summary.peakDay.date), " (", formatNumber(summary.peakDay.tokens), " tokens)")
), ),
calendarGrid && /* @__PURE__ */ import_react.default.createElement("div", { style: { display: "inline-block", minWidth: 780 } }, /* @__PURE__ */ import_react.default.createElement("div", { style: { display: "flex", marginLeft: 32, marginBottom: 4, height: 16 } }, monthHeaders.map((m, i) => /* @__PURE__ */ import_react.default.createElement( calendarGrid && /* @__PURE__ */ import_react.default.createElement("div", { style: { width: "100%", overflow: "hidden" } }, /* @__PURE__ */ import_react.default.createElement(
"div", "svg",
{ {
key: i, viewBox: "0 0 740 112",
style: { style: {
position: "relative", width: "100%",
left: m.col * 14, height: "auto",
width: 0, display: "block",
whiteSpace: "nowrap", overflow: "visible"
fontSize: 10,
color: "var(--dsw-alias-label-tertiary, #a0a0a0)"
} }
}, },
m.label monthHeaders.map((m, i) => /* @__PURE__ */ import_react.default.createElement(
))), /* @__PURE__ */ import_react.default.createElement("div", { style: { display: "flex", gap: 6 } }, /* @__PURE__ */ import_react.default.createElement( "text",
"div",
{
style: {
display: "flex",
flexDirection: "column",
gap: 3,
width: 26,
fontSize: 9,
color: "var(--dsw-alias-label-tertiary, #a0a0a0)",
textAlign: "right",
paddingTop: 1
}
},
DAY_LABELS.map((lbl, idx) => /* @__PURE__ */ import_react.default.createElement("div", { key: idx, style: { height: 11, lineHeight: "11px" } }, lbl))
), /* @__PURE__ */ import_react.default.createElement("div", { style: { display: "flex", gap: 3 } }, calendarGrid.map((week, colIdx) => /* @__PURE__ */ import_react.default.createElement("div", { key: colIdx, style: { display: "flex", flexDirection: "column", gap: 3 } }, week.map((day, rowIdx) => {
if (!day) {
return /* @__PURE__ */ import_react.default.createElement("div", { key: rowIdx, style: { width: 11, height: 11 } });
}
const lvl = day.stats.level || 0;
const bg = DEEPSEEK_LEVELS[lvl];
const isHovered = hoveredDay?.date === day.date;
const currentShadow = isHovered ? lvl >= 3 ? "0 0 12px rgba(79, 133, 255, 0.95), 0 0 2px #ffffff" : "0 0 4px rgba(51, 109, 250, 0.4)" : TILE_SHADOWS[lvl];
return /* @__PURE__ */ import_react.default.createElement(
"div",
{ {
key: rowIdx, key: i,
onMouseEnter: (e) => { x: 30 + m.col * 13.2,
setHoveredDay({ date: day.date, stats: day.stats }); y: 10,
const rect = e.currentTarget.getBoundingClientRect(); fontSize: 10,
setTooltipPos({ x: rect.left + rect.width / 2, y: rect.top - 8 }); fill: "var(--dsw-alias-label-tertiary, #888888)",
}, fontFamily: "inherit"
onMouseLeave: () => { },
setHoveredDay(null); m.label
setTooltipPos(null); )),
}, /* @__PURE__ */ import_react.default.createElement("text", { x: 2, y: 38, fontSize: 9, fill: "var(--dsw-alias-label-tertiary, #888888)", fontFamily: "inherit" }, "Mon"),
style: { /* @__PURE__ */ import_react.default.createElement("text", { x: 2, y: 64, fontSize: 9, fill: "var(--dsw-alias-label-tertiary, #888888)", fontFamily: "inherit" }, "Wed"),
width: 11, /* @__PURE__ */ import_react.default.createElement("text", { x: 2, y: 90, fontSize: 9, fill: "var(--dsw-alias-label-tertiary, #888888)", fontFamily: "inherit" }, "Fri"),
height: 11, calendarGrid.map((week, colIdx) => /* @__PURE__ */ import_react.default.createElement("g", { key: colIdx, transform: `translate(${28 + colIdx * 13.2}, 16)` }, week.map((day, rowIdx) => {
borderRadius: 2, if (!day) return null;
backgroundColor: bg, const lvl = day.stats.level || 0;
boxShadow: currentShadow, const bg = DEEPSEEK_LEVELS[lvl];
border: lvl === 0 ? "1px solid rgba(255, 255, 255, 0.05)" : "1px solid transparent", const isSelected = selectedDate === day.date;
cursor: "pointer", const isHovered = hoveredDay?.date === day.date;
transform: isHovered ? "scale(1.15)" : "scale(1)", const strokeColor = isSelected ? "#ffffff" : isHovered ? "#5686fe" : lvl === 0 ? "rgba(255, 255, 255, 0.05)" : "transparent";
zIndex: isHovered ? 5 : 1, const strokeWidth = isSelected ? 1.5 : isHovered ? 1.2 : 1;
transition: "all 0.12s ease", return /* @__PURE__ */ import_react.default.createElement(
position: "relative" "rect",
{
key: rowIdx,
x: 0,
y: rowIdx * 13,
width: 10.5,
height: 10.5,
rx: 2,
ry: 2,
fill: bg,
stroke: strokeColor,
strokeWidth,
style: {
cursor: "pointer",
transition: "fill 0.12s ease, stroke 0.12s ease",
filter: isSelected ? "drop-shadow(0 0 6px rgba(86, 134, 254, 0.9))" : isHovered ? "drop-shadow(0 0 4px rgba(86, 134, 254, 0.7))" : lvl === 4 ? "drop-shadow(0 0 3px rgba(79, 133, 255, 0.5))" : "none"
},
onClick: () => {
setSelectedDate(isSelected ? null : day.date);
},
onMouseEnter: (e) => {
setHoveredDay({ date: day.date, stats: day.stats });
const rect = e.currentTarget.getBoundingClientRect();
setTooltipPos({ x: rect.left + rect.width / 2, y: rect.top - 8 });
},
onMouseLeave: () => {
setHoveredDay(null);
setTooltipPos(null);
}
} }
} );
); })))
}))))), /* @__PURE__ */ import_react.default.createElement( ), /* @__PURE__ */ import_react.default.createElement(
"div", "div",
{ {
style: { style: {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "flex-end", justifyContent: "space-between",
gap: 6,
marginTop: 14, marginTop: 14,
fontSize: 11, fontSize: 11,
color: "var(--dsw-alias-label-tertiary, #a0a0a0)" color: "var(--dsw-alias-label-tertiary, #a0a0a0)"
} }
}, },
/* @__PURE__ */ import_react.default.createElement("span", null, "Less"), /* @__PURE__ */ import_react.default.createElement("span", { style: { fontSize: 11 } }, "Tip: Click any day to inspect sessions and token breakdown"),
DEEPSEEK_LEVELS.map((c, i) => /* @__PURE__ */ import_react.default.createElement( /* @__PURE__ */ import_react.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 6 } }, /* @__PURE__ */ import_react.default.createElement("span", null, "Less"), DEEPSEEK_LEVELS.map((c, i) => /* @__PURE__ */ import_react.default.createElement(
"div", "div",
{ {
key: i, key: i,
style: { style: {
width: 11, width: 10.5,
height: 11, height: 10.5,
borderRadius: 2, borderRadius: 2,
backgroundColor: c, backgroundColor: c,
boxShadow: TILE_SHADOWS[i], border: i === 0 ? "1px solid rgba(255, 255, 255, 0.05)" : "none",
border: i === 0 ? "1px solid rgba(255, 255, 255, 0.05)" : "none" filter: i === 4 ? "drop-shadow(0 0 3px rgba(79, 133, 255, 0.5))" : "none"
} }
} }
)), )), /* @__PURE__ */ import_react.default.createElement("span", null, "More"))
/* @__PURE__ */ import_react.default.createElement("span", null, "More")
)) ))
), ),
hoveredDay && tooltipPos && /* @__PURE__ */ import_react.default.createElement( selectedDate && /* @__PURE__ */ import_react.default.createElement(
"div",
{
style: {
marginTop: 18,
background: "var(--dsw-alias-bg-layer-2, #2c2c2c)",
border: "1px solid var(--dsw-alias-border-l2, #494949)",
borderRadius: 12,
padding: "18px 20px",
boxShadow: "0 6px 20px rgba(0, 0, 0, 0.25)",
animation: "fadeIn 0.15s ease"
}
},
/* @__PURE__ */ import_react.default.createElement(
"div",
{
style: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
borderBottom: "1px solid var(--dsw-alias-border-l1, #3a3a3a)",
paddingBottom: 12,
marginBottom: 14
}
},
/* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { style: { fontSize: 16, fontWeight: 700, color: "var(--dsw-alias-label-primary, #ffffff)" } }, (/* @__PURE__ */ new Date(selectedDate + "T00:00:00")).toLocaleDateString(void 0, {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
})), /* @__PURE__ */ import_react.default.createElement("div", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary, #b9b9b9)", marginTop: 2 } }, inspectedDayStats && inspectedDayStats.totalTokens > 0 ? /* @__PURE__ */ import_react.default.createElement("span", null, /* @__PURE__ */ import_react.default.createElement("strong", { style: { color: "#4f85ff" } }, formatExact(inspectedDayStats.totalTokens)), " total tokens across", " ", /* @__PURE__ */ import_react.default.createElement("strong", null, inspectedDayStats.turns), " turns") : "No activity recorded")),
/* @__PURE__ */ import_react.default.createElement(
"button",
{
onClick: () => setSelectedDate(null),
style: {
background: "transparent",
border: "none",
color: "var(--dsw-alias-label-tertiary)",
cursor: "pointer",
fontSize: 16,
padding: "4px 8px",
borderRadius: 4
},
title: "Close day view"
},
"\u2715"
)
),
inspectedDayStats && inspectedDayStats.totalTokens > 0 && /* @__PURE__ */ import_react.default.createElement(
"div",
{
style: {
display: "flex",
gap: 12,
flexWrap: "wrap",
marginBottom: 16,
fontSize: 12
}
},
/* @__PURE__ */ import_react.default.createElement("div", { style: { padding: "6px 12px", background: "var(--dsw-alias-bg-layer-1, #1e1e1e)", borderRadius: 6, border: "1px solid var(--dsw-alias-border-l1)" } }, /* @__PURE__ */ import_react.default.createElement("span", { style: { color: "var(--dsw-alias-label-tertiary)" } }, "Billed Input: "), /* @__PURE__ */ import_react.default.createElement("strong", null, formatNumber(inspectedDayStats.inputTokens))),
/* @__PURE__ */ import_react.default.createElement("div", { style: { padding: "6px 12px", background: "var(--dsw-alias-bg-layer-1, #1e1e1e)", borderRadius: 6, border: "1px solid var(--dsw-alias-border-l1)" } }, /* @__PURE__ */ import_react.default.createElement("span", { style: { color: "var(--dsw-alias-label-tertiary)" } }, "Output Generated: "), /* @__PURE__ */ import_react.default.createElement("strong", null, formatNumber(inspectedDayStats.outputTokens))),
/* @__PURE__ */ import_react.default.createElement("div", { style: { padding: "6px 12px", background: "var(--dsw-alias-bg-layer-1, #1e1e1e)", borderRadius: 6, border: "1px solid var(--dsw-alias-border-l1)" } }, /* @__PURE__ */ import_react.default.createElement("span", { style: { color: "var(--dsw-alias-label-tertiary)" } }, "Cache Reads: "), /* @__PURE__ */ import_react.default.createElement("strong", { style: { color: "#38bdf8" } }, formatNumber(inspectedDayStats.cacheReadTokens)), " (", Math.round(inspectedDayStats.cacheReadTokens / inspectedDayStats.totalTokens * 100), "%)")
),
/* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { style: { fontSize: 13, fontWeight: 600, color: "var(--dsw-alias-label-primary)", marginBottom: 10 } }, "Sessions Active on this Day (", inspectedDayStats?.sessions?.length || 0, ")"), inspectedDayStats?.sessions && inspectedDayStats.sessions.length > 0 ? /* @__PURE__ */ import_react.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8, maxHeight: 320, overflowY: "auto" } }, inspectedDayStats.sessions.map((sess, idx) => /* @__PURE__ */ import_react.default.createElement(
"div",
{
key: idx,
style: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "10px 14px",
background: "var(--dsw-alias-bg-layer-1, #1e1e1e)",
border: "1px solid var(--dsw-alias-border-l1, #3a3a3a)",
borderRadius: 8
}
},
/* @__PURE__ */ import_react.default.createElement("div", { style: { minWidth: 0, flex: 1, paddingRight: 16 } }, /* @__PURE__ */ import_react.default.createElement("div", { style: { fontWeight: 600, fontSize: 13, color: "var(--dsw-alias-label-primary, #ffffff)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, sess.sessionTitle), /* @__PURE__ */ import_react.default.createElement("div", { style: { fontSize: 11, color: "var(--dsw-alias-label-tertiary, #a0a0a0)", marginTop: 2 } }, "Started ", new Date(sess.createdAt).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }), " \xB7 ID: ", sess.sessionId.slice(0, 10))),
/* @__PURE__ */ import_react.default.createElement("div", { style: { textAlign: "right", flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("div", { style: { fontWeight: 700, fontSize: 13, color: "#4f85ff" } }, formatNumber(sess.totalTokens), " tokens"), /* @__PURE__ */ import_react.default.createElement("div", { style: { fontSize: 11, color: "var(--dsw-alias-label-secondary)", marginTop: 2 } }, sess.turns, " turns \xB7 ", formatNumber(sess.inputTokens + sess.outputTokens), " billed"))
))) : /* @__PURE__ */ import_react.default.createElement("div", { style: { padding: "16px", textAlign: "center", color: "var(--dsw-alias-label-tertiary)", fontSize: 12, background: "var(--dsw-alias-bg-layer-1)", borderRadius: 8 } }, "No session records found for this date."))
),
hoveredDay && tooltipPos && !selectedDate && /* @__PURE__ */ import_react.default.createElement(
"div", "div",
{ {
style: { style: {
@ -567,7 +640,7 @@ function HeatmapView() {
month: "short", month: "short",
day: "numeric" day: "numeric"
})), })),
hoveredDay.stats.totalTokens === 0 ? /* @__PURE__ */ import_react.default.createElement("div", { style: { color: "var(--dsw-alias-label-tertiary)" } }, "No activity recorded") : /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { style: { color: "#4f85ff", fontWeight: 600 } }, formatExact(hoveredDay.stats.totalTokens), " tokens"), /* @__PURE__ */ import_react.default.createElement("div", { style: { fontSize: 11, color: "var(--dsw-alias-label-secondary)", marginTop: 2 } }, hoveredDay.stats.turns, " requests / steps"), /* @__PURE__ */ import_react.default.createElement("div", { style: { fontSize: 10, color: "var(--dsw-alias-label-tertiary)", marginTop: 4 } }, "Billed: ", formatNumber(hoveredDay.stats.inputTokens + hoveredDay.stats.outputTokens), " \xB7 Cache: ", formatNumber(hoveredDay.stats.cacheReadTokens))) hoveredDay.stats.totalTokens === 0 ? /* @__PURE__ */ import_react.default.createElement("div", { style: { color: "var(--dsw-alias-label-tertiary)" } }, "No activity recorded") : /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { style: { color: "#4f85ff", fontWeight: 600 } }, formatExact(hoveredDay.stats.totalTokens), " tokens"), /* @__PURE__ */ import_react.default.createElement("div", { style: { fontSize: 11, color: "var(--dsw-alias-label-secondary)", marginTop: 2 } }, hoveredDay.stats.turns, " requests / steps"), /* @__PURE__ */ import_react.default.createElement("div", { style: { fontSize: 10, color: "var(--dsw-alias-label-tertiary)", marginTop: 4 } }, "Click to inspect sessions on this day"))
) )
); );
} }

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,16 @@
import React, { useEffect, useState, useMemo } from "react"; import React, { useEffect, useState, useMemo } from "react";
export interface DaySessionDetail {
sessionId: string;
sessionTitle: string;
createdAt: number;
totalTokens: number;
inputTokens: number;
outputTokens: number;
cacheReadTokens: number;
turns: number;
}
export interface DayStats { export interface DayStats {
totalTokens: number; totalTokens: number;
inputTokens: number; inputTokens: number;
@ -8,6 +19,7 @@ export interface DayStats {
cacheWriteTokens: number; cacheWriteTokens: number;
turns: number; turns: number;
level?: number; level?: number;
sessions?: DaySessionDetail[];
} }
export interface SessionSummary { export interface SessionSummary {
@ -55,7 +67,7 @@ function formatExact(num: number): string {
} }
const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const DAY_LABELS = ["", "Mon", "", "Wed", "", "Fri", ""]; const DAY_LABELS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
// Simple monochromatic gradient: Black -> Vibrant DeepSeek Blue // Simple monochromatic gradient: Black -> Vibrant DeepSeek Blue
const DEEPSEEK_LEVELS = [ const DEEPSEEK_LEVELS = [
@ -66,20 +78,12 @@ const DEEPSEEK_LEVELS = [
"#4f85ff", // Level 4: Bright electric DeepSeek blue "#4f85ff", // Level 4: Bright electric DeepSeek blue
]; ];
// Glow effect strictly for the bright blue contribution tiles
const TILE_SHADOWS = [
"none", // Level 0: Black / flat
"none", // Level 1: Dark deep blue / flat
"none", // Level 2: Mid blue / flat
"0 0 4px rgba(51, 109, 250, 0.4)", // Level 3: Faint brand blue edge
"0 0 10px rgba(79, 133, 255, 0.85), 0 0 2px rgba(255, 255, 255, 0.5)", // Level 4: Bright electric blue glow
];
export function HeatmapView() { export function HeatmapView() {
const [data, setData] = useState<HeatmapResponse | null>(null); const [data, setData] = useState<HeatmapResponse | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [selectedSessionId, setSelectedSessionId] = useState<string>("all"); const [selectedSessionId, setSelectedSessionId] = useState<string>("all");
const [selectedDate, setSelectedDate] = useState<string | null>(null);
const [hoveredDay, setHoveredDay] = useState<{ date: string; stats: DayStats } | null>(null); const [hoveredDay, setHoveredDay] = useState<{ date: string; stats: DayStats } | null>(null);
const [tooltipPos, setTooltipPos] = useState<{ x: number; y: number } | null>(null); const [tooltipPos, setTooltipPos] = useState<{ x: number; y: number } | null>(null);
@ -125,7 +129,6 @@ export function HeatmapView() {
}; };
} }
// Recalculate summary for this specific session
let totalTokens = session.totalTokens; let totalTokens = session.totalTokens;
let totalInputTokens = session.inputTokens; let totalInputTokens = session.inputTokens;
let totalOutputTokens = session.outputTokens; let totalOutputTokens = session.outputTokens;
@ -141,7 +144,6 @@ export function HeatmapView() {
} }
} }
// Re-level for this session
const positiveValues = Object.values(session.days) const positiveValues = Object.values(session.days)
.map((d) => d.totalTokens) .map((d) => d.totalTokens)
.filter((t) => t > 0) .filter((t) => t > 0)
@ -288,6 +290,8 @@ export function HeatmapView() {
? Math.round((summary.totalCacheReadTokens / summary.totalTokens) * 100) ? Math.round((summary.totalCacheReadTokens / summary.totalTokens) * 100)
: 0; : 0;
const inspectedDayStats = selectedDate ? activeView.days[selectedDate] : null;
return ( return (
<div <div
style={{ style={{
@ -356,7 +360,10 @@ export function HeatmapView() {
<span style={{ fontSize: 12, color: "var(--dsw-alias-label-tertiary)" }}>Session:</span> <span style={{ fontSize: 12, color: "var(--dsw-alias-label-tertiary)" }}>Session:</span>
<select <select
value={selectedSessionId} value={selectedSessionId}
onChange={(e) => setSelectedSessionId(e.target.value)} onChange={(e) => {
setSelectedSessionId(e.target.value);
setSelectedDate(null);
}}
style={{ style={{
background: "var(--dsw-alias-bg-layer-2, #2c2c2c)", background: "var(--dsw-alias-bg-layer-2, #2c2c2c)",
border: "1px solid var(--dsw-alias-border-l2, #494949)", border: "1px solid var(--dsw-alias-border-l2, #494949)",
@ -494,7 +501,7 @@ export function HeatmapView() {
</div> </div>
</div> </div>
{/* Heatmap Card */} {/* Heatmap Card (Auto-resizes responsive SVG panel, GitHub style) */}
<div <div
style={{ style={{
background: "var(--dsw-alias-bg-layer-2, #2c2c2c)", background: "var(--dsw-alias-bg-layer-2, #2c2c2c)",
@ -502,7 +509,6 @@ export function HeatmapView() {
borderRadius: 12, borderRadius: 12,
padding: "20px 22px", padding: "20px 22px",
position: "relative", position: "relative",
overflowX: "auto",
boxShadow: "0 4px 16px rgba(0, 0, 0, 0.2)", boxShadow: "0 4px 16px rgba(0, 0, 0, 0.2)",
}} }}
> >
@ -524,135 +530,285 @@ export function HeatmapView() {
)} )}
</div> </div>
{/* SVG Heatmap */} {/* Responsive GitHub-Style Calendar SVG (scales with container width) */}
{calendarGrid && ( {calendarGrid && (
<div style={{ display: "inline-block", minWidth: 780 }}> <div style={{ width: "100%", overflow: "hidden" }}>
{/* Month labels */} <svg
<div style={{ display: "flex", marginLeft: 32, marginBottom: 4, height: 16 }}> viewBox="0 0 740 112"
style={{
width: "100%",
height: "auto",
display: "block",
overflow: "visible",
}}
>
{/* Month labels */}
{monthHeaders.map((m, i) => ( {monthHeaders.map((m, i) => (
<div <text
key={i} key={i}
style={{ x={30 + m.col * 13.2}
position: "relative", y={10}
left: m.col * 14, fontSize={10}
width: 0, fill="var(--dsw-alias-label-tertiary, #888888)"
whiteSpace: "nowrap", fontFamily="inherit"
fontSize: 10,
color: "var(--dsw-alias-label-tertiary, #a0a0a0)",
}}
> >
{m.label} {m.label}
</div> </text>
))} ))}
</div>
{/* Grid with day labels */}
<div style={{ display: "flex", gap: 6 }}>
{/* Day of week labels */} {/* Day of week labels */}
<div <text x={2} y={38} fontSize={9} fill="var(--dsw-alias-label-tertiary, #888888)" fontFamily="inherit">
style={{ Mon
display: "flex", </text>
flexDirection: "column", <text x={2} y={64} fontSize={9} fill="var(--dsw-alias-label-tertiary, #888888)" fontFamily="inherit">
gap: 3, Wed
width: 26, </text>
fontSize: 9, <text x={2} y={90} fontSize={9} fill="var(--dsw-alias-label-tertiary, #888888)" fontFamily="inherit">
color: "var(--dsw-alias-label-tertiary, #a0a0a0)", Fri
textAlign: "right", </text>
paddingTop: 1,
}}
>
{DAY_LABELS.map((lbl, idx) => (
<div key={idx} style={{ height: 11, lineHeight: "11px" }}>
{lbl}
</div>
))}
</div>
{/* Columns of weeks */} {/* Day Tiles */}
<div style={{ display: "flex", gap: 3 }}> {calendarGrid.map((week, colIdx) => (
{calendarGrid.map((week, colIdx) => ( <g key={colIdx} transform={`translate(${28 + colIdx * 13.2}, 16)`}>
<div key={colIdx} style={{ display: "flex", flexDirection: "column", gap: 3 }}> {week.map((day, rowIdx) => {
{week.map((day, rowIdx) => { if (!day) return null;
if (!day) {
return <div key={rowIdx} style={{ width: 11, height: 11 }} />;
}
const lvl = day.stats.level || 0;
const bg = DEEPSEEK_LEVELS[lvl];
const isHovered = hoveredDay?.date === day.date;
const currentShadow = isHovered
? (lvl >= 3 ? "0 0 12px rgba(79, 133, 255, 0.95), 0 0 2px #ffffff" : "0 0 4px rgba(51, 109, 250, 0.4)")
: TILE_SHADOWS[lvl];
return ( const lvl = day.stats.level || 0;
<div const bg = DEEPSEEK_LEVELS[lvl];
key={rowIdx} const isSelected = selectedDate === day.date;
onMouseEnter={(e) => { const isHovered = hoveredDay?.date === day.date;
setHoveredDay({ date: day.date, stats: day.stats });
const rect = e.currentTarget.getBoundingClientRect();
setTooltipPos({ x: rect.left + rect.width / 2, y: rect.top - 8 });
}}
onMouseLeave={() => {
setHoveredDay(null);
setTooltipPos(null);
}}
style={{
width: 11,
height: 11,
borderRadius: 2,
backgroundColor: bg,
boxShadow: currentShadow,
border:
lvl === 0
? "1px solid rgba(255, 255, 255, 0.05)"
: "1px solid transparent",
cursor: "pointer",
transform: isHovered ? "scale(1.15)" : "scale(1)",
zIndex: isHovered ? 5 : 1,
transition: "all 0.12s ease",
position: "relative",
}}
/>
);
})}
</div>
))}
</div>
</div>
{/* Legend & Footnote */} // GitHub-style glow & outline
const strokeColor = isSelected
? "#ffffff"
: isHovered
? "#5686fe"
: lvl === 0
? "rgba(255, 255, 255, 0.05)"
: "transparent";
const strokeWidth = isSelected ? 1.5 : isHovered ? 1.2 : 1;
return (
<rect
key={rowIdx}
x={0}
y={rowIdx * 13}
width={10.5}
height={10.5}
rx={2}
ry={2}
fill={bg}
stroke={strokeColor}
strokeWidth={strokeWidth}
style={{
cursor: "pointer",
transition: "fill 0.12s ease, stroke 0.12s ease",
filter: isSelected
? "drop-shadow(0 0 6px rgba(86, 134, 254, 0.9))"
: isHovered
? "drop-shadow(0 0 4px rgba(86, 134, 254, 0.7))"
: lvl === 4
? "drop-shadow(0 0 3px rgba(79, 133, 255, 0.5))"
: "none",
}}
onClick={() => {
setSelectedDate(isSelected ? null : day.date);
}}
onMouseEnter={(e) => {
setHoveredDay({ date: day.date, stats: day.stats });
const rect = e.currentTarget.getBoundingClientRect();
setTooltipPos({ x: rect.left + rect.width / 2, y: rect.top - 8 });
}}
onMouseLeave={() => {
setHoveredDay(null);
setTooltipPos(null);
}}
/>
);
})}
</g>
))}
</svg>
{/* Bottom Legend */}
<div <div
style={{ style={{
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "flex-end", justifyContent: "space-between",
gap: 6,
marginTop: 14, marginTop: 14,
fontSize: 11, fontSize: 11,
color: "var(--dsw-alias-label-tertiary, #a0a0a0)", color: "var(--dsw-alias-label-tertiary, #a0a0a0)",
}} }}
> >
<span>Less</span> <span style={{ fontSize: 11 }}>
{DEEPSEEK_LEVELS.map((c, i) => ( Tip: Click any day to inspect sessions and token breakdown
<div </span>
key={i}
style={{ <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
width: 11, <span>Less</span>
height: 11, {DEEPSEEK_LEVELS.map((c, i) => (
borderRadius: 2, <div
backgroundColor: c, key={i}
boxShadow: TILE_SHADOWS[i], style={{
border: i === 0 ? "1px solid rgba(255, 255, 255, 0.05)" : "none", width: 10.5,
}} height: 10.5,
/> borderRadius: 2,
))} backgroundColor: c,
<span>More</span> border: i === 0 ? "1px solid rgba(255, 255, 255, 0.05)" : "none",
filter: i === 4 ? "drop-shadow(0 0 3px rgba(79, 133, 255, 0.5))" : "none",
}}
/>
))}
<span>More</span>
</div>
</div> </div>
</div> </div>
)} )}
</div> </div>
{/* Day Inspection Detail Drawer (Opens when any day is clicked) */}
{selectedDate && (
<div
style={{
marginTop: 18,
background: "var(--dsw-alias-bg-layer-2, #2c2c2c)",
border: "1px solid var(--dsw-alias-border-l2, #494949)",
borderRadius: 12,
padding: "18px 20px",
boxShadow: "0 6px 20px rgba(0, 0, 0, 0.25)",
animation: "fadeIn 0.15s ease",
}}
>
{/* Header of the Day Detail */}
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
borderBottom: "1px solid var(--dsw-alias-border-l1, #3a3a3a)",
paddingBottom: 12,
marginBottom: 14,
}}
>
<div>
<div style={{ fontSize: 16, fontWeight: 700, color: "var(--dsw-alias-label-primary, #ffffff)" }}>
{new Date(selectedDate + "T00:00:00").toLocaleDateString(undefined, {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
})}
</div>
<div style={{ fontSize: 12, color: "var(--dsw-alias-label-secondary, #b9b9b9)", marginTop: 2 }}>
{inspectedDayStats && inspectedDayStats.totalTokens > 0 ? (
<span>
<strong style={{ color: "#4f85ff" }}>{formatExact(inspectedDayStats.totalTokens)}</strong> total tokens across{" "}
<strong>{inspectedDayStats.turns}</strong> turns
</span>
) : (
"No activity recorded"
)}
</div>
</div>
<button
onClick={() => setSelectedDate(null)}
style={{
background: "transparent",
border: "none",
color: "var(--dsw-alias-label-tertiary)",
cursor: "pointer",
fontSize: 16,
padding: "4px 8px",
borderRadius: 4,
}}
title="Close day view"
>
✕
</button>
</div>
{/* Breakdown Pills for the day */}
{inspectedDayStats && inspectedDayStats.totalTokens > 0 && (
<div
style={{
display: "flex",
gap: 12,
flexWrap: "wrap",
marginBottom: 16,
fontSize: 12,
}}
>
<div style={{ padding: "6px 12px", background: "var(--dsw-alias-bg-layer-1, #1e1e1e)", borderRadius: 6, border: "1px solid var(--dsw-alias-border-l1)" }}>
<span style={{ color: "var(--dsw-alias-label-tertiary)" }}>Billed Input: </span>
<strong>{formatNumber(inspectedDayStats.inputTokens)}</strong>
</div>
<div style={{ padding: "6px 12px", background: "var(--dsw-alias-bg-layer-1, #1e1e1e)", borderRadius: 6, border: "1px solid var(--dsw-alias-border-l1)" }}>
<span style={{ color: "var(--dsw-alias-label-tertiary)" }}>Output Generated: </span>
<strong>{formatNumber(inspectedDayStats.outputTokens)}</strong>
</div>
<div style={{ padding: "6px 12px", background: "var(--dsw-alias-bg-layer-1, #1e1e1e)", borderRadius: 6, border: "1px solid var(--dsw-alias-border-l1)" }}>
<span style={{ color: "var(--dsw-alias-label-tertiary)" }}>Cache Reads: </span>
<strong style={{ color: "#38bdf8" }}>{formatNumber(inspectedDayStats.cacheReadTokens)}</strong> (
{Math.round((inspectedDayStats.cacheReadTokens / inspectedDayStats.totalTokens) * 100)}%)
</div>
</div>
)}
{/* Sessions List for that Day */}
<div>
<div style={{ fontSize: 13, fontWeight: 600, color: "var(--dsw-alias-label-primary)", marginBottom: 10 }}>
Sessions Active on this Day ({inspectedDayStats?.sessions?.length || 0})
</div>
{inspectedDayStats?.sessions && inspectedDayStats.sessions.length > 0 ? (
<div style={{ display: "flex", flexDirection: "column", gap: 8, maxHeight: 320, overflowY: "auto" }}>
{inspectedDayStats.sessions.map((sess, idx) => (
<div
key={idx}
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "10px 14px",
background: "var(--dsw-alias-bg-layer-1, #1e1e1e)",
border: "1px solid var(--dsw-alias-border-l1, #3a3a3a)",
borderRadius: 8,
}}
>
<div style={{ minWidth: 0, flex: 1, paddingRight: 16 }}>
<div style={{ fontWeight: 600, fontSize: 13, color: "var(--dsw-alias-label-primary, #ffffff)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
{sess.sessionTitle}
</div>
<div style={{ fontSize: 11, color: "var(--dsw-alias-label-tertiary, #a0a0a0)", marginTop: 2 }}>
Started {new Date(sess.createdAt).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })} · ID: {sess.sessionId.slice(0, 10)}
</div>
</div>
<div style={{ textAlign: "right", flexShrink: 0 }}>
<div style={{ fontWeight: 700, fontSize: 13, color: "#4f85ff" }}>
{formatNumber(sess.totalTokens)} tokens
</div>
<div style={{ fontSize: 11, color: "var(--dsw-alias-label-secondary)", marginTop: 2 }}>
{sess.turns} turns · {formatNumber(sess.inputTokens + sess.outputTokens)} billed
</div>
</div>
</div>
))}
</div>
) : (
<div style={{ padding: "16px", textAlign: "center", color: "var(--dsw-alias-label-tertiary)", fontSize: 12, background: "var(--dsw-alias-bg-layer-1)", borderRadius: 8 }}>
No session records found for this date.
</div>
)}
</div>
</div>
)}
{/* Floating Hover Tooltip */} {/* Floating Hover Tooltip */}
{hoveredDay && tooltipPos && ( {hoveredDay && tooltipPos && !selectedDate && (
<div <div
style={{ style={{
position: "fixed", position: "fixed",
@ -690,7 +846,7 @@ export function HeatmapView() {
{hoveredDay.stats.turns} requests / steps {hoveredDay.stats.turns} requests / steps
</div> </div>
<div style={{ fontSize: 10, color: "var(--dsw-alias-label-tertiary)", marginTop: 4 }}> <div style={{ fontSize: 10, color: "var(--dsw-alias-label-tertiary)", marginTop: 4 }}>
Billed: {formatNumber(hoveredDay.stats.inputTokens + hoveredDay.stats.outputTokens)} · Cache: {formatNumber(hoveredDay.stats.cacheReadTokens)} Click to inspect sessions on this day
</div> </div>
</div> </div>
)} )}

View file

@ -3,6 +3,17 @@ import path from "node:path";
import os from "node:os"; import os from "node:os";
import { spawn } from "node:child_process"; import { spawn } from "node:child_process";
export interface DaySessionDetail {
sessionId: string;
sessionTitle: string;
createdAt: number;
totalTokens: number;
inputTokens: number;
outputTokens: number;
cacheReadTokens: number;
turns: number;
}
export interface DayStats { export interface DayStats {
totalTokens: number; totalTokens: number;
inputTokens: number; inputTokens: number;
@ -11,6 +22,7 @@ export interface DayStats {
cacheWriteTokens: number; cacheWriteTokens: number;
turns: number; turns: number;
level?: number; // 0..4 level?: number; // 0..4
sessions?: DaySessionDetail[];
} }
export interface SessionSummary { export interface SessionSummary {
@ -229,6 +241,7 @@ export async function aggregateTokens(customSessionsRoot?: string): Promise<Heat
cacheReadTokens: 0, cacheReadTokens: 0,
cacheWriteTokens: 0, cacheWriteTokens: 0,
turns: 0, turns: 0,
sessions: [],
}; };
} }
days[date].totalTokens += stats.totalTokens; days[date].totalTokens += stats.totalTokens;
@ -237,6 +250,24 @@ export async function aggregateTokens(customSessionsRoot?: string): Promise<Heat
days[date].cacheReadTokens += stats.cacheReadTokens; days[date].cacheReadTokens += stats.cacheReadTokens;
days[date].cacheWriteTokens += stats.cacheWriteTokens; days[date].cacheWriteTokens += stats.cacheWriteTokens;
days[date].turns += stats.turns; days[date].turns += stats.turns;
days[date].sessions!.push({
sessionId: session.id,
sessionTitle: session.title,
createdAt: session.createdAt,
totalTokens: stats.totalTokens,
inputTokens: stats.inputTokens,
outputTokens: stats.outputTokens,
cacheReadTokens: stats.cacheReadTokens,
turns: stats.turns,
});
}
}
// Sort sessions within each day by totalTokens descending
for (const day of Object.values(days)) {
if (day.sessions) {
day.sessions.sort((a, b) => b.totalTokens - a.totalTokens);
} }
} }