Skip to content

Instantly share code, notes, and snippets.

@tarasyarema
Created January 19, 2026 19:22
Show Gist options
  • Select an option

  • Save tarasyarema/c14a215b64a9c14ecce804a7902d775b to your computer and use it in GitHub Desktop.

Select an option

Save tarasyarema/c14a215b64a9c14ecce804a7902d775b to your computer and use it in GitHub Desktop.
Github Org Metrics
import React, { useState, useMemo } from 'react';
import { ComposedChart, Bar, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
const data = {
"organization": "desplega-ai",
"period": { "months": 6, "since": "2025-07-19" },
"generatedAt": "2026-01-19T18:52:33.908Z",
"repositories": [
{
"name": "desplega.ai",
"fullName": "desplega-ai/desplega.ai",
"authors": [
...
{ "login": "vercel[bot]", "additions": 45, "deletions": 45, "commits": 1, "weeks": [{"week":"2025-12-07","additions":45,"deletions":45,"commits":1}] }
]
},
...
]
};
export default function GitHubViz() {
const [enabledContributors, setEnabledContributors] = useState(new Set());
const [enabledRepos, setEnabledRepos] = useState(new Set());
const [showContributorPanel, setShowContributorPanel] = useState(false);
const [showRepoPanel, setShowRepoPanel] = useState(false);
const [showTrendLine, setShowTrendLine] = useState(true);
// Extract all unique contributors and repos
const { allContributors, allRepos } = useMemo(() => {
const contributors = new Set();
const repos = new Set();
data.repositories.forEach(repo => {
repos.add(repo.name);
repo.authors.forEach(author => {
contributors.add(author.login);
});
});
return {
allContributors: Array.from(contributors).sort(),
allRepos: Array.from(repos).sort()
};
}, []);
// Initialize enabled sets on first render
useMemo(() => {
if (enabledContributors.size === 0) {
setEnabledContributors(new Set(allContributors));
}
if (enabledRepos.size === 0) {
setEnabledRepos(new Set(allRepos));
}
}, [allContributors, allRepos]);
// Process data for the chart
const chartData = useMemo(() => {
const weekMap = new Map();
data.repositories.forEach(repo => {
if (!enabledRepos.has(repo.name)) return;
repo.authors.forEach(author => {
if (!enabledContributors.has(author.login)) return;
author.weeks.forEach(week => {
const existing = weekMap.get(week.week) || { week: week.week, additions: 0, deletions: 0 };
existing.additions += week.additions;
existing.deletions += week.deletions;
weekMap.set(week.week, existing);
});
});
});
const sorted = Array.from(weekMap.values())
.sort((a, b) => a.week.localeCompare(b.week))
.map((d, index) => ({
...d,
index,
weekLabel: new Date(d.week).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }),
totalChanges: d.additions + d.deletions,
negDeletions: -d.deletions
}));
// Calculate 4-week rolling average for trend
const withTrend = sorted.map((d, i) => {
const windowSize = 4;
const start = Math.max(0, i - windowSize + 1);
const window = sorted.slice(start, i + 1);
const avgChanges = window.reduce((sum, w) => sum + w.totalChanges, 0) / window.length;
return { ...d, trendLine: Math.round(avgChanges) };
});
return withTrend;
}, [enabledContributors, enabledRepos]);
// Calculate monthly totals for comparison
const monthlyStats = useMemo(() => {
const months = {};
chartData.forEach(d => {
const month = d.week.substring(0, 7); // YYYY-MM
if (!months[month]) {
months[month] = { additions: 0, deletions: 0, total: 0 };
}
months[month].additions += d.additions;
months[month].deletions += d.deletions;
months[month].total += d.totalChanges;
});
return months;
}, [chartData]);
// Calculate growth multiplier
const growthStats = useMemo(() => {
const nov = monthlyStats['2025-11'] || { total: 1 };
const jan = monthlyStats['2026-01'] || { total: 0 };
const multiplier = nov.total > 0 ? (jan.total / nov.total) : 0;
return {
novTotal: nov.total,
janTotal: jan.total,
multiplier: multiplier.toFixed(1)
};
}, [monthlyStats]);
// Calculate totals
const totals = useMemo(() => {
return chartData.reduce((acc, d) => ({
additions: acc.additions + d.additions,
deletions: acc.deletions + d.deletions
}), { additions: 0, deletions: 0 });
}, [chartData]);
const toggleContributor = (contributor) => {
const newSet = new Set(enabledContributors);
if (newSet.has(contributor)) {
newSet.delete(contributor);
} else {
newSet.add(contributor);
}
setEnabledContributors(newSet);
};
const toggleRepo = (repo) => {
const newSet = new Set(enabledRepos);
if (newSet.has(repo)) {
newSet.delete(repo);
} else {
newSet.add(repo);
}
setEnabledRepos(newSet);
};
const selectAllContributors = () => setEnabledContributors(new Set(allContributors));
const clearAllContributors = () => setEnabledContributors(new Set());
const selectAllRepos = () => setEnabledRepos(new Set(allRepos));
const clearAllRepos = () => setEnabledRepos(new Set());
const formatNumber = (num) => {
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
return num.toString();
};
return (
<div className="min-h-screen bg-gray-950 text-gray-100 p-6">
<div className="max-w-7xl mx-auto">
<div className="mb-6">
<h1 className="text-2xl font-bold text-white mb-1">{data.organization} Contributions</h1>
<p className="text-gray-400 text-sm">Week over week code changes ยท {data.period.months} months since {data.period.since}</p>
</div>
{/* Summary Stats */}
<div className="grid grid-cols-2 md:grid-cols-5 gap-4 mb-6">
<div className="bg-gray-900 rounded-lg p-4 border border-gray-800">
<div className="text-green-400 text-2xl font-bold">+{formatNumber(totals.additions)}</div>
<div className="text-gray-500 text-sm">Additions</div>
</div>
<div className="bg-gray-900 rounded-lg p-4 border border-gray-800">
<div className="text-red-400 text-2xl font-bold">-{formatNumber(totals.deletions)}</div>
<div className="text-gray-500 text-sm">Deletions</div>
</div>
<div className="bg-gray-900 rounded-lg p-4 border border-gray-800">
<div className="text-blue-400 text-2xl font-bold">{enabledContributors.size}/{allContributors.length}</div>
<div className="text-gray-500 text-sm">Contributors</div>
</div>
<div className="bg-gray-900 rounded-lg p-4 border border-gray-800">
<div className="text-purple-400 text-2xl font-bold">{enabledRepos.size}/{allRepos.length}</div>
<div className="text-gray-500 text-sm">Repositories</div>
</div>
<div className="bg-gradient-to-r from-amber-900/50 to-orange-900/50 rounded-lg p-4 border border-amber-700/50">
<div className="text-amber-400 text-2xl font-bold">{growthStats.multiplier}x</div>
<div className="text-amber-200/70 text-sm">Jan vs Nov</div>
</div>
</div>
{/* Growth Callout */}
<div className="bg-gradient-to-r from-amber-900/30 to-orange-900/30 rounded-lg p-4 mb-6 border border-amber-700/30">
<div className="flex items-center gap-3">
<div className="text-3xl">๐Ÿš€</div>
<div>
<div className="text-amber-200 font-semibold">Acceleration: {growthStats.multiplier}x growth in 2 months</div>
<div className="text-amber-200/60 text-sm">
Nov 2025: {formatNumber(growthStats.novTotal)} changes โ†’ Jan 2026: {formatNumber(growthStats.janTotal)} changes
</div>
</div>
</div>
</div>
{/* Filter Buttons */}
<div className="flex flex-wrap gap-3 mb-6">
<button
onClick={() => setShowContributorPanel(!showContributorPanel)}
className={`px-4 py-2 rounded-lg font-medium transition-all ${
showContributorPanel
? 'bg-blue-600 text-white'
: 'bg-gray-800 text-gray-300 hover:bg-gray-700'
}`}
>
Contributors ({enabledContributors.size})
</button>
<button
onClick={() => setShowRepoPanel(!showRepoPanel)}
className={`px-4 py-2 rounded-lg font-medium transition-all ${
showRepoPanel
? 'bg-purple-600 text-white'
: 'bg-gray-800 text-gray-300 hover:bg-gray-700'
}`}
>
Repositories ({enabledRepos.size})
</button>
<button
onClick={() => setShowTrendLine(!showTrendLine)}
className={`px-4 py-2 rounded-lg font-medium transition-all ${
showTrendLine
? 'bg-amber-600 text-white'
: 'bg-gray-800 text-gray-300 hover:bg-gray-700'
}`}
>
{showTrendLine ? '๐Ÿ“ˆ Trend On' : '๐Ÿ“ˆ Trend Off'}
</button>
</div>
{/* Contributor Filter Panel */}
{showContributorPanel && (
<div className="bg-gray-900 rounded-lg p-4 mb-6 border border-gray-800">
<div className="flex justify-between items-center mb-3">
<span className="text-gray-300 font-medium">Filter by Contributor</span>
<div className="flex gap-2">
<button onClick={selectAllContributors} className="text-xs px-2 py-1 bg-gray-700 hover:bg-gray-600 rounded">Select All</button>
<button onClick={clearAllContributors} className="text-xs px-2 py-1 bg-gray-700 hover:bg-gray-600 rounded">Clear All</button>
</div>
</div>
<div className="flex flex-wrap gap-2">
{allContributors.map(contributor => (
<button
key={contributor}
onClick={() => toggleContributor(contributor)}
className={`px-3 py-1.5 rounded-full text-sm font-medium transition-all ${
enabledContributors.has(contributor)
? 'bg-blue-600 text-white'
: 'bg-gray-700 text-gray-400 hover:bg-gray-600'
}`}
>
{contributor}
</button>
))}
</div>
</div>
)}
{/* Repository Filter Panel */}
{showRepoPanel && (
<div className="bg-gray-900 rounded-lg p-4 mb-6 border border-gray-800">
<div className="flex justify-between items-center mb-3">
<span className="text-gray-300 font-medium">Filter by Repository</span>
<div className="flex gap-2">
<button onClick={selectAllRepos} className="text-xs px-2 py-1 bg-gray-700 hover:bg-gray-600 rounded">Select All</button>
<button onClick={clearAllRepos} className="text-xs px-2 py-1 bg-gray-700 hover:bg-gray-600 rounded">Clear All</button>
</div>
</div>
<div className="flex flex-wrap gap-2">
{allRepos.map(repo => (
<button
key={repo}
onClick={() => toggleRepo(repo)}
className={`px-3 py-1.5 rounded-full text-sm font-medium transition-all ${
enabledRepos.has(repo)
? 'bg-purple-600 text-white'
: 'bg-gray-700 text-gray-400 hover:bg-gray-600'
}`}
>
{repo}
</button>
))}
</div>
</div>
)}
{/* Chart */}
<div className="bg-gray-900 rounded-lg p-6 border border-gray-800">
<div className="flex items-center gap-2 mb-4">
<h2 className="text-gray-300 font-medium">Weekly Code Changes</h2>
{showTrendLine && (
<span className="text-xs px-2 py-1 bg-amber-900/50 text-amber-300 rounded-full">
4-week rolling average
</span>
)}
</div>
<ResponsiveContainer width="100%" height={450}>
<ComposedChart data={chartData} margin={{ top: 20, right: 30, left: 20, bottom: 60 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#374151" />
<XAxis
dataKey="weekLabel"
stroke="#9CA3AF"
tick={{ fill: '#9CA3AF', fontSize: 11 }}
angle={-45}
textAnchor="end"
height={60}
/>
<YAxis
yAxisId="left"
stroke="#9CA3AF"
tick={{ fill: '#9CA3AF', fontSize: 11 }}
tickFormatter={formatNumber}
/>
<YAxis
yAxisId="right"
orientation="right"
stroke="#F59E0B"
tick={{ fill: '#F59E0B', fontSize: 11 }}
tickFormatter={formatNumber}
domain={[0, 'auto']}
/>
<Tooltip
contentStyle={{
backgroundColor: '#1F2937',
border: '1px solid #374151',
borderRadius: '8px',
color: '#F3F4F6'
}}
formatter={(value, name) => {
const absValue = Math.abs(value);
if (name === 'negDeletions') return [formatNumber(absValue), 'Deletions'];
if (name === 'trendLine') return [formatNumber(absValue), 'Trend (4-wk avg)'];
return [formatNumber(absValue), 'Additions'];
}}
labelFormatter={(label) => `Week of ${label}`}
/>
<Legend
formatter={(value) => {
if (value === 'negDeletions') return 'Deletions';
if (value === 'trendLine') return 'Trend (4-wk rolling avg)';
return 'Additions';
}}
wrapperStyle={{ paddingTop: '20px' }}
/>
<Bar
yAxisId="left"
dataKey="additions"
fill="#22C55E"
name="Additions"
radius={[4, 4, 0, 0]}
/>
<Bar
yAxisId="left"
dataKey="negDeletions"
fill="#EF4444"
name="negDeletions"
radius={[0, 0, 4, 4]}
/>
{showTrendLine && (
<Line
yAxisId="right"
type="monotone"
dataKey="trendLine"
stroke="#F59E0B"
strokeWidth={3}
dot={false}
name="trendLine"
/>
)}
</ComposedChart>
</ResponsiveContainer>
</div>
{/* Monthly Breakdown */}
<div className="mt-6 bg-gray-900 rounded-lg p-4 border border-gray-800">
<h3 className="text-gray-300 font-medium mb-3">Monthly Breakdown</h3>
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-7 gap-3">
{Object.entries(monthlyStats).sort().map(([month, stats]) => {
const monthName = new Date(month + '-01').toLocaleDateString('en-US', { month: 'short', year: '2-digit' });
const isHighlight = month === '2026-01' || month === '2025-11';
return (
<div
key={month}
className={`rounded-lg p-3 ${
isHighlight
? 'bg-gradient-to-b from-amber-900/40 to-gray-800 border border-amber-700/30'
: 'bg-gray-800'
}`}
>
<div className="text-gray-400 text-xs mb-1">{monthName}</div>
<div className="text-white font-bold">{formatNumber(stats.total)}</div>
<div className="text-xs">
<span className="text-green-400">+{formatNumber(stats.additions)}</span>
{' / '}
<span className="text-red-400">-{formatNumber(stats.deletions)}</span>
</div>
</div>
);
})}
</div>
</div>
<p className="text-gray-500 text-xs mt-4 text-center">
Generated {new Date(data.generatedAt).toLocaleDateString()}
</p>
</div>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment