Skip to content

Commit 04dbc4d

Browse files
committed
Add full OrgExplorer dashboard: Overview, HealthScore, ActivityChart , NetworkGraph , RepoTable , Insights & CSV export
1 parent e31a47a commit 04dbc4d

28 files changed

Lines changed: 3339 additions & 361 deletions

package-lock.json

Lines changed: 2157 additions & 146 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,19 @@
1010
"preview": "vite preview"
1111
},
1212
"dependencies": {
13+
"d3-force": "^3.0.0",
14+
"idb": "^8.0.3",
1315
"react": "^19.2.0",
1416
"react-dom": "^19.2.0",
15-
"recharts": "^3.8.0"
17+
"react-force-graph": "^1.48.2",
18+
"react-force-graph-2d": "^1.29.1",
19+
"react-router-dom": "^7.13.2",
20+
"recharts": "^3.8.1"
1621
},
1722
"devDependencies": {
1823
"@eslint/js": "^9.39.1",
24+
"@tailwindcss/vite": "^4.2.2",
25+
"@types/d3-force": "^3.0.10",
1926
"@types/node": "^24.10.1",
2027
"@types/react": "^19.2.5",
2128
"@types/react-dom": "^19.2.3",
@@ -24,6 +31,7 @@
2431
"eslint-plugin-react-hooks": "^7.0.1",
2532
"eslint-plugin-react-refresh": "^0.4.24",
2633
"globals": "^16.5.0",
34+
"tailwindcss": "^4.2.2",
2735
"typescript": "~5.9.3",
2836
"typescript-eslint": "^8.46.4",
2937
"vite": "npm:rolldown-vite@7.2.5"

src/App.css

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,49 @@
33
margin: 0 auto;
44
padding: 2rem;
55
text-align: center;
6+
}
7+
8+
body {
9+
background: #0f172a;
10+
color: #e2e8f0;
11+
font-family: "Inter", sans-serif;
12+
}
13+
14+
.chart-container {
15+
margin-top: 30px;
16+
padding: 20px;
17+
border-radius: 16px;
18+
background: rgba(255, 255, 255, 0.05);
19+
backdrop-filter: blur(10px);
20+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
21+
}
22+
23+
h1 {
24+
font-size: 32px;
25+
margin-bottom: 20px;
26+
}
27+
28+
h2 {
29+
margin-bottom: 10px;
30+
}
31+
32+
table {
33+
width: 100%;
34+
border-collapse: collapse;
35+
margin-top: 20px;
36+
}
37+
38+
th, td {
39+
padding: 10px;
40+
border-bottom: 1px solid #444;
41+
text-align: left;
42+
}
43+
44+
th {
45+
cursor: pointer;
46+
color: #38bdf8;
47+
}
48+
49+
tr:hover {
50+
background: rgba(255,255,255,0.05);
651
}

src/App.tsx

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
1-
import './App.css';
2-
import Dashboard from "./components/Dashboard";
1+
import { useState } from "react";
2+
import { Routes, Route } from "react-router-dom";
33

4+
import DashboardLayout from "./layout/DashboardLayout";
5+
import Overview from "./pages/Overview";
6+
import Repositories from "./pages/Repositories";
7+
import GraphPage from "./pages/GraphPage";
48

5-
function App() {
9+
export default function App() {
10+
const [orgInput, setOrgInput] = useState("");
611

712
return (
8-
<>
9-
<Dashboard />
10-
</>
11-
)
12-
}
13+
<DashboardLayout orgInput={orgInput}>
14+
<Routes>
15+
<Route
16+
path="/"
17+
element={
18+
<Overview
19+
orgInput={orgInput}
20+
setOrgInput={setOrgInput}
21+
/>
22+
}
23+
/>
1324

14-
export default App
25+
<Route path="/repositories" element={<Repositories />} />
26+
<Route path="/graph" element={<GraphPage />} />
27+
</Routes>
28+
</DashboardLayout>
29+
);
30+
}

