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";12import InsightsBox from "../components/insights/InsightsBox";13 14/* -------------------- Helper -------------------- */15function median(values) {16 if (!values.length) return 0;17 const sorted = [...values].sort((a, b) => a - b);18 const mid = Math.floor(sorted.length / 2);19 return sorted.length % 2 !== 020 ? sorted[mid]21 : (sorted[mid - 1] + sorted[mid]) / 2;22}23 24/* -------------------- Tooltip -------------------- */25function CustomTooltip({ active, payload, label }) {26 if (active && payload && payload.length) {27 return (28 <div29 style={{30 background: "#ffffff",31 padding: "8px 12px",32 borderRadius: 6,33 border: "1px solid #334155",34 fontSize: 12,35 }}36 >37 <strong>{label}</strong>38 <div style={{ marginTop: 6 }}>39 Issues per 1,000 stars: <strong>{payload[0].value.toFixed(1)}</strong>40 </div>41 </div>42 );43 }44 return null;45}46 47/* -------------------- Chart -------------------- */48export default function VerificationImpactChart({ rows = [] }) {49 const chartData = useMemo(() => {50 if (!Array.isArray(rows)) return [];51 52 const verified = [];53 const unverified = [];54 55 rows.forEach((row) => {56 const stars = Number(row.no_of_stars) || 0;57 const issues = Number(row.no_of_open_issues);58 59 if (stars <= 0 || issues < 0) return;60 61 // ⭐ Maintenance load formula62 const issuesPer1k = (issues / stars) * 1000;63 64 const isVerified =65 row.is_action_verified === true || row.is_action_verified === "TRUE";66 67 if (isVerified) {68 verified.push(issuesPer1k);69 } else {70 unverified.push(issuesPer1k);71 }72 });73 74 return [75 {76 status: "Verified actions",77 medianIssues: median(verified),78 count: verified.length,79 },80 {81 status: "Unverified community actions",82 medianIssues: median(unverified),83 count: unverified.length,84 },85 ];86 }, [rows]);87 88 if (!chartData.length) {89 return (90 <ChartCard91 title="Do Verified Actions Handle Issues Better?"92 subtitle="Not enough data available"93 >94 <p className="small">No valid star or issue data found.</p>95 </ChartCard>96 );97 }98 99 return (100 <ChartCard101 title="Do Verified Actions Handle Issues Better?"102 subtitle="Comparison using issues per 1,000 stars"103 >104 <div style={{ height: 340 }}>105 <ResponsiveContainer>106 <BarChart107 data={chartData}108 margin={{ top: 20, right: 30, left: 70, bottom: 40 }}109 >110 <CartesianGrid strokeDasharray="3 3" stroke="#334155" />111 112 <XAxis dataKey="status" tick={{ fill: "#94a3b8", fontSize: 12 }} />113 114 <YAxis115 tick={{ fill: "#94a3b8", fontSize: 12 }}116 label={{117 value: "Issues per 1,000 stars",118 angle: -90,119 position: "insideLeft",120 fill: "#94a3b8",121 }}122 />123 124 <Tooltip content={<CustomTooltip />} />125 126 <Bar dataKey="medianIssues" fill="#60a5fa" radius={[6, 6, 0, 0]} />127 </BarChart>128 </ResponsiveContainer>129 </div>130 131 {/* Explanation */}132 <p className="small center">133 <strong>Formula used:</strong> Open issues ÷ stars × 1,000134 </p>135 136 <InsightsBox137 points={[138 "Verified actions have more issues per 1,000 stars than unverified ones.",139 "This suggests verified actions attract more feature requests and reports.",140 "Verification does not automatically mean lower maintenance work.",141 "Popularity increases issue volume, even for trusted actions.",142 ]}143 />144 </ChartCard>145 );146}147 