harshapitla/github-actions-analytics
0
1import React, { useMemo } from "react";2import {3 BarChart,4 Bar,5 XAxis,6 YAxis,7 CartesianGrid,8 Tooltip,9 ResponsiveContainer,10} from "recharts";11import ChartCard from "../components/charts/ChartCard";12 13/* -------------------- Tooltip -------------------- */14function CustomTooltip({ active, payload, label }) {15 if (active && payload && payload.length) {16 return (17 <div18 style={{19 background: "rgba(5, 18, 35, 0.95)",20 padding: "8px 12px",21 borderRadius: 6,22 border: "1px solid #334155",23 }}24 >25 <div style={{ fontWeight: "bold", marginBottom: 4 }}>{label}</div>26 <div style={{ fontSize: 12 }}>27 {payload[0].name}: {payload[0].value.toLocaleString()}28 </div>29 </div>30 );31 }32 return null;33}34 35/* -------------------- Metric Chart -------------------- */36function MetricBarChart({ title, dataKey, data }) {37 return (38 <div style={{ height: 220, marginBottom: 24 }}>39 <h4 style={{ color: "#e5e7eb", marginBottom: 8 }}>{title}</h4>40 <ResponsiveContainer>41 <BarChart42 data={data}43 layout="vertical"44 margin={{ top: 5, right: 30, left: 120, bottom: 5 }}45 >46 <CartesianGrid strokeDasharray="3 3" stroke="#334155" />47 <XAxis type="number" tick={{ fill: "#94a3b8", fontSize: 12 }} />48 <YAxis49 type="category"50 dataKey="name"51 tick={{ fill: "#94a3b8", fontSize: 12 }}52 width={120}53 />54 <Tooltip content={<CustomTooltip />} />55 <Bar dataKey={dataKey} fill="#60a5fa" radius={[0, 6, 6, 0]} />56 </BarChart>57 </ResponsiveContainer>58 </div>59 );60}61 62/* -------------------- Main Chart -------------------- */63export default function Top3ActionsComparisonChart({ rows = [] }) {64 const topActions = useMemo(() => {65 if (!Array.isArray(rows)) return [];66 67 return rows68 .filter((row) => row.no_of_stars && !isNaN(row.no_of_stars))69 .sort((a, b) => Number(b.no_of_stars) - Number(a.no_of_stars))70 .slice(0, 3)71 .map((row) => ({72 name: row.action_title || "Unknown",73 stars: Number(row.no_of_stars) || 0,74 contributors: Number(row.no_of_contributors) || 0,75 prs: Number(row.no_of_PRs) || 0,76 issues: Number(row.no_of_open_issues) || 0,77 }));78 }, [rows]);79 80 if (!topActions.length) {81 return (82 <ChartCard83 title="Top 3 Actions Comparison"84 subtitle="Side-by-side comparison across key metrics"85 >86 <p className="small">No sufficient data available.</p>87 </ChartCard>88 );89 }90 91 return (92 <ChartCard93 title="Top 3 Actions โ Metric Comparison"94 subtitle="Clear comparison across adoption and maintenance dimensions"95 >96 <MetricBarChart97 title="โญ Stars (Adoption)"98 dataKey="stars"99 data={topActions}100 />101 102 <MetricBarChart103 title="๐ฅ Contributors (Bus Factor)"104 dataKey="contributors"105 data={topActions}106 />107 108 <MetricBarChart109 title="๐ Pull Requests (Activity)"110 dataKey="prs"111 data={topActions}112 />113 114 <MetricBarChart115 title="๐ Open Issues (Maintenance Load)"116 dataKey="issues"117 data={topActions}118 />119 120 <div121 style={{122 marginTop: 12,123 fontSize: 12,124 color: "#94a3b8",125 textAlign: "center",126 borderTop: "1px solid #334155",127 paddingTop: 10,128 }}129 >130 <p>131 This view avoids normalization and visual distortion, allowing direct132 comparison of adoption, contributor depth, activity, and maintenance133 load.134 </p>135 </div>136 </ChartCard>137 );138}139 