From ed9a243ec4e581eb9dbac5e79d75706cb1acdff1 Mon Sep 17 00:00:00 2001 From: castrojo Date: Tue, 8 Sep 2026 14:02:17 +0000 Subject: [PATCH] fix(analytics): retain Countme zeros and preserve missing values as gaps Project Bluefin family cards computed isTracked as count > 0, so a real reported zero (e.g. Dakota weekly value 0) was treated identically to missing data: the sparkline history was cleared to [] and the card fell back to its bootstrapping/provisioning placeholder text instead of showing the trend. Read counts through a shared readCount() helper that keeps a reported 0 as 0 and only returns null when the field is actually absent or non-finite, matching the gapSafe() convention already used by the comparative charts in this file. isTracked and per-week history now key off count !== null instead of count > 0, so zero values stay visible and only genuinely missing weeks render as sparkline gaps. Signed-off-by: castrojo --- .../analytics/CountmeAnalyticsCharts.tsx | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/components/analytics/CountmeAnalyticsCharts.tsx b/src/components/analytics/CountmeAnalyticsCharts.tsx index d7e489aa..69b9b185 100644 --- a/src/components/analytics/CountmeAnalyticsCharts.tsx +++ b/src/components/analytics/CountmeAnalyticsCharts.tsx @@ -110,6 +110,17 @@ const BLUEFIN_FAMILY_IMAGES: ProjectBluefinImageSpec[] = [ }, ]; +/** + * Reads a variant's count for a week. Missing/null/non-finite stays `null` + * (a gap); a real reported `0` is preserved as `0`, never coerced away. + */ +function readCount(week: CountmeWeek | undefined, key: string): number | null { + const raw = week?.[key]; + if (raw === undefined || raw === null) return null; + const num = Number(raw); + return Number.isFinite(num) ? num : null; +} + export default function CountmeAnalyticsCharts(): React.JSX.Element { const data = countmeHistoryData as unknown as CountmeDataset; const weeks = data?.weeks || []; @@ -120,12 +131,15 @@ export default function CountmeAnalyticsCharts(): React.JSX.Element { const [viewMode, setViewMode] = useState("all-ecosystem"); const latestWeek = weeks[weeks.length - 1] || ({} as CountmeWeek); - const latestBluefin = Number(latestWeek.bluefin) || 0; - const latestBluefinLts = Number(latestWeek["bluefin-lts"]) || 0; - const latestDakota = Number(latestWeek.dakota) || 0; - const latestUtah = Number(latestWeek.utah) || 0; + const latestBluefin = readCount(latestWeek, "bluefin"); + const latestBluefinLts = readCount(latestWeek, "bluefin-lts"); + const latestDakota = readCount(latestWeek, "dakota"); + const latestUtah = readCount(latestWeek, "utah"); const currentTotalBluefin = - latestBluefin + latestBluefinLts + latestDakota + latestUtah; + (latestBluefin ?? 0) + + (latestBluefinLts ?? 0) + + (latestDakota ?? 0) + + (latestUtah ?? 0); // Filtered weeks for Hero Bluefin chart const heroFilteredWeeks = useMemo(() => { @@ -421,13 +435,20 @@ export default function CountmeAnalyticsCharts(): React.JSX.Element { className={`${styles.heroSubBadge} ${styles.heroSubBadgeHighlight}`} > Flagship (projectbluefin/bluefin):{" "} - {latestBluefin.toLocaleString()} ( - {((latestBluefin / currentTotalBluefin) * 100).toFixed(1)}%) + {(latestBluefin ?? 0).toLocaleString()} ( + {(((latestBluefin ?? 0) / currentTotalBluefin) * 100).toFixed( + 1, + )} + %) LTS (projectbluefin/bluefin-lts):{" "} - {latestBluefinLts.toLocaleString()} ( - {((latestBluefinLts / currentTotalBluefin) * 100).toFixed(1)}%) + {(latestBluefinLts ?? 0).toLocaleString()} ( + {( + ((latestBluefinLts ?? 0) / currentTotalBluefin) * + 100 + ).toFixed(1)} + %) Dakota: Bootstrapping Utah: Provisioning @@ -521,9 +542,9 @@ export default function CountmeAnalyticsCharts(): React.JSX.Element { ? latestDakota : latestUtah; - const isTracked = count > 0; + const isTracked = count !== null; const history = isTracked - ? weeks.slice(-12).map((w) => (w[img.id] as number) ?? null) + ? weeks.slice(-12).map((w) => readCount(w, img.id)) : []; return ( @@ -548,13 +569,13 @@ export default function CountmeAnalyticsCharts(): React.JSX.Element {
- {isTracked + {count !== null ? count.toLocaleString() : img.status === "bootstrapping" ? "Initial" : "Pending"} - {isTracked && currentTotalBluefin > 0 && ( + {count !== null && currentTotalBluefin > 0 && ( {((count / currentTotalBluefin) * 100).toFixed(1)}% fleet @@ -606,7 +627,9 @@ export default function CountmeAnalyticsCharts(): React.JSX.Element { ? "accumulating countme data" : "provisioning countme" } - label={`${img.name} 12-week adoption trend: currently ${count.toLocaleString()}`} + label={`${img.name} 12-week adoption trend: currently ${ + count !== null ? count.toLocaleString() : "no data yet" + }`} />