src/components/Cards/statCard.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
interface Props {
2+
title: string;
3+
value: string | number;
4+
}
5+
6+
export default function StatCard({ title, value }: Props) {
7+
return (
8+
<div className="bg-[#1F2937] p-4 rounded-xl h-32">
9+
<p className="text-gray-400 text-sm">{title}</p>
10+
<h2 className="text-2xl font-bold text-green-400">{value}</h2>
11+
</div>
12+
);
13+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { useState, useMemo } from "react";
2+
import {
3+
LineChart, Line,
4+
BarChart, Bar,
5+
PieChart, Pie, Cell, LabelList,
6+
XAxis, YAxis, Tooltip, Legend
7+
} from "recharts";
8+
9+
const tooltipFormatter = (
10+
value?: number | string,
11+
name?: string
12+
): [string, string] => {
13+
return [
14+
value !== undefined ? value.toString() : "-",
15+
name !== undefined ? name : "-"
16+
];
17+
};
18+
19+
export default function ActivityChart({ repos }: any) {
20+
const [chartType, setChartType] = useState("line");
21+
const [filter, setFilter] = useState("top");
22+
23+
const COLORS = ["#22c55e", "#3b82f6", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
24+
25+
const data = useMemo(() => {
26+
let processed = [...repos];
27+
28+
if (filter === "top") {
29+
processed.sort((a, b) => b.stargazers_count - a.stargazers_count);
30+
}
31+
if (filter === "inactive") {
32+
const now = new Date().getTime();
33+
processed = processed.filter(r =>
34+
now - new Date(r.updated_at).getTime() > 90 * 24 * 60 * 60 * 1000
35+
);
36+
}
37+
38+
return processed.slice(0, 8).map((r: any) => ({
39+
name: r.name,
40+
stars: r.stargazers_count,
41+
forks: r.forks_count
42+
}));
43+
}, [repos, filter]);
44+
45+
return (
46+
<div className="bg-[#1F2937] p-4 rounded mt-6 text-white" >
47+
48+
<div className="flex gap-3 mb-4">
49+
{["line", "bar", "pie"].map(type => (
50+
<button
51+
key={type}
52+
onClick={() => setChartType(type)}
53+
className={`px-3 py-1 rounded ${chartType === type ? "bg-green-500" : "bg-gray-700"}`}
54+
>
55+
{type.charAt(0).toUpperCase() + type.slice(1)}
56+
</button>
57+
))}
58+
</div>
59+
60+
<div className="flex gap-3 mb-4">
61+
<button
62+
onClick={() => setFilter("top")}
63+
className={`px-3 py-1 rounded ${filter === "top" ? "bg-blue-500" : "bg-gray-700"}`}
64+
>
65+
Top Repos
66+
</button>
67+
<button
68+
onClick={() => setFilter("inactive")}
69+
className={`px-3 py-1 rounded ${filter === "inactive" ? "bg-blue-500" : "bg-gray-700"}`}
70+
>
71+
Inactive
72+
</button>
73+
</div>
74+
75+
{chartType === "line" && (
76+
<LineChart width={600} height={300} data={data}>
77+
<XAxis dataKey="name" />
78+
<YAxis />
79+
<Tooltip />
80+
<Legend />
81+
<Line type="monotone" dataKey="stars" stroke="#22c55e" />
82+
<Line type="monotone" dataKey="forks" stroke="#3b82f6" />
83+
</LineChart>
84+
)}
85+
86+
{chartType === "bar" && (
87+
<BarChart width={600} height={300} data={data}>
88+
<XAxis dataKey="name" />
89+
<YAxis />
90+
<Tooltip />
91+
<Legend />
92+
<Bar dataKey="stars" fill="#22c55e">
93+
<LabelList dataKey="stars" position="top" />
94+
</Bar>
95+
<Bar dataKey="forks" fill="#3b82f6">
96+
<LabelList dataKey="forks" position="top" />
97+
</Bar>
98+
</BarChart>
99+
)}
100+
101+
{chartType === "pie" && (
102+
<PieChart width={400} height={400}>
103+
<Pie
104+
data={data}
105+
dataKey="stars"
106+
nameKey="name"
107+
outerRadius={100}
108+
label={({ name, value }) => `${name}: ${value}`}
109+
>
110+
{data.map((_, index) => (
111+
<Cell key={index} fill={COLORS[index % COLORS.length]} />
112+
))}
113+
</Pie>
114+
<Tooltip formatter={tooltipFormatter} />
115+
<Legend />
116+
</PieChart>
117+
)}
118+
119+
</div>
120+
);
121+
}

0 commit comments

Comments
 (0)